mirror of
https://github.com/CatalaLang/catala.git
synced 2024-11-08 07:51:43 +03:00
Merge branch 'master' into dates_calc_lib
This commit is contained in:
commit
ffd2e1dec3
@ -1,6 +1,10 @@
|
||||
# Reformatting commits to be skipped when running 'git blame'
|
||||
# Use `git config --global blame.ignoreRevsFile .git-blame-ignore-revs` to use it
|
||||
# Add new reformatting commits at the top
|
||||
99b6fc33b508c879f669172005b6c359d7d4f596
|
||||
|
||||
7485c7f2ce726f59f1ec66ddfe1d3f7d640201d8
|
||||
|
||||
f9fc1a8e8b0b2dcbf5361f95ca778df63ac4e247
|
||||
|
||||
f17875f90e07688f683e5ea6e880c57ded640a81
|
||||
|
7
.gitattributes
vendored
7
.gitattributes
vendored
@ -2,7 +2,14 @@
|
||||
*.mld linguist-documentation
|
||||
*.md linguist-documentation
|
||||
*.hints linguist-generated
|
||||
|
||||
french_law/js/french_law.js binary linguist-generated
|
||||
|
||||
french_law/ocaml/law_source/allocations_familiales.ml binary linguist-generated
|
||||
french_law/ocaml/law_source/allocations_familiales_api_web.ml binary linguist-generated
|
||||
french_law/ocaml/law_source/unit_tests/tests_allocations_famiales.ml binary linguist-generated
|
||||
french_law/python/src/allocations_familiales.py binary linguist-generated
|
||||
|
||||
french_law/ocaml/law_source/aides_logement.ml binary linguist-generated
|
||||
french_law/ocaml/law_source/aides_logement_api_web.ml binary linguist-generated
|
||||
french_law/python/src/aides_logement.py binary linguist-generated
|
||||
|
28
.github/workflows/run-builds.yml
vendored
28
.github/workflows/run-builds.yml
vendored
@ -6,34 +6,6 @@ on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build-ubuntu:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Set up OCaml
|
||||
uses: avsm/setup-ocaml@v2
|
||||
with:
|
||||
ocaml-compiler: 4.11.x
|
||||
dune-cache: true
|
||||
|
||||
- name: Install external dependencies
|
||||
run: |
|
||||
sudo apt-get update && sudo apt-get install python3-dev virtualenv \
|
||||
python3-setuptools python3-pip python3-pygments man2html rsync \
|
||||
colordiff npm nodejs libmpc-dev ninja-build pandoc
|
||||
sudo python3 -m pip install --upgrade pip
|
||||
sudo python3 -m pip install virtualenv
|
||||
sudo make pygments
|
||||
./french_law/python/setup_env.sh
|
||||
- name: Install OCaml dependencies
|
||||
run: |
|
||||
make dependencies-ocaml-with-z3
|
||||
- name: Make build
|
||||
run: |
|
||||
OCAMLRUNPARAM=b opam exec -- make build
|
||||
|
||||
build-nix-flake:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
48
.github/workflows/run-make-all.yml
vendored
48
.github/workflows/run-make-all.yml
vendored
@ -11,26 +11,38 @@ jobs:
|
||||
# The type of runner that the job will run on
|
||||
runs-on: self-hosted
|
||||
|
||||
env:
|
||||
IMAGE_TAG: ${{ github.head_ref || github.ref_name }}
|
||||
|
||||
# Steps represent a sequence of tasks that will be executed as part of the job
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Re-initialize python dependencies
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Prepare container with all dependencies
|
||||
run: git archive HEAD | docker build - --target dev-build-context
|
||||
- name: Run builds, checks and tests
|
||||
run: git archive HEAD | docker build - --force-rm -t catalalang/catala-build:${IMAGE_TAG}
|
||||
- name: Cleanup Docker image
|
||||
if: ${{ github.ref != 'refs/heads/master' }}
|
||||
run: docker image rm catalalang/catala-build:${IMAGE_TAG}
|
||||
- name: Build architecture-independent artifacts
|
||||
if: ${{ github.ref == 'refs/heads/master' }}
|
||||
run: |
|
||||
./french_law/python/setup_env.sh
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
opam exec -- make dependencies pygments
|
||||
- name: Check promoted files
|
||||
run: |
|
||||
opam exec -- make check-promoted > promotion.out 2>&1 || touch bad-promote
|
||||
- name: Make all
|
||||
run: |
|
||||
OCAMLRUNPARAM=b opam exec -- make all
|
||||
- name: Forward result from promotion check
|
||||
run: |
|
||||
if [ -e bad-promote ]; then
|
||||
echo "[ERROR] Some promoted files were not up-to-date";
|
||||
cat promotion.out;
|
||||
exit 1
|
||||
fi
|
||||
RELEASE_TAG=$(git describe --tags)
|
||||
mkdir -p artifacts
|
||||
docker run --rm catalalang/catala-build:${IMAGE_TAG} sh -uexc '
|
||||
opam --cli=2.1 exec -- dune build --profile=release french_law compiler/catala.bc.js >&2
|
||||
mv _build/default/compiler/catala.bc.js catala_'"${RELEASE_TAG}"'_node.js >&2
|
||||
tar c -h catala_'"${RELEASE_TAG}"'_node.js french_law --exclude french_law/js/node_modules --exclude french_law/python/env --exclude '"'"'.*'"'"'
|
||||
' | tar vx -C artifacts
|
||||
- name: Build static binaries
|
||||
if: ${{ github.ref == 'refs/heads/master' }}
|
||||
run: ./build_release.sh -C artifacts
|
||||
- name: Publish artifacts
|
||||
if: ${{ github.ref == 'refs/heads/master' }}
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Catala artifacts
|
||||
path: artifacts/*
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -10,5 +10,6 @@ legifrance_oauth*
|
||||
*.html
|
||||
.vscode/
|
||||
.ninja_*
|
||||
node_modules/
|
||||
|
||||
build.ninja
|
||||
|
@ -1,29 +1,29 @@
|
||||
{ lib
|
||||
, pkgs
|
||||
, fetchFromGitHub
|
||||
, buildDunePackage
|
||||
, alcotest
|
||||
, ansiterminal
|
||||
, sedlex
|
||||
, menhir
|
||||
, unionfind
|
||||
, bindlib
|
||||
, cmdliner_1_1_0
|
||||
, re
|
||||
, zarith
|
||||
, zarith_stubs_js
|
||||
, ocamlgraph
|
||||
, calendar
|
||||
, visitors
|
||||
, benchmark
|
||||
, bindlib
|
||||
, buildDunePackage
|
||||
, calendar
|
||||
, cmdliner_1_1_0
|
||||
, cppo
|
||||
, fetchFromGitHub
|
||||
, js_of_ocaml
|
||||
, js_of_ocaml-ppx
|
||||
, camomile
|
||||
, cppo
|
||||
, ppx_deriving
|
||||
, z3
|
||||
, alcotest
|
||||
, ppx_yojson_conv
|
||||
, menhir
|
||||
, menhirLib ? null #for nixos-unstable compatibility.
|
||||
, ocamlgraph
|
||||
, pkgs
|
||||
, ppx_deriving
|
||||
, ppx_yojson_conv
|
||||
, re
|
||||
, sedlex
|
||||
, ubase
|
||||
, unionfind
|
||||
, visitors
|
||||
, z3
|
||||
, zarith
|
||||
, zarith_stubs_js
|
||||
}:
|
||||
|
||||
buildDunePackage rec {
|
||||
@ -37,34 +37,30 @@ buildDunePackage rec {
|
||||
useDune2 = true;
|
||||
|
||||
propagatedBuildInputs = [
|
||||
alcotest
|
||||
ansiterminal
|
||||
sedlex
|
||||
menhir
|
||||
menhirLib
|
||||
cmdliner_1_1_0
|
||||
re
|
||||
zarith
|
||||
zarith_stubs_js
|
||||
ocamlgraph
|
||||
calendar
|
||||
visitors
|
||||
benchmark
|
||||
bindlib
|
||||
calendar
|
||||
camomile
|
||||
cmdliner_1_1_0
|
||||
cppo
|
||||
js_of_ocaml
|
||||
js_of_ocaml-ppx
|
||||
ppx_yojson_conv
|
||||
camomile
|
||||
cppo
|
||||
z3
|
||||
|
||||
|
||||
menhir
|
||||
menhirLib
|
||||
ocamlgraph
|
||||
pkgs.z3
|
||||
|
||||
ppx_deriving
|
||||
|
||||
alcotest
|
||||
|
||||
ppx_yojson_conv
|
||||
re
|
||||
sedlex
|
||||
ubase
|
||||
unionfind
|
||||
bindlib
|
||||
visitors
|
||||
z3
|
||||
zarith
|
||||
zarith_stubs_js
|
||||
] ++ (if isNull menhirLib then [ ] else [ menhirLib ]);
|
||||
doCheck = true;
|
||||
|
||||
|
@ -9,3 +9,5 @@ cases-exp-indent=2
|
||||
indicate-multiline-delimiters=no
|
||||
parens-tuple=multi-line-only
|
||||
space-around-lists=false
|
||||
break-infix-before-func
|
||||
break-infix= fit-or-vertical
|
||||
|
63
Dockerfile
63
Dockerfile
@ -1,13 +1,54 @@
|
||||
FROM ocaml/opam:ubuntu-lts-ocaml-4.12
|
||||
# Stage 1: setup an opam switch with all dependencies installed
|
||||
# (only depends on the opam files)
|
||||
FROM ocamlpro/ocaml:4.14-2022-07-17 AS dev-build-context
|
||||
|
||||
RUN sudo apt-get update && sudo apt-get install -y \
|
||||
man2html \
|
||||
colordiff \
|
||||
latexmk \
|
||||
python3 \
|
||||
python3-pip \
|
||||
libgmp-dev \
|
||||
npm \
|
||||
nodejs
|
||||
# pandoc is not in alpine stable yet, install it manually with an explicit repository
|
||||
RUN sudo apk add pandoc --repository=http://dl-cdn.alpinelinux.org/alpine/edge/testing/
|
||||
|
||||
RUN sudo pip3 install virtualenv
|
||||
RUN mkdir catala
|
||||
WORKDIR catala
|
||||
|
||||
# Get only the opam files at this stage to allow caching
|
||||
ADD --chown=ocaml:ocaml *.opam ./
|
||||
|
||||
# trigger the selection of catala dev tools in opam
|
||||
ENV OPAMVAR_cataladevmode=1
|
||||
ENV OPAMVAR_catalaz3mode=1
|
||||
|
||||
# Get a switch with all the dependencies installed
|
||||
RUN opam --cli=2.1 switch create catala ocaml-system && \
|
||||
opam --cli=2.1 pin . --no-action && \
|
||||
opam --cli=2.1 install . --with-test --with-doc --depext-only && \
|
||||
opam --cli=2.1 install . --with-test --with-doc --deps-only && \
|
||||
opam clean
|
||||
# Note: just one `opam switch create .` command should be enough once opam 2.1.3 is released (opam#5047 ; opam#5185)
|
||||
|
||||
|
||||
# Stage 2: get the whole repo, run checks and builds
|
||||
FROM dev-build-context
|
||||
|
||||
# Get the full repo
|
||||
ADD --chown=ocaml:ocaml . .
|
||||
|
||||
# Prepare extra local dependencies
|
||||
RUN opam exec -- make pygments dependencies-js
|
||||
RUN opam exec -- ./french_law/python/setup_env.sh
|
||||
|
||||
# OCaml backtraces may be useful on failure
|
||||
ENV OCAMLRUNPARAM=b
|
||||
|
||||
# Check promoted files (but delay failure)
|
||||
RUN opam exec -- make check-promoted > promotion.out 2>&1 || touch bad-promote
|
||||
|
||||
# Check the build
|
||||
RUN opam exec -- make build
|
||||
|
||||
# Check tests & all alt targets
|
||||
RUN OCAMLRUNPARAM=b opam exec -- make all -B
|
||||
|
||||
# Forward results of promotion check
|
||||
RUN if [ -e bad-promote ]; then \
|
||||
echo "[ERROR] Some promoted files were not up-to-date"; \
|
||||
cat promotion.out; \
|
||||
exit 1; \
|
||||
fi
|
||||
|
40
INSTALL.md
40
INSTALL.md
@ -11,11 +11,11 @@ Start by installing Docker: https://docs.docker.com/get-docker/
|
||||
|
||||
Then build the Docker image:
|
||||
|
||||
docker build . -t catala
|
||||
docker build . --target dev-build-context -t catala
|
||||
|
||||
Finally, start a `bash` shell inside a new container created from the newly built image:
|
||||
Finally, start a shell inside a new container created from the newly built image:
|
||||
|
||||
docker run -it -v $PWD:$PWD -w $PWD --name catala catala bash
|
||||
docker run -it --name catala catala
|
||||
|
||||
### With nix
|
||||
|
||||
@ -41,18 +41,20 @@ OCaml's distribution and package manager. Follow the [instructions on the `opam`
|
||||
website](https://opam.ocaml.org/doc/Install.html).
|
||||
|
||||
Next, you will need to use the correct version of OCaml. Catala has been tested
|
||||
with OCaml compiler versions that are at least 4.12.0. To switch to OCaml 4.12.0.,
|
||||
with OCaml compiler versions that are at least 4.13.0. To switch to OCaml 4.13.0.,
|
||||
just use:
|
||||
|
||||
opam switch 4.12.0
|
||||
opam switch 4.13.0
|
||||
|
||||
If you get a `No switch 4.12.0 is currently installed` error message, follow
|
||||
the hint and enter `opam switch create 4.12.0`.
|
||||
If you get a `No switch 4.13.0 is currently installed` error message, follow
|
||||
the hint and enter `opam switch create 4.13.0`.
|
||||
|
||||
## Dependencies
|
||||
|
||||
Next, install all the OCaml packages that Catala depend on, as well as some
|
||||
git submodules, with
|
||||
You can skip this step if you used the *Docker* option above, it is already taken
|
||||
care of.
|
||||
|
||||
Next, install all the packages that Catala depends on with
|
||||
|
||||
make dependencies
|
||||
|
||||
@ -61,23 +63,13 @@ This should ensure everything is set up for developing on the Catala compiler!
|
||||
**Warning**: this command does not include the `z3` dependency required to enable
|
||||
the proof platform feature of Catala. If you wish to enable support for the
|
||||
proof platform and the `Proof` command of the Catala compiler, you should
|
||||
instead execute `make dependencies-with-ocaml` prior to building the compiler.
|
||||
instead execute `make dependencies-with-z3` prior to building the compiler.
|
||||
|
||||
Other features of the Catala repository also require the following executables
|
||||
to be present
|
||||
to be present. On debian, arch or apline-based distributions, the above command
|
||||
should already take care of them.
|
||||
|
||||
man2html virtualenv python3 pip rsync colordiff pygmentize nodejs npm
|
||||
|
||||
please install them if they're not here, otherwise you will get some errors.
|
||||
On a Debian distribution, this can be
|
||||
done with
|
||||
|
||||
sudo apt install python3-dev virtualenv python3-setuptools python3-pip python3-pygments man2html rsync colordiff npm nodejs libmpc-dev ninja-build
|
||||
sudo python3 -m pip install --upgrade pip
|
||||
|
||||
On ArchLinux :
|
||||
|
||||
sudo pacman -S python-virtualenv man2html rsync colordiff nodejs npm
|
||||
groff virtualenv python3 pip rsync colordiff pygmentize nodejs npm
|
||||
|
||||
## Build
|
||||
|
||||
@ -112,7 +104,7 @@ Catala website.
|
||||
|
||||
./generate_website_assets.sh <path-to-catala-website>/assets
|
||||
|
||||
You will need the `man2html` executable to generate the HTML versions of the man
|
||||
You will need the `groff` executable to generate the HTML versions of the man
|
||||
pages, as well as the `rsync` executable to transfer files (preferred to `cp`)
|
||||
because it also works with a remote server.
|
||||
|
||||
|
159
Makefile
159
Makefile
@ -3,6 +3,8 @@ help : Makefile
|
||||
|
||||
ROOT_DIR:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
|
||||
|
||||
export DUNE_PROFILE ?= release
|
||||
|
||||
# Export all variables to sub-make
|
||||
export
|
||||
|
||||
@ -10,28 +12,30 @@ export
|
||||
# Dependencies
|
||||
##########################################
|
||||
|
||||
EXECUTABLES = man2html python3 colordiff node pygmentize node npm ninja pandoc
|
||||
EXECUTABLES = groff python3 colordiff node pygmentize node npm ninja pandoc
|
||||
K := $(foreach exec,$(EXECUTABLES),\
|
||||
$(if $(shell which $(exec)),some string,$(warning [WARNING] No "$(exec)" executable found. \
|
||||
Please install this executable for everything to work smoothly)))
|
||||
|
||||
OPAM = opam --cli=2.1
|
||||
|
||||
dependencies-ocaml:
|
||||
opam install . ./doc/catala-dev-dependencies.opam --deps-only --with-doc --with-test --yes
|
||||
$(OPAM) pin . --no-action
|
||||
OPAMVAR_cataladevmode=1 $(OPAM) install . --with-doc --with-test --update-invariant --depext-only
|
||||
OPAMVAR_cataladevmode=1 $(OPAM) install . --with-doc --with-test --update-invariant --deps-only
|
||||
|
||||
dependencies-ocaml-with-z3:
|
||||
opam install . ./doc/catala-dev-dependencies.opam z3 --deps-only --with-doc --with-test --yes
|
||||
$(OPAM) pin . --no-action
|
||||
OPAMVAR_cataladevmode=1 OPAMVAR_catalaz3mode=1 $(OPAM) install . --with-doc --with-test --update-invariant --depext-only
|
||||
OPAMVAR_cataladevmode=1 OPAMVAR_catalaz3mode=1 $(OPAM) install . --with-doc --with-test --update-invariant --deps-only
|
||||
|
||||
dependencies-js:
|
||||
$(MAKE) -C $(FRENCH_LAW_JS_LIB_DIR) dependencies
|
||||
|
||||
init-submodules:
|
||||
git submodule update --init
|
||||
|
||||
|
||||
#> dependencies : Install the Catala OCaml, JS and Git dependencies
|
||||
dependencies: dependencies-ocaml dependencies-js init-submodules
|
||||
dependencies: dependencies-ocaml dependencies-js
|
||||
|
||||
dependencies-with-z3: dependencies-ocaml-with-z3 dependencies-js init-submodules
|
||||
dependencies-with-z3: dependencies-ocaml-with-z3 dependencies-js
|
||||
|
||||
##########################################
|
||||
# Catala compiler rules
|
||||
@ -42,16 +46,18 @@ BUILD_SYSTEM_DIR=build_system
|
||||
|
||||
#> build_dev : Builds the Catala compiler, without formatting code
|
||||
build_dev: parser-messages
|
||||
dune build $(COMPILER_DIR)/catala.exe $(BUILD_SYSTEM_DIR)/clerk.exe
|
||||
dune build \
|
||||
$(COMPILER_DIR)/catala.exe \
|
||||
$(COMPILER_DIR)/plugins/ \
|
||||
$(BUILD_SYSTEM_DIR)/clerk.exe
|
||||
|
||||
#> build : Builds the Catala compiler
|
||||
build: parser-messages format
|
||||
dune build $(COMPILER_DIR)/catala.exe $(BUILD_SYSTEM_DIR)/clerk.exe
|
||||
build: parser-messages format build_dev
|
||||
|
||||
#> js_build : Builds the Web-compatible JS versions of the Catala compiler
|
||||
js_build:
|
||||
dune build $(COMPILER_DIR)/catala.bc.js --profile release
|
||||
dune build $(COMPILER_DIR)/catala_web_interpreter.bc.js --profile release
|
||||
dune build $(COMPILER_DIR)/catala.bc.js
|
||||
dune build $(COMPILER_DIR)/catala_web_interpreter.bc.js
|
||||
|
||||
#> doc : Generates the HTML OCaml documentation
|
||||
doc:
|
||||
@ -61,8 +67,12 @@ doc:
|
||||
install:
|
||||
dune build @install
|
||||
|
||||
#> plugins : Builds the demonstration plugins
|
||||
plugins:
|
||||
#> runtimes : Builds the OCaml and js_of_ocaml runtimes
|
||||
runtimes:
|
||||
dune build runtimes/
|
||||
|
||||
#> plugins : Builds the compiler backend plugins
|
||||
plugins: runtimes
|
||||
dune build compiler/plugins/
|
||||
@echo "define CATALA_PLUGINS=_build/default/compiler/plugins to test the plugins"
|
||||
|
||||
@ -74,11 +84,11 @@ check-promoted:
|
||||
dune build @update-parser-messages @fmt
|
||||
|
||||
compiler/surface/parser.messages: compiler/surface/tokens.mly compiler/surface/parser.mly
|
||||
dune build @update-parser-messages --auto-promote || true
|
||||
-dune build @update-parser-messages --auto-promote
|
||||
parser-messages: compiler/surface/parser.messages
|
||||
|
||||
format:
|
||||
dune build @fmt --auto-promote 2>/dev/null || true
|
||||
-dune build @fmt --auto-promote 2>/dev/null
|
||||
|
||||
##########################################
|
||||
# Syntax highlighting rules
|
||||
@ -188,32 +198,44 @@ literate_examples: literate_allocations_familiales literate_code_general_impots
|
||||
# OCaml
|
||||
#-----------------------------------------
|
||||
|
||||
FRENCH_LAW_OCAML_LIB_DIR=french_law/ocaml
|
||||
FRENCH_LAW_OCAML_LIB_DIR = french_law/ocaml
|
||||
|
||||
$(FRENCH_LAW_OCAML_LIB_DIR)/law_source/allocations_familiales.ml:
|
||||
CATALA_OPTS="$(CATALA_OPTS) -t" $(MAKE) -C $(ALLOCATIONS_FAMILIALES_DIR) allocations_familiales.ml
|
||||
cp -f $(ALLOCATIONS_FAMILIALES_DIR)/allocations_familiales.ml $@
|
||||
FRENCH_LAW_LIBRARY_OCAML = \
|
||||
$(FRENCH_LAW_OCAML_LIB_DIR)/law_source/allocations_familiales_api_web.ml \
|
||||
$(FRENCH_LAW_OCAML_LIB_DIR)/law_source/unit_tests/tests_allocations_familiales.ml \
|
||||
$(FRENCH_LAW_OCAML_LIB_DIR)/law_source/aides_logement_api_web.ml
|
||||
|
||||
$(FRENCH_LAW_OCAML_LIB_DIR)/law_source/unit_tests/tests_allocations_familiales.ml:
|
||||
CATALA_OPTS="$(CATALA_OPTS) -t" $(MAKE) -C $(ALLOCATIONS_FAMILIALES_DIR) tests/tests_allocations_familiales.ml
|
||||
cp -f $(ALLOCATIONS_FAMILIALES_DIR)/tests/tests_allocations_familiales.ml $@
|
||||
$(addprefix _build/default/,$(FRENCH_LAW_LIBRARY_OCAML)) :
|
||||
dune build $@
|
||||
|
||||
#> generate_french_law_library_ocaml : Generates the French law library OCaml sources from Catala
|
||||
generate_french_law_library_ocaml:\
|
||||
$(FRENCH_LAW_OCAML_LIB_DIR)/law_source/allocations_familiales.ml \
|
||||
$(FRENCH_LAW_OCAML_LIB_DIR)/law_source/unit_tests/tests_allocations_familiales.ml
|
||||
$(MAKE) format
|
||||
generate_french_law_library_ocaml:
|
||||
dune build $(FRENCH_LAW_LIBRARY_OCAML)
|
||||
|
||||
#> build_french_law_library_ocaml : Builds the OCaml French law library
|
||||
build_french_law_library_ocaml: generate_french_law_library_ocaml format
|
||||
build_french_law_library_ocaml:
|
||||
dune build $(FRENCH_LAW_OCAML_LIB_DIR)/api.a
|
||||
|
||||
run_french_law_library_benchmark_ocaml: generate_french_law_library_ocaml
|
||||
run_french_law_library_benchmark_ocaml:
|
||||
dune exec --profile release $(FRENCH_LAW_OCAML_LIB_DIR)/bench.exe
|
||||
|
||||
run_french_law_library_ocaml_tests: build_french_law_library_ocaml
|
||||
run_french_law_library_ocaml_tests:
|
||||
dune exec $(FRENCH_LAW_OCAML_LIB_DIR)/law_source/unit_tests/run_tests.exe
|
||||
|
||||
#-----------------------------------------
|
||||
# JSON schemas
|
||||
#-----------------------------------------
|
||||
|
||||
JSON_SCHEMAS = \
|
||||
$(AIDES_LOGEMENT_DIR)/aides_logement_schema.json \
|
||||
$(ALLOCATIONS_FAMILIALES_DIR)/allocations_familiales_schema.json
|
||||
|
||||
#> generate_french_law_json_schemas : Generates the French law library JSON schemas
|
||||
$(addprefix _build/default/,$(JSON_SCHEMAS)):
|
||||
dune build $@
|
||||
|
||||
generate_french_law_json_schemas:
|
||||
dune build $(JSON_SCHEMAS)
|
||||
|
||||
#-----------------------------------------
|
||||
# JS
|
||||
@ -225,10 +247,11 @@ run_french_law_library_benchmark_js: build_french_law_library_js
|
||||
$(MAKE) -C $(FRENCH_LAW_JS_LIB_DIR) bench
|
||||
|
||||
#> build_french_law_library_js : Builds the JS version of the OCaml French law library
|
||||
build_french_law_library_js: generate_french_law_library_ocaml format
|
||||
dune build --profile release $(FRENCH_LAW_OCAML_LIB_DIR)/api_web.bc.js
|
||||
cp -f $(ROOT_DIR)/_build/default/$(FRENCH_LAW_OCAML_LIB_DIR)/api_web.bc.js $(FRENCH_LAW_JS_LIB_DIR)/french_law.js
|
||||
build_french_law_library_js:
|
||||
dune build $(FRENCH_LAW_JS_LIB_DIR)/french_law.js
|
||||
|
||||
#> build_french_law_library_web_api : Builds the web API of the French law library
|
||||
build_french_law_library_web_api: build_french_law_library_js generate_french_law_json_schemas
|
||||
|
||||
#-----------------------------------------
|
||||
# Python
|
||||
@ -236,23 +259,31 @@ build_french_law_library_js: generate_french_law_library_ocaml format
|
||||
|
||||
FRENCH_LAW_PYTHON_LIB_DIR=french_law/python
|
||||
|
||||
$(FRENCH_LAW_PYTHON_LIB_DIR)/src/allocations_familiales.py:
|
||||
CATALA_OPTS="$(CATALA_OPTS) -O -t" $(MAKE) -C $(ALLOCATIONS_FAMILIALES_DIR) allocations_familiales.py
|
||||
cp -f $(ALLOCATIONS_FAMILIALES_DIR)/allocations_familiales.py $@
|
||||
FRENCH_LAW_LIBRARY_PYTHON = \
|
||||
$(FRENCH_LAW_PYTHON_LIB_DIR)/src/allocations_familiales.py \
|
||||
$(FRENCH_LAW_PYTHON_LIB_DIR)/src/aides_logement.py
|
||||
|
||||
PY_VIRTUALENV = $(FRENCH_LAW_PYTHON_LIB_DIR)/env/bin/activate
|
||||
|
||||
$(PY_VIRTUALENV):
|
||||
@$(if $(wildcard $(PY_VIRTUALENV)),,$(error "Python virtualenv not initialised, you need to run $(FRENCH_LAW_PYTHON_LIB_DIR)/setup_env.sh"))
|
||||
|
||||
$(FRENCH_LAW_LIBRARY_PYTHON):
|
||||
dune build $@
|
||||
|
||||
#> generate_french_law_library_python : Generates the French law library Python sources from Catala
|
||||
generate_french_law_library_python:\
|
||||
$(FRENCH_LAW_PYTHON_LIB_DIR)/src/allocations_familiales.py
|
||||
. $(FRENCH_LAW_PYTHON_LIB_DIR)/env/bin/activate ;\
|
||||
$(MAKE) -C $(FRENCH_LAW_PYTHON_LIB_DIR) format
|
||||
generate_french_law_library_python:
|
||||
dune build $(FRENCH_LAW_LIBRARY_PYTHON)
|
||||
|
||||
#> type_french_law_library_python : Types the French law library Python sources with mypy
|
||||
type_french_law_library_python: generate_french_law_library_python
|
||||
. $(FRENCH_LAW_PYTHON_LIB_DIR)/env/bin/activate ;\
|
||||
type_french_law_library_python: $(PY_VIRTUALENV) \
|
||||
generate_french_law_library_python
|
||||
. $(PY_VIRTUALENV) ;\
|
||||
$(MAKE) -C $(FRENCH_LAW_PYTHON_LIB_DIR) type
|
||||
|
||||
run_french_law_library_benchmark_python: type_french_law_library_python
|
||||
. $(FRENCH_LAW_PYTHON_LIB_DIR)/env/bin/activate ;\
|
||||
run_french_law_library_benchmark_python: $(PY_VIRTUALENV) \
|
||||
type_french_law_library_python
|
||||
. $(PY_VIRTUALENV) ;\
|
||||
$(MAKE) -C $(FRENCH_LAW_PYTHON_LIB_DIR) bench
|
||||
|
||||
##########################################
|
||||
@ -272,10 +303,10 @@ CLERK=$(CLERK_BIN) --exe $(CATALA_BIN) \
|
||||
.FORCE:
|
||||
|
||||
test_suite: .FORCE
|
||||
$(CLERK) test tests
|
||||
OCAMLRUNPARAM= $(CLERK) test tests
|
||||
|
||||
test_examples: .FORCE
|
||||
$(CLERK) test examples
|
||||
OCAMLRUNPARAM= $(CLERK) test examples
|
||||
|
||||
#> tests : Run interpreter tests
|
||||
tests: test_suite test_examples
|
||||
@ -299,15 +330,14 @@ tests/%: .FORCE
|
||||
# Website assets
|
||||
##########################################
|
||||
|
||||
grammar.html: $(COMPILER_DIR)/surface/parser.mly
|
||||
obelisk html -o $@ $<
|
||||
WEBSITE_ASSETS = grammar.html catala.html
|
||||
|
||||
catala.html: $(COMPILER_DIR)/utils/cli.ml
|
||||
dune exec $(COMPILER_DIR)/catala.exe -- --help=groff | man2html | sed -e '1,8d' \
|
||||
| tac | sed "1,20d" | tac > $@
|
||||
$(addprefix _build/default/,$(WEBSITE_ASSETS)):
|
||||
dune build $@
|
||||
|
||||
#> website-assets : Builds all the assets necessary for the Catala website
|
||||
website-assets: doc js_build literate_examples grammar.html catala.html build_french_law_library_js
|
||||
website-assets: js_build literate_examples build_french_law_library_web_api doc
|
||||
dune build $(WEBSITE_ASSETS)
|
||||
|
||||
##########################################
|
||||
# Misceallenous
|
||||
@ -315,20 +345,23 @@ website-assets: doc js_build literate_examples grammar.html catala.html build_fr
|
||||
|
||||
#> all : Run all make commands
|
||||
all: \
|
||||
build js_build doc website-assets\
|
||||
build js_build doc \
|
||||
tests \
|
||||
runtimes \
|
||||
plugins \
|
||||
generate_french_law_library_ocaml build_french_law_library_ocaml \
|
||||
tests_ocaml bench_ocaml \
|
||||
build_french_law_library_js \
|
||||
bench_js \
|
||||
generate_french_law_library_python type_french_law_library_python\
|
||||
bench_python
|
||||
generate_french_law_library_python type_french_law_library_python \
|
||||
bench_python \
|
||||
website-assets
|
||||
|
||||
|
||||
#> clean : Clean build artifacts
|
||||
clean:
|
||||
dune clean
|
||||
rm -rf artifacts
|
||||
$(MAKE) -C $(ALLOCATIONS_FAMILIALES_DIR) clean
|
||||
$(MAKE) -C $(US_TAX_CODE_DIR) clean
|
||||
$(MAKE) -C $(TUTORIEL_FR_DIR) clean
|
||||
@ -350,6 +383,12 @@ help_catala:
|
||||
##########################################
|
||||
# Special targets
|
||||
##########################################
|
||||
.PHONY: inspect clean all literate_examples english allocations_familiales pygments \
|
||||
install build_dev build doc format dependencies dependencies-ocaml \
|
||||
catala.html help parser-messages plugins
|
||||
.PHONY: inspect clean all literate_examples english allocations_familiales \
|
||||
pygments install build_dev build doc format dependencies \
|
||||
dependencies-ocaml catala.html help parser-messages plugins \
|
||||
generate_french_law_json_schemas generate_french_law_library_python \
|
||||
generate_french_law_library_ocaml \
|
||||
run_french_law_library_benchmark_python \
|
||||
run_french_law_library_benchmark_js run_french_law_library_ocaml_tests \
|
||||
build_french_law_library_js build_french_law_library_web_api \
|
||||
build_french_law_library_ocaml
|
||||
|
46
build_release.sh
Executable file
46
build_release.sh
Executable file
@ -0,0 +1,46 @@
|
||||
#! /usr/bin/env sh
|
||||
|
||||
set -ue
|
||||
|
||||
RELEASE_TAG=${RELEASE_TAG:-$(git describe --tags 2>/dev/null || echo dev)}
|
||||
|
||||
BIN_TAG=${BIN_TAG:-$(uname -s)_$(uname -m)}
|
||||
|
||||
CUSTOM_LINKING_CATALA_Z3="\
|
||||
(-cclib -static
|
||||
-cclib -no-pie
|
||||
-noautolink
|
||||
-cclib -L/home/ocaml/.opam/z3/lib/stublibs
|
||||
-cclib -lz3ml-static
|
||||
-cclib -lz3
|
||||
-cclib -lstdc++
|
||||
-cclib -lthreadsnat
|
||||
-cclib -lzarith
|
||||
-cclib -lgmp
|
||||
-cclib -lcamlstr
|
||||
-cclib -lANSITerminal_stubs
|
||||
-cclib -lunix)"
|
||||
|
||||
CUSTOM_LINKING_CATALA_NOZ3="(-cclib -static -cclib -no-pie)"
|
||||
|
||||
CUSTOM_LINKING_CLERK="(-cclib -static -cclib -no-pie)"
|
||||
|
||||
git archive HEAD --prefix catala/ | \
|
||||
docker run --rm -i registry.gitlab.inria.fr/lgesbert/catala-ci-images:ocaml.4.14-z3static.4.10.1 \
|
||||
sh -uexc \
|
||||
'{ tar x &&
|
||||
cd catala &&
|
||||
echo "'"${CUSTOM_LINKING_CATALA_Z3}"'" >compiler/custom_linking.sexp &&
|
||||
echo "'"${CUSTOM_LINKING_CLERK}"'" >build_system/custom_linking.sexp &&
|
||||
opam --cli=2.1 install ./ninja_utils.opam ./clerk.opam ./catala.opam --destdir ../release.out/ &&
|
||||
mv ../release.out/bin/catala ../release.out/bin/catala-z3 &&
|
||||
opam --cli=2.1 remove z3 catala &&
|
||||
echo "'"${CUSTOM_LINKING_CATALA_NOZ3}"'" >compiler/custom_linking.sexp &&
|
||||
opam --cli=2.1 install ./catala.opam --destdir ../release.out/ &&
|
||||
rm -f ../release.out/bin/catala_web_interpreter &&
|
||||
for f in ../release.out/bin/*; do
|
||||
strip ${f};
|
||||
mv ${f} ${f}_'"${RELEASE_TAG}"'_'"${BIN_TAG}"';
|
||||
done;
|
||||
} >&2 && tar c -hC ../release.out/bin .' |
|
||||
tar vx "$@"
|
@ -24,7 +24,8 @@ module Nj = Ninja_utils
|
||||
|
||||
let files_or_folders =
|
||||
Arg.(
|
||||
non_empty & pos_right 0 file []
|
||||
non_empty
|
||||
& pos_right 0 file []
|
||||
& info [] ~docv:"FILE(S)" ~doc:"File(s) or folder(s) to process")
|
||||
|
||||
let command =
|
||||
@ -38,7 +39,8 @@ let debug =
|
||||
|
||||
let reset_test_outputs =
|
||||
Arg.(
|
||||
value & flag
|
||||
value
|
||||
& flag
|
||||
& info ["r"; "reset"]
|
||||
~doc:
|
||||
"Used with the `test` command, resets the test output to whatever is \
|
||||
@ -88,8 +90,16 @@ let catala_opts =
|
||||
|
||||
let clerk_t f =
|
||||
Term.(
|
||||
const f $ files_or_folders $ command $ catalac $ catala_opts $ makeflags
|
||||
$ debug $ scope $ reset_test_outputs $ ninja_output)
|
||||
const f
|
||||
$ files_or_folders
|
||||
$ command
|
||||
$ catalac
|
||||
$ catala_opts
|
||||
$ makeflags
|
||||
$ debug
|
||||
$ scope
|
||||
$ reset_test_outputs
|
||||
$ ninja_output)
|
||||
|
||||
let version = "0.5.0"
|
||||
|
||||
@ -336,7 +346,8 @@ let collect_all_ninja_build
|
||||
let expected_output_file =
|
||||
expected_output.output_dir
|
||||
^ Filename.basename expected_output.tested_filename
|
||||
^ "." ^ expected_output.id
|
||||
^ "."
|
||||
^ expected_output.id
|
||||
in
|
||||
let vars =
|
||||
[
|
||||
@ -392,7 +403,8 @@ let add_root_test_build
|
||||
(all_file_names : string list)
|
||||
(all_test_builds : string) : ninja =
|
||||
let file_names_str =
|
||||
List.hd all_file_names ^ ""
|
||||
List.hd all_file_names
|
||||
^ ""
|
||||
^ List.fold_left
|
||||
(fun acc name -> acc ^ "; " ^ name)
|
||||
"" (List.tl all_file_names)
|
||||
@ -440,9 +452,11 @@ let get_catala_files_in_folder (dir : string) : string list =
|
||||
false
|
||||
in
|
||||
if f_is_dir then
|
||||
readdir_sort f |> Array.to_list
|
||||
readdir_sort f
|
||||
|> Array.to_list
|
||||
|> List.map (Filename.concat f)
|
||||
|> List.append fs |> loop result
|
||||
|> List.append fs
|
||||
|> loop result
|
||||
else loop (f :: result) fs
|
||||
| [] -> result
|
||||
in
|
||||
@ -647,7 +661,9 @@ let driver
|
||||
Nj.format fmt
|
||||
(add_root_test_build ninja ctx.all_file_names
|
||||
ctx.all_test_builds));
|
||||
let ninja_cmd = "ninja " ^ ninja_flags ^ " test -f " ^ ninja_output in
|
||||
let ninja_cmd =
|
||||
"ninja -f " ^ ninja_output ^ " " ^ ninja_flags ^ " test"
|
||||
in
|
||||
Cli.debug_print "executing '%s'..." ninja_cmd;
|
||||
Sys.command ninja_cmd
|
||||
with Sys_error e ->
|
||||
|
@ -7,12 +7,29 @@
|
||||
(library
|
||||
(name clerk_driver)
|
||||
(public_name clerk.driver)
|
||||
(libraries catala.runtime catala.utils ninja_utils cmdliner re ANSITerminal)
|
||||
(libraries
|
||||
catala.runtime_ocaml
|
||||
catala.utils
|
||||
ninja_utils
|
||||
cmdliner
|
||||
re
|
||||
ANSITerminal)
|
||||
(modules clerk_driver))
|
||||
|
||||
(rule
|
||||
(target custom_linking.sexp)
|
||||
(mode fallback)
|
||||
(action
|
||||
(with-stdout-to
|
||||
%{target}
|
||||
(echo "()"))))
|
||||
|
||||
(executable
|
||||
(name clerk)
|
||||
(public_name clerk)
|
||||
(flags
|
||||
(:standard
|
||||
(:include custom_linking.sexp)))
|
||||
(libraries clerk.driver)
|
||||
(modules clerk)
|
||||
(package clerk))
|
||||
|
44
catala.opam
44
catala.opam
@ -18,28 +18,34 @@ license: "Apache-2.0"
|
||||
homepage: "https://github.com/CatalaLang/catala"
|
||||
bug-reports: "https://github.com/CatalaLang/catala/issues"
|
||||
depends: [
|
||||
"dune" {>= "2.8"}
|
||||
"ocaml" {>= "4.11.0"}
|
||||
"ANSITerminal" {>= "0.8.2"}
|
||||
"sedlex" {>= "2.4"}
|
||||
"menhir" {>= "20200211"}
|
||||
"menhirLib" {>= "20200211"}
|
||||
"unionFind" {>= "20200320"}
|
||||
"benchmark" {>= "1.6"}
|
||||
"bindlib" {>= "5.0.1"}
|
||||
"cmdliner" {>= "1.1.0"}
|
||||
"re" {>= "1.9.0"}
|
||||
"zarith" {>= "1.12"}
|
||||
"zarith_stubs_js" {>= "v0.14.1"}
|
||||
"ocamlgraph" {>= "1.8.8"}
|
||||
"visitors" {>= "20200210"}
|
||||
"benchmark" {>= "1.6"}
|
||||
"js_of_ocaml-ppx" {>= "3.8.0"}
|
||||
"ppx_yojson_conv" {>= "0.14.0"}
|
||||
"camomile" {>= "1.0.2"}
|
||||
"cppo" {>= "1"}
|
||||
"dates_calc" {>= "0.0.2"}
|
||||
"dune" {>= "2.8"}
|
||||
"js_of_ocaml-ppx" {>= "3.8.0"}
|
||||
"menhir" {>= "20200211"}
|
||||
"menhirLib" {>= "20200211"}
|
||||
"ocaml" {>= "4.13.0"}
|
||||
"ocamlfind" {!= "1.9.5"}
|
||||
"ocamlgraph" {>= "1.8.8"}
|
||||
"ppx_yojson_conv" {>= "0.14.0"}
|
||||
"re" {>= "1.9.0"}
|
||||
"sedlex" {>= "2.4"}
|
||||
"ubase" {>= "0.05"}
|
||||
"unionFind" {>= "20200320"}
|
||||
"visitors" {>= "20200210"}
|
||||
"zarith" {>= "1.12"}
|
||||
"zarith_stubs_js" {>= "v0.14.1"}
|
||||
"alcotest" {with-test & >= "1.5.0"}
|
||||
"odoc" {with-doc}
|
||||
"ocamlformat" {cataladevmode & = "0.21.0"}
|
||||
"obelisk" {cataladevmode}
|
||||
"conf-npm" {cataladevmode}
|
||||
"conf-python-3-dev" {cataladevmode}
|
||||
"z3" {catalaz3mode}
|
||||
]
|
||||
depopts: ["z3"]
|
||||
conflicts: [
|
||||
@ -60,3 +66,11 @@ build: [
|
||||
]
|
||||
]
|
||||
dev-repo: "git+https://github.com/CatalaLang/catala.git"
|
||||
depexts: [
|
||||
["groff" "colordiff" "latexmk" "python3-pip" "pandoc"]
|
||||
{cataladevmode & os-family = "debian"}
|
||||
["groff" "colordiff" "texlive" "py3-pip" "py3-pygments"]
|
||||
{cataladevmode & os-distribution = "alpine"}
|
||||
["groff" "colordiff" "latex-mk" "python-pygments" "pandoc"]
|
||||
{cataladevmode & os-family = "arch"}
|
||||
]
|
||||
|
@ -35,4 +35,7 @@ build: [
|
||||
]
|
||||
]
|
||||
dev-repo: "git+https://github.com/CatalaLang/catala.git"
|
||||
depexts: ["ninja-build"] {os-family = "debian"}
|
||||
depexts: [
|
||||
["ninja-build"] {os-family = "debian"}
|
||||
["samurai"] {os-distribution = "alpine"}
|
||||
]
|
||||
|
@ -13,7 +13,7 @@ let _ =
|
||||
(Contents (Js.to_string contents))
|
||||
{
|
||||
Utils.Cli.debug = false;
|
||||
unstyled = false;
|
||||
color = Never;
|
||||
wrap_weaved_output = false;
|
||||
avoid_exceptions = false;
|
||||
backend = "Interpret";
|
||||
|
@ -18,6 +18,7 @@
|
||||
[@@@ocaml.warning "-7-34"]
|
||||
|
||||
open Utils
|
||||
module Runtime = Runtime_ocaml.Runtime
|
||||
|
||||
module ScopeName : Uid.Id with type info = Uid.MarkedString.info =
|
||||
Uid.Make (Uid.MarkedString) ()
|
||||
@ -39,15 +40,15 @@ module EnumConstructor : Uid.Id with type info = Uid.MarkedString.info =
|
||||
module EnumMap : Map.S with type key = EnumName.t = Map.Make (EnumName)
|
||||
|
||||
type typ_lit = TBool | TUnit | TInt | TRat | TMoney | TDate | TDuration
|
||||
type struct_name = StructName.t
|
||||
type enum_name = EnumName.t
|
||||
|
||||
type typ =
|
||||
type marked_typ = typ Marked.pos
|
||||
|
||||
and typ =
|
||||
| TLit of typ_lit
|
||||
| TTuple of typ Pos.marked list * struct_name option
|
||||
| TEnum of typ Pos.marked list * enum_name
|
||||
| TArrow of typ Pos.marked * typ Pos.marked
|
||||
| TArray of typ Pos.marked
|
||||
| TTuple of marked_typ list * StructName.t option
|
||||
| TEnum of marked_typ list * EnumName.t
|
||||
| TArrow of marked_typ * marked_typ
|
||||
| TArray of marked_typ
|
||||
| TAny
|
||||
|
||||
type date = Runtime.date
|
||||
@ -95,36 +96,104 @@ type unop =
|
||||
| Log of log_entry * Utils.Uid.MarkedString.info list
|
||||
| Length
|
||||
| IntToRat
|
||||
| MoneyToRat
|
||||
| RatToMoney
|
||||
| GetDay
|
||||
| GetMonth
|
||||
| GetYear
|
||||
| FirstDayOfMonth
|
||||
| LastDayOfMonth
|
||||
| RoundMoney
|
||||
| RoundDecimal
|
||||
|
||||
type operator = Ternop of ternop | Binop of binop | Unop of unop
|
||||
|
||||
type expr =
|
||||
| EVar of expr Bindlib.var Pos.marked
|
||||
| ETuple of expr Pos.marked list * struct_name option
|
||||
(** Some structures used for type inference *)
|
||||
module Infer = struct
|
||||
module Any =
|
||||
Utils.Uid.Make
|
||||
(struct
|
||||
type info = unit
|
||||
|
||||
let format_info fmt () = Format.fprintf fmt "any"
|
||||
end)
|
||||
()
|
||||
|
||||
type unionfind_typ = typ Marked.pos UnionFind.elem
|
||||
(** We do not reuse {!type: Dcalc.Ast.typ} because we have to include a new
|
||||
[TAny] variant. Indeed, error terms can have any type and this has to be
|
||||
captured by the type sytem. *)
|
||||
|
||||
and typ =
|
||||
| TLit of typ_lit
|
||||
| TArrow of unionfind_typ * unionfind_typ
|
||||
| TTuple of unionfind_typ list * StructName.t option
|
||||
| TEnum of unionfind_typ list * EnumName.t
|
||||
| TArray of unionfind_typ
|
||||
| TAny of Any.t
|
||||
|
||||
let rec typ_to_ast (ty : unionfind_typ) : marked_typ =
|
||||
let ty, pos = UnionFind.get (UnionFind.find ty) in
|
||||
match ty with
|
||||
| TLit l -> TLit l, pos
|
||||
| TTuple (ts, s) -> TTuple (List.map typ_to_ast ts, s), pos
|
||||
| TEnum (ts, e) -> TEnum (List.map typ_to_ast ts, e), pos
|
||||
| TArrow (t1, t2) -> TArrow (typ_to_ast t1, typ_to_ast t2), pos
|
||||
| TAny _ -> TAny, pos
|
||||
| TArray t1 -> TArray (typ_to_ast t1), pos
|
||||
|
||||
let rec ast_to_typ (ty : marked_typ) : unionfind_typ =
|
||||
let ty' =
|
||||
match Marked.unmark ty with
|
||||
| TLit l -> TLit l
|
||||
| TArrow (t1, t2) -> TArrow (ast_to_typ t1, ast_to_typ t2)
|
||||
| TTuple (ts, s) -> TTuple (List.map (fun t -> ast_to_typ t) ts, s)
|
||||
| TEnum (ts, e) -> TEnum (List.map (fun t -> ast_to_typ t) ts, e)
|
||||
| TArray t -> TArray (ast_to_typ t)
|
||||
| TAny -> TAny (Any.fresh ())
|
||||
in
|
||||
UnionFind.make (Marked.same_mark_as ty' ty)
|
||||
end
|
||||
|
||||
type untyped = { pos : Pos.t } [@@ocaml.unboxed]
|
||||
type typed = { pos : Pos.t; ty : marked_typ }
|
||||
type inferring = { pos : Pos.t; uf : Infer.unionfind_typ }
|
||||
|
||||
(** The generic type of AST markings. Using a GADT allows functions to be
|
||||
polymorphic in the marking, but still do transformations on types when
|
||||
appropriate *)
|
||||
type _ mark =
|
||||
| Untyped : untyped -> untyped mark
|
||||
| Typed : typed -> typed mark
|
||||
| Inferring : inferring -> inferring mark
|
||||
|
||||
type ('a, 'm) marked = ('a, 'm mark) Marked.t
|
||||
|
||||
type 'm marked_expr = ('m expr, 'm) marked
|
||||
|
||||
and 'm expr =
|
||||
| EVar of 'm expr Bindlib.var
|
||||
| ETuple of 'm marked_expr list * StructName.t option
|
||||
| ETupleAccess of
|
||||
expr Pos.marked * int * struct_name option * typ Pos.marked list
|
||||
| EInj of expr Pos.marked * int * enum_name * typ Pos.marked list
|
||||
| EMatch of expr Pos.marked * expr Pos.marked list * enum_name
|
||||
| EArray of expr Pos.marked list
|
||||
'm marked_expr * int * StructName.t option * typ Marked.pos list
|
||||
| EInj of 'm marked_expr * int * EnumName.t * typ Marked.pos list
|
||||
| EMatch of 'm marked_expr * 'm marked_expr list * EnumName.t
|
||||
| EArray of 'm marked_expr list
|
||||
| ELit of lit
|
||||
| EAbs of
|
||||
(expr, expr Pos.marked) Bindlib.mbinder Pos.marked * typ Pos.marked list
|
||||
| EApp of expr Pos.marked * expr Pos.marked list
|
||||
| EAssert of expr Pos.marked
|
||||
(('m expr, 'm marked_expr) Bindlib.mbinder[@opaque]) * typ Marked.pos list
|
||||
| EApp of 'm marked_expr * 'm marked_expr list
|
||||
| EAssert of 'm marked_expr
|
||||
| EOp of operator
|
||||
| EDefault of expr Pos.marked list * expr Pos.marked * expr Pos.marked
|
||||
| EIfThenElse of expr Pos.marked * expr Pos.marked * expr Pos.marked
|
||||
| ErrorOnEmpty of expr Pos.marked
|
||||
| EDefault of 'm marked_expr list * 'm marked_expr * 'm marked_expr
|
||||
| EIfThenElse of 'm marked_expr * 'm marked_expr * 'm marked_expr
|
||||
| ErrorOnEmpty of 'm marked_expr
|
||||
|
||||
type struct_ctx = (StructFieldName.t * typ Pos.marked) list StructMap.t
|
||||
type enum_ctx = (EnumConstructor.t * typ Pos.marked) list EnumMap.t
|
||||
type typed_expr = typed marked_expr
|
||||
type struct_ctx = (StructFieldName.t * typ Marked.pos) list StructMap.t
|
||||
type enum_ctx = (EnumConstructor.t * typ Marked.pos) list EnumMap.t
|
||||
type decl_ctx = { ctx_enums : enum_ctx; ctx_structs : struct_ctx }
|
||||
type binder = (expr, expr Pos.marked) Bindlib.binder
|
||||
type 'm binder = ('m expr, 'm marked_expr) Bindlib.binder
|
||||
|
||||
type scope_let_kind =
|
||||
| DestructuringInputStruct
|
||||
@ -134,173 +203,158 @@ type scope_let_kind =
|
||||
| DestructuringSubScopeResults
|
||||
| Assertion
|
||||
|
||||
type 'expr scope_let = {
|
||||
type ('expr, 'm) scope_let = {
|
||||
scope_let_kind : scope_let_kind;
|
||||
scope_let_typ : typ Utils.Pos.marked;
|
||||
scope_let_expr : 'expr Utils.Pos.marked;
|
||||
scope_let_next : ('expr, 'expr scope_body_expr) Bindlib.binder;
|
||||
scope_let_pos : Utils.Pos.t;
|
||||
scope_let_typ : typ Marked.pos;
|
||||
scope_let_expr : ('expr, 'm) marked;
|
||||
scope_let_next : ('expr, ('expr, 'm) scope_body_expr) Bindlib.binder;
|
||||
scope_let_pos : Pos.t;
|
||||
}
|
||||
|
||||
and 'expr scope_body_expr =
|
||||
| Result of 'expr Utils.Pos.marked
|
||||
| ScopeLet of 'expr scope_let
|
||||
and ('expr, 'm) scope_body_expr =
|
||||
| Result of ('expr, 'm) marked
|
||||
| ScopeLet of ('expr, 'm) scope_let
|
||||
|
||||
type 'expr scope_body = {
|
||||
type ('expr, 'm) scope_body = {
|
||||
scope_body_input_struct : StructName.t;
|
||||
scope_body_output_struct : StructName.t;
|
||||
scope_body_expr : ('expr, 'expr scope_body_expr) Bindlib.binder;
|
||||
scope_body_expr : ('expr, ('expr, 'm) scope_body_expr) Bindlib.binder;
|
||||
}
|
||||
|
||||
type 'expr scope_def = {
|
||||
type ('expr, 'm) scope_def = {
|
||||
scope_name : ScopeName.t;
|
||||
scope_body : 'expr scope_body;
|
||||
scope_next : ('expr, 'expr scopes) Bindlib.binder;
|
||||
scope_body : ('expr, 'm) scope_body;
|
||||
scope_next : ('expr, ('expr, 'm) scopes) Bindlib.binder;
|
||||
}
|
||||
|
||||
and 'expr scopes = Nil | ScopeDef of 'expr scope_def
|
||||
and ('expr, 'm) scopes = Nil | ScopeDef of ('expr, 'm) scope_def
|
||||
|
||||
type program = { decl_ctx : decl_ctx; scopes : expr scopes }
|
||||
type ('expr, 'm) program_generic = {
|
||||
decl_ctx : decl_ctx;
|
||||
scopes : ('expr, 'm) scopes;
|
||||
}
|
||||
|
||||
let evar (v : expr Bindlib.var) (pos : Pos.t) : expr Pos.marked Bindlib.box =
|
||||
Bindlib.box_apply (fun v' -> v', pos) (Bindlib.box_var v)
|
||||
type 'm program = ('m expr, 'm) program_generic
|
||||
|
||||
let etuple
|
||||
(args : expr Pos.marked Bindlib.box list)
|
||||
(s : StructName.t option)
|
||||
(pos : Pos.t) : expr Pos.marked Bindlib.box =
|
||||
Bindlib.box_apply (fun args -> ETuple (args, s), pos) (Bindlib.box_list args)
|
||||
let no_mark (type m) : m mark -> m mark = function
|
||||
| Untyped _ -> Untyped { pos = Pos.no_pos }
|
||||
| Typed _ -> Typed { pos = Pos.no_pos; ty = Marked.mark Pos.no_pos TAny }
|
||||
| Inferring _ ->
|
||||
Inferring
|
||||
{
|
||||
pos = Pos.no_pos;
|
||||
uf = UnionFind.make Infer.(TAny (Any.fresh ()), Pos.no_pos);
|
||||
}
|
||||
|
||||
let etupleaccess
|
||||
(e1 : expr Pos.marked Bindlib.box)
|
||||
(i : int)
|
||||
(s : StructName.t option)
|
||||
(typs : typ Pos.marked list)
|
||||
(pos : Pos.t) : expr Pos.marked Bindlib.box =
|
||||
Bindlib.box_apply (fun e1 -> ETupleAccess (e1, i, s, typs), pos) e1
|
||||
let mark_pos (type m) (m : m mark) : Pos.t =
|
||||
match m with
|
||||
| Untyped { pos } | Typed { pos; _ } | Inferring { pos; _ } -> pos
|
||||
|
||||
let einj
|
||||
(e1 : expr Pos.marked Bindlib.box)
|
||||
(i : int)
|
||||
(e_name : EnumName.t)
|
||||
(typs : typ Pos.marked list)
|
||||
(pos : Pos.t) : expr Pos.marked Bindlib.box =
|
||||
Bindlib.box_apply (fun e1 -> EInj (e1, i, e_name, typs), pos) e1
|
||||
let pos (type m) (x : ('a, m) marked) : Pos.t = mark_pos (Marked.get_mark x)
|
||||
let ty (_, m) : marked_typ = match m with Typed { ty; _ } -> ty
|
||||
|
||||
let ematch
|
||||
(arg : expr Pos.marked Bindlib.box)
|
||||
(arms : expr Pos.marked Bindlib.box list)
|
||||
(e_name : EnumName.t)
|
||||
(pos : Pos.t) : expr Pos.marked Bindlib.box =
|
||||
let with_ty (type m) (ty : marked_typ) (x : ('a, m) marked) : ('a, typed) marked
|
||||
=
|
||||
Marked.mark
|
||||
(match Marked.get_mark x with
|
||||
| Untyped { pos } | Inferring { pos; _ } -> Typed { pos; ty }
|
||||
| Typed m -> Typed { m with ty })
|
||||
(Marked.unmark x)
|
||||
|
||||
let evar v mark = Bindlib.box_apply (Marked.mark mark) (Bindlib.box_var v)
|
||||
|
||||
let etuple args s mark =
|
||||
Bindlib.box_apply (fun args -> ETuple (args, s), mark) (Bindlib.box_list args)
|
||||
|
||||
let etupleaccess e1 i s typs mark =
|
||||
Bindlib.box_apply (fun e1 -> ETupleAccess (e1, i, s, typs), mark) e1
|
||||
|
||||
let einj e1 i e_name typs mark =
|
||||
Bindlib.box_apply (fun e1 -> EInj (e1, i, e_name, typs), mark) e1
|
||||
|
||||
let ematch arg arms e_name mark =
|
||||
Bindlib.box_apply2
|
||||
(fun arg arms -> EMatch (arg, arms, e_name), pos)
|
||||
(fun arg arms -> EMatch (arg, arms, e_name), mark)
|
||||
arg (Bindlib.box_list arms)
|
||||
|
||||
let earray (args : expr Pos.marked Bindlib.box list) (pos : Pos.t) :
|
||||
expr Pos.marked Bindlib.box =
|
||||
Bindlib.box_apply (fun args -> EArray args, pos) (Bindlib.box_list args)
|
||||
let earray args mark =
|
||||
Bindlib.box_apply (fun args -> EArray args, mark) (Bindlib.box_list args)
|
||||
|
||||
let elit (l : lit) (pos : Pos.t) : expr Pos.marked Bindlib.box =
|
||||
Bindlib.box (ELit l, pos)
|
||||
let elit l mark = Bindlib.box (ELit l, mark)
|
||||
|
||||
let eabs
|
||||
(binder : (expr, expr Pos.marked) Bindlib.mbinder Bindlib.box)
|
||||
(pos_binder : Pos.t)
|
||||
(typs : typ Pos.marked list)
|
||||
(pos : Pos.t) : expr Pos.marked Bindlib.box =
|
||||
Bindlib.box_apply
|
||||
(fun binder -> EAbs ((binder, pos_binder), typs), pos)
|
||||
binder
|
||||
let eabs binder typs mark =
|
||||
Bindlib.box_apply (fun binder -> EAbs (binder, typs), mark) binder
|
||||
|
||||
let eapp
|
||||
(e1 : expr Pos.marked Bindlib.box)
|
||||
(args : expr Pos.marked Bindlib.box list)
|
||||
(pos : Pos.t) : expr Pos.marked Bindlib.box =
|
||||
let eapp e1 args mark =
|
||||
Bindlib.box_apply2
|
||||
(fun e1 args -> EApp (e1, args), pos)
|
||||
(fun e1 args -> EApp (e1, args), mark)
|
||||
e1 (Bindlib.box_list args)
|
||||
|
||||
let eassert (e1 : expr Pos.marked Bindlib.box) (pos : Pos.t) :
|
||||
expr Pos.marked Bindlib.box =
|
||||
Bindlib.box_apply (fun e1 -> EAssert e1, pos) e1
|
||||
let eassert e1 mark = Bindlib.box_apply (fun e1 -> EAssert e1, mark) e1
|
||||
let eop op mark = Bindlib.box (EOp op, mark)
|
||||
|
||||
let eop (op : operator) (pos : Pos.t) : expr Pos.marked Bindlib.box =
|
||||
Bindlib.box (EOp op, pos)
|
||||
|
||||
let edefault
|
||||
(excepts : expr Pos.marked Bindlib.box list)
|
||||
(just : expr Pos.marked Bindlib.box)
|
||||
(cons : expr Pos.marked Bindlib.box)
|
||||
(pos : Pos.t) : expr Pos.marked Bindlib.box =
|
||||
let edefault excepts just cons mark =
|
||||
Bindlib.box_apply3
|
||||
(fun excepts just cons -> EDefault (excepts, just, cons), pos)
|
||||
(fun excepts just cons -> EDefault (excepts, just, cons), mark)
|
||||
(Bindlib.box_list excepts) just cons
|
||||
|
||||
let eifthenelse
|
||||
(e1 : expr Pos.marked Bindlib.box)
|
||||
(e2 : expr Pos.marked Bindlib.box)
|
||||
(e3 : expr Pos.marked Bindlib.box)
|
||||
(pos : Pos.t) : expr Pos.marked Bindlib.box =
|
||||
Bindlib.box_apply3 (fun e1 e2 e3 -> EIfThenElse (e1, e2, e3), pos) e1 e2 e3
|
||||
let eifthenelse e1 e2 e3 mark =
|
||||
Bindlib.box_apply3 (fun e1 e2 e3 -> EIfThenElse (e1, e2, e3), mark) e1 e2 e3
|
||||
|
||||
let eerroronempty (e1 : expr Pos.marked Bindlib.box) (pos : Pos.t) :
|
||||
expr Pos.marked Bindlib.box =
|
||||
Bindlib.box_apply (fun e1 -> ErrorOnEmpty e1, pos) e1
|
||||
let eerroronempty e1 mark =
|
||||
Bindlib.box_apply (fun e1 -> ErrorOnEmpty e1, mark) e1
|
||||
|
||||
let map_expr
|
||||
(ctx : 'a)
|
||||
~(f : 'a -> expr Pos.marked -> expr Pos.marked Bindlib.box)
|
||||
(e : expr Pos.marked) : expr Pos.marked Bindlib.box =
|
||||
match Pos.unmark e with
|
||||
| EVar (v, _pos) -> evar v (Pos.get_position e)
|
||||
| EApp (e1, args) ->
|
||||
eapp (f ctx e1) (List.map (f ctx) args) (Pos.get_position e)
|
||||
| EAbs ((binder, binder_pos), typs) ->
|
||||
eabs
|
||||
(Bindlib.box_mbinder (f ctx) binder)
|
||||
binder_pos typs (Pos.get_position e)
|
||||
| ETuple (args, s) -> etuple (List.map (f ctx) args) s (Pos.get_position e)
|
||||
let translate_var v = Bindlib.copy_var v (fun x -> EVar x) (Bindlib.name_of v)
|
||||
|
||||
let map_expr ctx ~f e =
|
||||
let m = Marked.get_mark e in
|
||||
match Marked.unmark e with
|
||||
| EVar v -> evar (translate_var v) m
|
||||
| EApp (e1, args) -> eapp (f ctx e1) (List.map (f ctx) args) m
|
||||
| EAbs (binder, typs) ->
|
||||
let vars, body = Bindlib.unmbind binder in
|
||||
eabs (Bindlib.bind_mvar (Array.map translate_var vars) (f ctx body)) typs m
|
||||
| ETuple (args, s) -> etuple (List.map (f ctx) args) s m
|
||||
| ETupleAccess (e1, n, s_name, typs) ->
|
||||
etupleaccess ((f ctx) e1) n s_name typs (Pos.get_position e)
|
||||
| EInj (e1, i, e_name, typs) ->
|
||||
einj ((f ctx) e1) i e_name typs (Pos.get_position e)
|
||||
etupleaccess ((f ctx) e1) n s_name typs m
|
||||
| EInj (e1, i, e_name, typs) -> einj ((f ctx) e1) i e_name typs m
|
||||
| EMatch (arg, arms, e_name) ->
|
||||
ematch ((f ctx) arg) (List.map (f ctx) arms) e_name (Pos.get_position e)
|
||||
| EArray args -> earray (List.map (f ctx) args) (Pos.get_position e)
|
||||
| ELit l -> elit l (Pos.get_position e)
|
||||
| EAssert e1 -> eassert ((f ctx) e1) (Pos.get_position e)
|
||||
| EOp op -> Bindlib.box (EOp op, Pos.get_position e)
|
||||
ematch ((f ctx) arg) (List.map (f ctx) arms) e_name m
|
||||
| EArray args -> earray (List.map (f ctx) args) m
|
||||
| ELit l -> elit l m
|
||||
| EAssert e1 -> eassert ((f ctx) e1) m
|
||||
| EOp op -> Bindlib.box (EOp op, m)
|
||||
| EDefault (excepts, just, cons) ->
|
||||
edefault
|
||||
(List.map (f ctx) excepts)
|
||||
((f ctx) just)
|
||||
((f ctx) cons)
|
||||
(Pos.get_position e)
|
||||
edefault (List.map (f ctx) excepts) ((f ctx) just) ((f ctx) cons) m
|
||||
| EIfThenElse (e1, e2, e3) ->
|
||||
eifthenelse ((f ctx) e1) ((f ctx) e2) ((f ctx) e3) (Pos.get_position e)
|
||||
| ErrorOnEmpty e1 -> eerroronempty ((f ctx) e1) (Pos.get_position e)
|
||||
eifthenelse ((f ctx) e1) ((f ctx) e2) ((f ctx) e3) m
|
||||
| ErrorOnEmpty e1 -> eerroronempty ((f ctx) e1) m
|
||||
|
||||
let rec map_expr_top_down ~f e =
|
||||
map_expr () ~f:(fun () -> map_expr_top_down ~f) (f e)
|
||||
|
||||
let map_expr_marks ~f e =
|
||||
map_expr_top_down ~f:(fun e -> Marked.(mark (f (get_mark e)) (unmark e))) e
|
||||
|
||||
let untype_expr e = map_expr_marks ~f:(fun m -> Untyped { pos = mark_pos m }) e
|
||||
|
||||
type ('expr, 'm) box_expr_sig =
|
||||
('expr, 'm) marked -> ('expr, 'm) marked Bindlib.box
|
||||
|
||||
(** See [Bindlib.box_term] documentation for why we are doing that. *)
|
||||
let box_expr (e : expr Pos.marked) : expr Pos.marked Bindlib.box =
|
||||
let box_expr : ('m expr, 'm) box_expr_sig =
|
||||
fun e ->
|
||||
let rec id_t () e = map_expr () ~f:id_t e in
|
||||
id_t () e
|
||||
|
||||
type 'expr box_expr_sig = 'expr Pos.marked -> 'expr Pos.marked Bindlib.box
|
||||
|
||||
let rec fold_left_scope_lets
|
||||
~(f : 'a -> 'expr scope_let -> 'expr Bindlib.var -> 'a)
|
||||
~(init : 'a)
|
||||
(scope_body_expr : 'expr scope_body_expr) : 'a =
|
||||
let rec fold_left_scope_lets ~f ~init scope_body_expr =
|
||||
match scope_body_expr with
|
||||
| Result _ -> init
|
||||
| ScopeLet scope_let ->
|
||||
let var, next = Bindlib.unbind scope_let.scope_let_next in
|
||||
fold_left_scope_lets ~f ~init:(f init scope_let var) next
|
||||
|
||||
let rec fold_right_scope_lets
|
||||
~(f : 'expr scope_let -> 'expr Bindlib.var -> 'a -> 'a)
|
||||
~(init : 'expr Pos.marked -> 'a)
|
||||
(scope_body_expr : 'expr scope_body_expr) : 'a =
|
||||
let rec fold_right_scope_lets ~f ~init scope_body_expr =
|
||||
match scope_body_expr with
|
||||
| Result result -> init result
|
||||
| ScopeLet scope_let ->
|
||||
@ -308,39 +362,25 @@ let rec fold_right_scope_lets
|
||||
let next_result = fold_right_scope_lets ~f ~init next in
|
||||
f scope_let var next_result
|
||||
|
||||
let map_exprs_in_scope_lets
|
||||
~(f : 'expr Pos.marked -> 'expr Pos.marked Bindlib.box)
|
||||
(scope_body_expr : 'expr scope_body_expr) :
|
||||
'expr scope_body_expr Bindlib.box =
|
||||
let map_exprs_in_scope_lets ~f ~varf scope_body_expr =
|
||||
fold_right_scope_lets
|
||||
~f:(fun scope_let var_next (acc : 'expr scope_body_expr Bindlib.box) ->
|
||||
let new_scope_let =
|
||||
Bindlib.box_apply
|
||||
(fun new_expr -> { scope_let with scope_let_expr = new_expr })
|
||||
(f scope_let.scope_let_expr)
|
||||
in
|
||||
let new_next = Bindlib.bind_var var_next acc in
|
||||
~f:(fun scope_let var_next acc ->
|
||||
Bindlib.box_apply2
|
||||
(fun new_next new_scope_let ->
|
||||
ScopeLet { new_scope_let with scope_let_next = new_next })
|
||||
new_next new_scope_let)
|
||||
(fun scope_let_next scope_let_expr ->
|
||||
ScopeLet { scope_let with scope_let_next; scope_let_expr })
|
||||
(Bindlib.bind_var (varf var_next) acc)
|
||||
(f scope_let.scope_let_expr))
|
||||
~init:(fun res -> Bindlib.box_apply (fun res -> Result res) (f res))
|
||||
scope_body_expr
|
||||
|
||||
let rec fold_left_scope_defs
|
||||
~(f : 'a -> 'expr scope_def -> 'expr Bindlib.var -> 'a)
|
||||
~(init : 'a)
|
||||
(scopes : 'expr scopes) : 'a =
|
||||
let rec fold_left_scope_defs ~f ~init scopes =
|
||||
match scopes with
|
||||
| Nil -> init
|
||||
| ScopeDef scope_def ->
|
||||
let var, next = Bindlib.unbind scope_def.scope_next in
|
||||
fold_left_scope_defs ~f ~init:(f init scope_def var) next
|
||||
|
||||
let rec fold_right_scope_defs
|
||||
~(f : 'expr scope_def -> 'expr Bindlib.var -> 'a -> 'a)
|
||||
~(init : 'a)
|
||||
(scopes : 'expr scopes) : 'a =
|
||||
let rec fold_right_scope_defs ~f ~init scopes =
|
||||
match scopes with
|
||||
| Nil -> init
|
||||
| ScopeDef scope_def ->
|
||||
@ -348,9 +388,7 @@ let rec fold_right_scope_defs
|
||||
let result_next = fold_right_scope_defs ~f ~init next in
|
||||
f scope_def var_next result_next
|
||||
|
||||
let map_scope_defs
|
||||
~(f : 'expr scope_def -> 'expr scope_def Bindlib.box)
|
||||
(scopes : 'expr scopes) : 'expr scopes Bindlib.box =
|
||||
let map_scope_defs ~f scopes =
|
||||
fold_right_scope_defs
|
||||
~f:(fun scope_def var_next acc ->
|
||||
let new_scope_def = f scope_def in
|
||||
@ -361,48 +399,62 @@ let map_scope_defs
|
||||
new_scope_def new_next)
|
||||
~init:(Bindlib.box Nil) scopes
|
||||
|
||||
let map_exprs_in_scopes
|
||||
~(f : 'expr Pos.marked -> 'expr Pos.marked Bindlib.box)
|
||||
(scopes : 'expr scopes) : 'expr scopes Bindlib.box =
|
||||
map_scope_defs
|
||||
~f:(fun scope_def ->
|
||||
let map_exprs_in_scopes ~f ~varf scopes =
|
||||
fold_right_scope_defs
|
||||
~f:(fun scope_def var_next acc ->
|
||||
let scope_input_var, scope_lets =
|
||||
Bindlib.unbind scope_def.scope_body.scope_body_expr
|
||||
in
|
||||
let new_scope_body_expr = map_exprs_in_scope_lets ~f scope_lets in
|
||||
let new_scope_body_expr = map_exprs_in_scope_lets ~f ~varf scope_lets in
|
||||
let new_scope_body_expr =
|
||||
Bindlib.bind_var scope_input_var new_scope_body_expr
|
||||
Bindlib.bind_var (varf scope_input_var) new_scope_body_expr
|
||||
in
|
||||
Bindlib.box_apply
|
||||
(fun new_scope_body_expr ->
|
||||
{
|
||||
scope_def with
|
||||
scope_body =
|
||||
{
|
||||
scope_def.scope_body with
|
||||
scope_body_expr = new_scope_body_expr;
|
||||
};
|
||||
})
|
||||
new_scope_body_expr)
|
||||
scopes
|
||||
let new_next = Bindlib.bind_var (varf var_next) acc in
|
||||
Bindlib.box_apply2
|
||||
(fun scope_body_expr scope_next ->
|
||||
ScopeDef
|
||||
{
|
||||
scope_def with
|
||||
scope_body = { scope_def.scope_body with scope_body_expr };
|
||||
scope_next;
|
||||
})
|
||||
new_scope_body_expr new_next)
|
||||
~init:(Bindlib.box Nil) scopes
|
||||
|
||||
let untype_program prg =
|
||||
{
|
||||
prg with
|
||||
scopes =
|
||||
Bindlib.unbox
|
||||
(map_exprs_in_scopes
|
||||
~f:(fun e -> untype_expr e)
|
||||
~varf:translate_var prg.scopes);
|
||||
}
|
||||
|
||||
type 'm var = 'm expr Bindlib.var
|
||||
type 'm vars = 'm expr Bindlib.mvar
|
||||
|
||||
let new_var s = Bindlib.new_var (fun x -> EVar x) s
|
||||
|
||||
module Var = struct
|
||||
type t = expr Bindlib.var
|
||||
type t = V : 'a expr Bindlib.var -> t
|
||||
(* We use this trivial GADT to make the 'm parameter disappear under an
|
||||
existential. It's fine for a use as keys only. (bindlib defines [any_var]
|
||||
similarly but it's not exported) todo: add [@@ocaml.unboxed] once it's
|
||||
possible through abstract types *)
|
||||
|
||||
let make (s : string Pos.marked) : t =
|
||||
Bindlib.new_var
|
||||
(fun (x : expr Bindlib.var) : expr -> EVar (x, Pos.get_position s))
|
||||
(Pos.unmark s)
|
||||
|
||||
let compare x y = Bindlib.compare_vars x y
|
||||
let t v = V v
|
||||
let get (V v) = Bindlib.copy_var v (fun x -> EVar x) (Bindlib.name_of v)
|
||||
let compare (V x) (V y) = Bindlib.compare_vars x y
|
||||
let eq (V x) (V y) = Bindlib.eq_vars x y
|
||||
end
|
||||
|
||||
module VarMap = Map.Make (Var)
|
||||
module VarSet = Set.Make (Var)
|
||||
module VarMap = Map.Make (Var)
|
||||
|
||||
let rec free_vars_expr (e : expr Pos.marked) : VarSet.t =
|
||||
match Pos.unmark e with
|
||||
| EVar (v, _) -> VarSet.singleton v
|
||||
let rec free_vars_expr (e : 'm marked_expr) : VarSet.t =
|
||||
match Marked.unmark e with
|
||||
| EVar v -> VarSet.singleton (Var.t v)
|
||||
| ETuple (es, _) | EArray es ->
|
||||
es |> List.map free_vars_expr |> List.fold_left VarSet.union VarSet.empty
|
||||
| ETupleAccess (e1, _, _, _)
|
||||
@ -411,85 +463,162 @@ let rec free_vars_expr (e : expr Pos.marked) : VarSet.t =
|
||||
| EInj (e1, _, _, _) ->
|
||||
free_vars_expr e1
|
||||
| EApp (e1, es) | EMatch (e1, es, _) ->
|
||||
e1 :: es |> List.map free_vars_expr
|
||||
e1 :: es
|
||||
|> List.map free_vars_expr
|
||||
|> List.fold_left VarSet.union VarSet.empty
|
||||
| EDefault (es, ejust, econs) ->
|
||||
ejust :: econs :: es |> List.map free_vars_expr
|
||||
ejust :: econs :: es
|
||||
|> List.map free_vars_expr
|
||||
|> List.fold_left VarSet.union VarSet.empty
|
||||
| EOp _ | ELit _ -> VarSet.empty
|
||||
| EIfThenElse (e1, e2, e3) ->
|
||||
[e1; e2; e3] |> List.map free_vars_expr
|
||||
[e1; e2; e3]
|
||||
|> List.map free_vars_expr
|
||||
|> List.fold_left VarSet.union VarSet.empty
|
||||
| EAbs ((binder, _), _) ->
|
||||
| EAbs (binder, _) ->
|
||||
let vs, body = Bindlib.unmbind binder in
|
||||
Array.fold_right VarSet.remove vs (free_vars_expr body)
|
||||
Array.fold_right VarSet.remove (Array.map Var.t vs) (free_vars_expr body)
|
||||
|
||||
let rec free_vars_scope_body_expr (scope_lets : expr scope_body_expr) : VarSet.t
|
||||
=
|
||||
let rec free_vars_scope_body_expr (scope_lets : ('m expr, 'm) scope_body_expr) :
|
||||
VarSet.t =
|
||||
match scope_lets with
|
||||
| Result e -> free_vars_expr e
|
||||
| ScopeLet { scope_let_expr = e; scope_let_next = next; _ } ->
|
||||
let v, body = Bindlib.unbind next in
|
||||
VarSet.union (free_vars_expr e)
|
||||
(VarSet.remove v (free_vars_scope_body_expr body))
|
||||
(VarSet.remove (Var.t v) (free_vars_scope_body_expr body))
|
||||
|
||||
let free_vars_scope_body (scope_body : expr scope_body) : VarSet.t =
|
||||
let free_vars_scope_body (scope_body : ('m expr, 'm) scope_body) : VarSet.t =
|
||||
let { scope_body_expr = binder; _ } = scope_body in
|
||||
let v, body = Bindlib.unbind binder in
|
||||
VarSet.remove v (free_vars_scope_body_expr body)
|
||||
VarSet.remove (Var.t v) (free_vars_scope_body_expr body)
|
||||
|
||||
let rec free_vars_scopes (scopes : expr scopes) : VarSet.t =
|
||||
let rec free_vars_scopes (scopes : ('m expr, 'm) scopes) : VarSet.t =
|
||||
match scopes with
|
||||
| Nil -> VarSet.empty
|
||||
| ScopeDef { scope_body = body; scope_next = next; _ } ->
|
||||
let v, next = Bindlib.unbind next in
|
||||
VarSet.union
|
||||
(VarSet.remove v (free_vars_scopes next))
|
||||
(VarSet.remove (Var.t v) (free_vars_scopes next))
|
||||
(free_vars_scope_body body)
|
||||
(* type vars = expr Bindlib.mvar *)
|
||||
|
||||
type vars = expr Bindlib.mvar
|
||||
let make_var ((x, mark) : ('m expr Bindlib.var, 'm) marked) :
|
||||
'm marked_expr Bindlib.box =
|
||||
Bindlib.box_apply (fun x -> x, mark) (Bindlib.box_var x)
|
||||
|
||||
let make_var ((x, pos) : Var.t Pos.marked) : expr Pos.marked Bindlib.box =
|
||||
Bindlib.box_apply (fun x -> x, pos) (Bindlib.box_var x)
|
||||
type ('e, 'm) make_abs_sig =
|
||||
'e Bindlib.mvar ->
|
||||
('e, 'm) marked Bindlib.box ->
|
||||
typ Marked.pos list ->
|
||||
'm mark ->
|
||||
('e, 'm) marked Bindlib.box
|
||||
|
||||
let make_abs
|
||||
(xs : vars)
|
||||
(e : expr Pos.marked Bindlib.box)
|
||||
(pos_binder : Pos.t)
|
||||
(taus : typ Pos.marked list)
|
||||
(pos : Pos.t) : expr Pos.marked Bindlib.box =
|
||||
Bindlib.box_apply
|
||||
(fun b -> EAbs ((b, pos_binder), taus), pos)
|
||||
(Bindlib.bind_mvar xs e)
|
||||
let (make_abs : ('m expr, 'm) make_abs_sig) =
|
||||
fun xs e taus mark ->
|
||||
Bindlib.box_apply (fun b -> EAbs (b, taus), mark) (Bindlib.bind_mvar xs e)
|
||||
|
||||
let make_app
|
||||
(e : expr Pos.marked Bindlib.box)
|
||||
(u : expr Pos.marked Bindlib.box list)
|
||||
(pos : Pos.t) : expr Pos.marked Bindlib.box =
|
||||
Bindlib.box_apply2 (fun e u -> EApp (e, u), pos) e (Bindlib.box_list u)
|
||||
let make_app :
|
||||
'm marked_expr Bindlib.box ->
|
||||
'm marked_expr Bindlib.box list ->
|
||||
'm mark ->
|
||||
'm marked_expr Bindlib.box =
|
||||
fun e u mark ->
|
||||
Bindlib.box_apply2 (fun e u -> EApp (e, u), mark) e (Bindlib.box_list u)
|
||||
|
||||
let make_let_in
|
||||
(x : Var.t)
|
||||
(tau : typ Pos.marked)
|
||||
(e1 : expr Pos.marked Bindlib.box)
|
||||
(e2 : expr Pos.marked Bindlib.box)
|
||||
(pos : Pos.t) : expr Pos.marked Bindlib.box =
|
||||
make_app (make_abs (Array.of_list [x]) e2 pos [tau] pos) [e1] pos
|
||||
type ('expr, 'm) make_let_in_sig =
|
||||
'expr Bindlib.var ->
|
||||
typ Marked.pos ->
|
||||
('expr, 'm) marked Bindlib.box ->
|
||||
('expr, 'm) marked Bindlib.box ->
|
||||
Pos.t ->
|
||||
('expr, 'm) marked Bindlib.box
|
||||
|
||||
let empty_thunked_term : expr Pos.marked =
|
||||
let silent = Var.make ("_", Pos.no_pos) in
|
||||
let map_mark
|
||||
(type m)
|
||||
(pos_f : Pos.t -> Pos.t)
|
||||
(ty_f : marked_typ -> marked_typ)
|
||||
(m : m mark) : m mark =
|
||||
match m with
|
||||
| Untyped { pos } -> Untyped { pos = pos_f pos }
|
||||
| Typed { pos; ty } -> Typed { pos = pos_f pos; ty = ty_f ty }
|
||||
| Inferring { pos; uf } ->
|
||||
Inferring
|
||||
{ pos = pos_f pos; uf = Infer.ast_to_typ (ty_f (Infer.typ_to_ast uf)) }
|
||||
|
||||
let resolve_inferring { uf; pos } = { ty = Infer.typ_to_ast uf; pos }
|
||||
|
||||
let map_mark2
|
||||
(type m)
|
||||
(pos_f : Pos.t -> Pos.t -> Pos.t)
|
||||
(ty_f : typed -> typed -> marked_typ)
|
||||
(m1 : m mark)
|
||||
(m2 : m mark) : m mark =
|
||||
match m1, m2 with
|
||||
| Untyped m1, Untyped m2 -> Untyped { pos = pos_f m1.pos m2.pos }
|
||||
| Typed m1, Typed m2 -> Typed { pos = pos_f m1.pos m2.pos; ty = ty_f m1 m2 }
|
||||
| Inferring m1, Inferring m2 ->
|
||||
Inferring
|
||||
{
|
||||
pos = pos_f m1.pos m2.pos;
|
||||
uf =
|
||||
Infer.ast_to_typ (ty_f (resolve_inferring m1) (resolve_inferring m2));
|
||||
}
|
||||
|
||||
let fold_marks
|
||||
(type m)
|
||||
(pos_f : Pos.t list -> Pos.t)
|
||||
(ty_f : typed list -> marked_typ)
|
||||
(ms : m mark list) : m mark =
|
||||
match ms with
|
||||
| [] -> invalid_arg "Dcalc.Ast.fold_mark"
|
||||
| Untyped _ :: _ as ms ->
|
||||
Untyped { pos = pos_f (List.map (function Untyped { pos } -> pos) ms) }
|
||||
| Typed _ :: _ ->
|
||||
Typed
|
||||
{
|
||||
pos = pos_f (List.map (function Typed { pos; _ } -> pos) ms);
|
||||
ty = ty_f (List.map (function Typed m -> m) ms);
|
||||
}
|
||||
| Inferring _ :: _ ->
|
||||
Inferring
|
||||
{
|
||||
pos = pos_f (List.map (function Inferring { pos; _ } -> pos) ms);
|
||||
uf =
|
||||
Infer.ast_to_typ
|
||||
(ty_f (List.map (function Inferring m -> resolve_inferring m) ms));
|
||||
}
|
||||
|
||||
let empty_thunked_term mark : 'm marked_expr =
|
||||
let silent = new_var "_" in
|
||||
let pos = mark_pos mark in
|
||||
Bindlib.unbox
|
||||
(make_abs (Array.of_list [silent])
|
||||
(Bindlib.box (ELit LEmptyError, Pos.no_pos))
|
||||
Pos.no_pos
|
||||
[TLit TUnit, Pos.no_pos]
|
||||
Pos.no_pos)
|
||||
(make_abs [| silent |]
|
||||
(Bindlib.box (ELit LEmptyError, mark))
|
||||
[TLit TUnit, pos]
|
||||
(map_mark
|
||||
(fun pos -> pos)
|
||||
(fun ty ->
|
||||
Marked.mark pos (TArrow (Marked.mark pos (TLit TUnit), ty)))
|
||||
mark))
|
||||
|
||||
let is_value (e : expr Pos.marked) : bool =
|
||||
match Pos.unmark e with ELit _ | EAbs _ | EOp _ -> true | _ -> false
|
||||
let (make_let_in : ('m expr, 'm) make_let_in_sig) =
|
||||
fun x tau e1 e2 pos ->
|
||||
let m_e1 = Marked.get_mark (Bindlib.unbox e1) in
|
||||
let m_e2 = Marked.get_mark (Bindlib.unbox e2) in
|
||||
let m_abs =
|
||||
map_mark2
|
||||
(fun _ _ -> pos)
|
||||
(fun m1 m2 -> Marked.mark pos (TArrow (m1.ty, m2.ty)))
|
||||
m_e1 m_e2
|
||||
in
|
||||
make_app (make_abs [| x |] e2 [tau] m_abs) [e1] m_e2
|
||||
|
||||
let rec equal_typs (ty1 : typ Pos.marked) (ty2 : typ Pos.marked) : bool =
|
||||
match Pos.unmark ty1, Pos.unmark ty2 with
|
||||
let is_value (e : 'e marked_expr) : bool =
|
||||
match Marked.unmark e with ELit _ | EAbs _ | EOp _ -> true | _ -> false
|
||||
|
||||
let rec equal_typs (ty1 : typ Marked.pos) (ty2 : typ Marked.pos) : bool =
|
||||
match Marked.unmark ty1, Marked.unmark ty2 with
|
||||
| TLit l1, TLit l2 -> l1 = l2
|
||||
| TTuple (tys1, n1), TTuple (tys2, n2) -> n1 = n2 && equal_typs_list tys1 tys2
|
||||
| TEnum (tys1, n1), TEnum (tys2, n2) -> n1 = n2 && equal_typs_list tys1 tys2
|
||||
@ -498,7 +627,7 @@ let rec equal_typs (ty1 : typ Pos.marked) (ty2 : typ Pos.marked) : bool =
|
||||
| TAny, TAny -> true
|
||||
| _, _ -> false
|
||||
|
||||
and equal_typs_list (tys1 : typ Pos.marked list) (tys2 : typ Pos.marked list) :
|
||||
and equal_typs_list (tys1 : typ Marked.pos list) (tys2 : typ Marked.pos list) :
|
||||
bool =
|
||||
List.length tys1 = List.length tys2
|
||||
&& (* OCaml && operator short-circuits when a clause is false, we can safely
|
||||
@ -525,9 +654,9 @@ let equal_ops (op1 : operator) (op2 : operator) : bool =
|
||||
| Unop op1, Unop op2 -> equal_unops op1 op2
|
||||
| _, _ -> false
|
||||
|
||||
let rec equal_exprs (e1 : expr Pos.marked) (e2 : expr Pos.marked) : bool =
|
||||
match Pos.unmark e1, Pos.unmark e2 with
|
||||
| EVar v1, EVar v2 -> Pos.unmark v1 = Pos.unmark v2
|
||||
let rec equal_exprs (e1 : 'm marked_expr) (e2 : 'm marked_expr) : bool =
|
||||
match Marked.unmark e1, Marked.unmark e2 with
|
||||
| EVar v1, EVar v2 -> Bindlib.eq_vars v1 v2
|
||||
| ETuple (es1, n1), ETuple (es2, n2) -> n1 = n2 && equal_exprs_list es1 es2
|
||||
| ETupleAccess (e1, id1, n1, tys1), ETupleAccess (e2, id2, n2, tys2) ->
|
||||
equal_exprs e1 e2 && id1 = id2 && n1 = n2 && equal_typs_list tys1 tys2
|
||||
@ -540,50 +669,32 @@ let rec equal_exprs (e1 : expr Pos.marked) (e2 : expr Pos.marked) : bool =
|
||||
| EAbs (b1, tys1), EAbs (b2, tys2) ->
|
||||
equal_typs_list tys1 tys2
|
||||
&&
|
||||
let vars1, body1 = Bindlib.unmbind (Pos.unmark b1) in
|
||||
let body2 =
|
||||
Bindlib.msubst (Pos.unmark b2)
|
||||
(Array.map (fun x -> EVar (x, Pos.no_pos)) vars1)
|
||||
in
|
||||
let vars1, body1 = Bindlib.unmbind b1 in
|
||||
let body2 = Bindlib.msubst b2 (Array.map (fun x -> EVar x) vars1) in
|
||||
equal_exprs body1 body2
|
||||
| EAssert e1, EAssert e2 -> equal_exprs e1 e2
|
||||
| EOp op1, EOp op2 -> equal_ops op1 op2
|
||||
| EDefault (exc1, def1, cons1), EDefault (exc2, def2, cons2) ->
|
||||
equal_exprs def1 def2 && equal_exprs cons1 cons2
|
||||
equal_exprs def1 def2
|
||||
&& equal_exprs cons1 cons2
|
||||
&& equal_exprs_list exc1 exc2
|
||||
| EIfThenElse (if1, then1, else1), EIfThenElse (if2, then2, else2) ->
|
||||
equal_exprs if1 if2 && equal_exprs then1 then2 && equal_exprs else1 else2
|
||||
| ErrorOnEmpty e1, ErrorOnEmpty e2 -> equal_exprs e1 e2
|
||||
| _, _ -> false
|
||||
|
||||
and equal_exprs_list (es1 : expr Pos.marked list) (es2 : expr Pos.marked list) :
|
||||
and equal_exprs_list (es1 : 'e marked_expr list) (es2 : 'm marked_expr list) :
|
||||
bool =
|
||||
List.length es1 = List.length es2
|
||||
&& (* OCaml && operator short-circuits when a clause is false, we can safely
|
||||
assume here that both lists have equal length *)
|
||||
List.for_all (fun (x, y) -> equal_exprs x y) (List.combine es1 es2)
|
||||
|
||||
type 'expr make_let_in_sig =
|
||||
'expr Bindlib.var ->
|
||||
typ Pos.marked ->
|
||||
'expr Pos.marked Bindlib.box ->
|
||||
'expr Pos.marked Bindlib.box ->
|
||||
Pos.t ->
|
||||
'expr Pos.marked Bindlib.box
|
||||
|
||||
type 'expr make_abs_sig =
|
||||
'expr Bindlib.mvar ->
|
||||
'expr Pos.marked Bindlib.box ->
|
||||
Pos.t ->
|
||||
typ Pos.marked list ->
|
||||
Pos.t ->
|
||||
'expr Pos.marked Bindlib.box
|
||||
|
||||
let rec unfold_scope_body_expr
|
||||
~(box_expr : 'expr box_expr_sig)
|
||||
~(make_let_in : 'expr make_let_in_sig)
|
||||
~(box_expr : ('expr, 'm) box_expr_sig)
|
||||
~(make_let_in : ('expr, 'm) make_let_in_sig)
|
||||
(ctx : decl_ctx)
|
||||
(scope_let : 'expr scope_body_expr) : 'expr Pos.marked Bindlib.box =
|
||||
(scope_let : ('expr, 'm) scope_body_expr) : ('expr, 'm) marked Bindlib.box =
|
||||
match scope_let with
|
||||
| Result e -> box_expr e
|
||||
| ScopeLet
|
||||
@ -600,29 +711,29 @@ let rec unfold_scope_body_expr
|
||||
scope_let_pos
|
||||
|
||||
let build_whole_scope_expr
|
||||
~(box_expr : 'expr box_expr_sig)
|
||||
~(make_abs : 'expr make_abs_sig)
|
||||
~(make_let_in : 'expr make_let_in_sig)
|
||||
~(box_expr : ('expr, 'm) box_expr_sig)
|
||||
~(make_abs : ('expr, 'm) make_abs_sig)
|
||||
~(make_let_in : ('expr, 'm) make_let_in_sig)
|
||||
(ctx : decl_ctx)
|
||||
(body : 'expr scope_body)
|
||||
(pos_scope : Pos.t) : 'expr Pos.marked Bindlib.box =
|
||||
(body : ('expr, 'm) scope_body)
|
||||
(mark_scope : 'm mark) : ('expr, 'm) marked Bindlib.box =
|
||||
let var, body_expr = Bindlib.unbind body.scope_body_expr in
|
||||
let body_expr = unfold_scope_body_expr ~box_expr ~make_let_in ctx body_expr in
|
||||
make_abs (Array.of_list [var]) body_expr pos_scope
|
||||
make_abs (Array.of_list [var]) body_expr
|
||||
[
|
||||
( TTuple
|
||||
( List.map snd
|
||||
(StructMap.find body.scope_body_input_struct ctx.ctx_structs),
|
||||
Some body.scope_body_input_struct ),
|
||||
pos_scope );
|
||||
mark_pos mark_scope );
|
||||
]
|
||||
pos_scope
|
||||
mark_scope
|
||||
|
||||
let build_scope_typ_from_sig
|
||||
(ctx : decl_ctx)
|
||||
(scope_input_struct_name : StructName.t)
|
||||
(scope_return_struct_name : StructName.t)
|
||||
(pos : Pos.t) : typ Pos.marked =
|
||||
(pos : Pos.t) : typ Marked.pos =
|
||||
let scope_sig = StructMap.find scope_input_struct_name ctx.ctx_structs in
|
||||
let scope_return_typ =
|
||||
StructMap.find scope_return_struct_name ctx.ctx_structs
|
||||
@ -639,22 +750,27 @@ type 'expr scope_name_or_var =
|
||||
| ScopeName of ScopeName.t
|
||||
| ScopeVar of 'expr Bindlib.var
|
||||
|
||||
let get_scope_body_mark scope_body =
|
||||
match snd (Bindlib.unbind scope_body.scope_body_expr) with
|
||||
| Result e | ScopeLet { scope_let_expr = e; _ } -> Marked.get_mark e
|
||||
|
||||
let rec unfold_scopes
|
||||
~(box_expr : 'expr box_expr_sig)
|
||||
~(make_abs : 'expr make_abs_sig)
|
||||
~(make_let_in : 'expr make_let_in_sig)
|
||||
~(box_expr : ('expr, 'm) box_expr_sig)
|
||||
~(make_abs : ('expr, 'm) make_abs_sig)
|
||||
~(make_let_in : ('expr, 'm) make_let_in_sig)
|
||||
(ctx : decl_ctx)
|
||||
(s : 'expr scopes)
|
||||
(main_scope : 'expr scope_name_or_var) : 'expr Pos.marked Bindlib.box =
|
||||
(s : ('expr, 'm) scopes)
|
||||
(mark : 'm mark)
|
||||
(main_scope : 'expr scope_name_or_var) : ('expr, 'm) marked Bindlib.box =
|
||||
match s with
|
||||
| Nil -> (
|
||||
match main_scope with
|
||||
| ScopeVar v ->
|
||||
Bindlib.box_apply (fun v -> v, Pos.no_pos) (Bindlib.box_var v)
|
||||
| ScopeVar v -> Bindlib.box_apply (fun v -> v, mark) (Bindlib.box_var v)
|
||||
| ScopeName _ -> failwith "should not happen")
|
||||
| ScopeDef { scope_name; scope_body; scope_next } ->
|
||||
let scope_var, scope_next = Bindlib.unbind scope_next in
|
||||
let scope_pos = Pos.get_position (ScopeName.get_info scope_name) in
|
||||
let scope_pos = Marked.get_mark (ScopeName.get_info scope_name) in
|
||||
let scope_body_mark = get_scope_body_mark scope_body in
|
||||
let main_scope =
|
||||
match main_scope with
|
||||
| ScopeVar v -> ScopeVar v
|
||||
@ -666,16 +782,32 @@ let rec unfold_scopes
|
||||
(build_scope_typ_from_sig ctx scope_body.scope_body_input_struct
|
||||
scope_body.scope_body_output_struct scope_pos)
|
||||
(build_whole_scope_expr ~box_expr ~make_abs ~make_let_in ctx scope_body
|
||||
scope_pos)
|
||||
(unfold_scopes ~box_expr ~make_abs ~make_let_in ctx scope_next main_scope)
|
||||
scope_body_mark)
|
||||
(unfold_scopes ~box_expr ~make_abs ~make_let_in ctx scope_next mark
|
||||
main_scope)
|
||||
scope_pos
|
||||
|
||||
let build_whole_program_expr (p : program) (main_scope : ScopeName.t) =
|
||||
let rec find_scope name vars = function
|
||||
| Nil -> raise Not_found
|
||||
| ScopeDef { scope_name; scope_body; _ } when scope_name = name ->
|
||||
List.rev vars, scope_body
|
||||
| ScopeDef { scope_next; _ } ->
|
||||
let var, next = Bindlib.unbind scope_next in
|
||||
find_scope name (var :: vars) next
|
||||
|
||||
let build_whole_program_expr
|
||||
~(box_expr : ('expr, 'm) box_expr_sig)
|
||||
~(make_abs : ('expr, 'm) make_abs_sig)
|
||||
~(make_let_in : ('expr, 'm) make_let_in_sig)
|
||||
(p : ('expr, 'm) program_generic)
|
||||
(main_scope : ScopeName.t) : ('expr, 'm) marked Bindlib.box =
|
||||
let _, main_scope_body = find_scope main_scope [] p.scopes in
|
||||
unfold_scopes ~box_expr ~make_abs ~make_let_in p.decl_ctx p.scopes
|
||||
(get_scope_body_mark main_scope_body)
|
||||
(ScopeName main_scope)
|
||||
|
||||
let rec expr_size (e : expr Pos.marked) : int =
|
||||
match Pos.unmark e with
|
||||
let rec expr_size (e : 'm marked_expr) : int =
|
||||
match Marked.unmark e with
|
||||
| EVar _ | ELit _ | EOp _ -> 1
|
||||
| ETuple (args, _) | EArray args ->
|
||||
List.fold_left (fun acc arg -> acc + expr_size arg) 1 args
|
||||
@ -686,7 +818,7 @@ let rec expr_size (e : expr Pos.marked) : int =
|
||||
expr_size e1 + 1
|
||||
| EMatch (arg, args, _) | EApp (arg, args) ->
|
||||
List.fold_left (fun acc arg -> acc + expr_size arg) (1 + expr_size arg) args
|
||||
| EAbs ((binder, _), _) ->
|
||||
| EAbs (binder, _) ->
|
||||
let _, body = Bindlib.unmbind binder in
|
||||
1 + expr_size body
|
||||
| EIfThenElse (e1, e2, e3) -> 1 + expr_size e1 + expr_size e2 + expr_size e3
|
||||
@ -696,9 +828,9 @@ let rec expr_size (e : expr Pos.marked) : int =
|
||||
(1 + expr_size just + expr_size cons)
|
||||
exceptions
|
||||
|
||||
let remove_logging_calls (e : expr Pos.marked) : expr Pos.marked Bindlib.box =
|
||||
let remove_logging_calls (e : 'm marked_expr) : 'm marked_expr Bindlib.box =
|
||||
let rec f () e =
|
||||
match Pos.unmark e with
|
||||
match Marked.unmark e with
|
||||
| EApp ((EOp (Unop (Log _)), _), [arg]) -> map_expr () ~f arg
|
||||
| _ -> map_expr () ~f e
|
||||
in
|
||||
|
@ -18,6 +18,7 @@
|
||||
(** Abstract syntax tree of the default calculus intermediate representation *)
|
||||
|
||||
open Utils
|
||||
module Runtime = Runtime_ocaml.Runtime
|
||||
module ScopeName : Uid.Id with type info = Uid.MarkedString.info
|
||||
module StructName : Uid.Id with type info = Uid.MarkedString.info
|
||||
module StructFieldName : Uid.Id with type info = Uid.MarkedString.info
|
||||
@ -32,12 +33,14 @@ module EnumMap : Map.S with type key = EnumName.t
|
||||
|
||||
type typ_lit = TBool | TUnit | TInt | TRat | TMoney | TDate | TDuration
|
||||
|
||||
type typ =
|
||||
type marked_typ = typ Marked.pos
|
||||
|
||||
and typ =
|
||||
| TLit of typ_lit
|
||||
| TTuple of typ Pos.marked list * StructName.t option
|
||||
| TEnum of typ Pos.marked list * EnumName.t
|
||||
| TArrow of typ Pos.marked * typ Pos.marked
|
||||
| TArray of typ Pos.marked
|
||||
| TTuple of marked_typ list * StructName.t option
|
||||
| TEnum of marked_typ list * EnumName.t
|
||||
| TArrow of marked_typ * marked_typ
|
||||
| TArray of marked_typ
|
||||
| TAny
|
||||
|
||||
type date = Runtime.date
|
||||
@ -94,43 +97,85 @@ type unop =
|
||||
| Log of log_entry * Utils.Uid.MarkedString.info list
|
||||
| Length
|
||||
| IntToRat
|
||||
| MoneyToRat
|
||||
| RatToMoney
|
||||
| GetDay
|
||||
| GetMonth
|
||||
| GetYear
|
||||
| FirstDayOfMonth
|
||||
| LastDayOfMonth
|
||||
| RoundMoney
|
||||
| RoundDecimal
|
||||
|
||||
type operator = Ternop of ternop | Binop of binop | Unop of unop
|
||||
|
||||
(** Contains some structures used for type inference *)
|
||||
module Infer : sig
|
||||
module Any : Utils.Uid.Id with type info = unit
|
||||
|
||||
type unionfind_typ = typ Marked.pos UnionFind.elem
|
||||
(** We do not reuse {!type: typ} because we have to include a new [TAny]
|
||||
variant. Indeed, error terms can have any type and this has to be captured
|
||||
by the type sytem. *)
|
||||
|
||||
and typ =
|
||||
| TLit of typ_lit
|
||||
| TArrow of unionfind_typ * unionfind_typ
|
||||
| TTuple of unionfind_typ list * StructName.t option
|
||||
| TEnum of unionfind_typ list * EnumName.t
|
||||
| TArray of unionfind_typ
|
||||
| TAny of Any.t
|
||||
|
||||
val typ_to_ast : unionfind_typ -> marked_typ
|
||||
val ast_to_typ : marked_typ -> unionfind_typ
|
||||
end
|
||||
|
||||
type untyped = { pos : Pos.t } [@@unboxed]
|
||||
type typed = { pos : Pos.t; ty : marked_typ }
|
||||
type inferring = { pos : Pos.t; uf : Infer.unionfind_typ }
|
||||
|
||||
(** The generic type of AST markings. Using a GADT allows functions to be
|
||||
polymorphic in the marking, but still do transformations on types when
|
||||
appropriate *)
|
||||
type _ mark =
|
||||
| Untyped : untyped -> untyped mark
|
||||
| Typed : typed -> typed mark
|
||||
| Inferring : inferring -> inferring mark
|
||||
|
||||
type ('a, 'm) marked = ('a, 'm mark) Marked.t
|
||||
|
||||
type 'm marked_expr = ('m expr, 'm) marked
|
||||
|
||||
(** The expressions use the {{:https://lepigre.fr/ocaml-bindlib/} Bindlib}
|
||||
library, based on higher-order abstract syntax*)
|
||||
type expr =
|
||||
| EVar of expr Bindlib.var Pos.marked
|
||||
| ETuple of expr Pos.marked list * StructName.t option
|
||||
and 'm expr =
|
||||
| EVar of 'm expr Bindlib.var
|
||||
| ETuple of 'm marked_expr list * StructName.t option
|
||||
(** The [MarkedString.info] is the former struct field name*)
|
||||
| ETupleAccess of
|
||||
expr Pos.marked * int * StructName.t option * typ Pos.marked list
|
||||
| ETupleAccess of 'm marked_expr * int * StructName.t option * marked_typ list
|
||||
(** The [MarkedString.info] is the former struct field name *)
|
||||
| EInj of expr Pos.marked * int * EnumName.t * typ Pos.marked list
|
||||
| EInj of 'm marked_expr * int * EnumName.t * marked_typ list
|
||||
(** The [MarkedString.info] is the former enum case name *)
|
||||
| EMatch of expr Pos.marked * expr Pos.marked list * EnumName.t
|
||||
| EMatch of 'm marked_expr * 'm marked_expr list * EnumName.t
|
||||
(** The [MarkedString.info] is the former enum case name *)
|
||||
| EArray of expr Pos.marked list
|
||||
| EArray of 'm marked_expr list
|
||||
| ELit of lit
|
||||
| EAbs of
|
||||
((expr, expr Pos.marked) Bindlib.mbinder[@opaque]) Pos.marked
|
||||
* typ Pos.marked list
|
||||
| EApp of expr Pos.marked * expr Pos.marked list
|
||||
| EAssert of expr Pos.marked
|
||||
(('m expr, 'm marked_expr) Bindlib.mbinder[@opaque]) * marked_typ list
|
||||
| EApp of 'm marked_expr * 'm marked_expr list
|
||||
| EAssert of 'm marked_expr
|
||||
| EOp of operator
|
||||
| EDefault of expr Pos.marked list * expr Pos.marked * expr Pos.marked
|
||||
| EIfThenElse of expr Pos.marked * expr Pos.marked * expr Pos.marked
|
||||
| ErrorOnEmpty of expr Pos.marked
|
||||
| EDefault of 'm marked_expr list * 'm marked_expr * 'm marked_expr
|
||||
| EIfThenElse of 'm marked_expr * 'm marked_expr * 'm marked_expr
|
||||
| ErrorOnEmpty of 'm marked_expr
|
||||
|
||||
type struct_ctx = (StructFieldName.t * typ Pos.marked) list StructMap.t
|
||||
type enum_ctx = (EnumConstructor.t * typ Pos.marked) list EnumMap.t
|
||||
(** {3 Expression annotations ([Marked.t])} *)
|
||||
|
||||
type typed_expr = typed marked_expr
|
||||
type struct_ctx = (StructFieldName.t * marked_typ) list StructMap.t
|
||||
type enum_ctx = (EnumConstructor.t * marked_typ) list EnumMap.t
|
||||
type decl_ctx = { ctx_enums : enum_ctx; ctx_structs : struct_ctx }
|
||||
type binder = (expr, expr Pos.marked) Bindlib.binder
|
||||
type 'm binder = ('m expr, 'm marked_expr) Bindlib.binder
|
||||
|
||||
(** This kind annotation signals that the let-binding respects a structural
|
||||
invariant. These invariants concern the shape of the expression in the
|
||||
@ -145,12 +190,12 @@ type scope_let_kind =
|
||||
| DestructuringSubScopeResults (** [let s.x = result.x ]**)
|
||||
| Assertion (** [let _ = assert e]*)
|
||||
|
||||
type 'expr scope_let = {
|
||||
type ('expr, 'm) scope_let = {
|
||||
scope_let_kind : scope_let_kind;
|
||||
scope_let_typ : typ Utils.Pos.marked;
|
||||
scope_let_expr : 'expr Utils.Pos.marked;
|
||||
scope_let_next : ('expr, 'expr scope_body_expr) Bindlib.binder;
|
||||
scope_let_pos : Utils.Pos.t;
|
||||
scope_let_typ : marked_typ;
|
||||
scope_let_expr : ('expr, 'm) marked;
|
||||
scope_let_next : ('expr, ('expr, 'm) scope_body_expr) Bindlib.binder;
|
||||
scope_let_pos : Pos.t;
|
||||
}
|
||||
(** This type is parametrized by the expression type so it can be reused in
|
||||
later intermediate representations. *)
|
||||
@ -158,110 +203,143 @@ type 'expr scope_let = {
|
||||
(** A scope let-binding has all the information necessary to make a proper
|
||||
let-binding expression, plus an annotation for the kind of the let-binding
|
||||
that comes from the compilation of a {!module: Scopelang.Ast} statement. *)
|
||||
and 'expr scope_body_expr =
|
||||
| Result of 'expr Utils.Pos.marked
|
||||
| ScopeLet of 'expr scope_let
|
||||
and ('expr, 'm) scope_body_expr =
|
||||
| Result of ('expr, 'm) marked
|
||||
| ScopeLet of ('expr, 'm) scope_let
|
||||
|
||||
type 'expr scope_body = {
|
||||
type ('expr, 'm) scope_body = {
|
||||
scope_body_input_struct : StructName.t;
|
||||
scope_body_output_struct : StructName.t;
|
||||
scope_body_expr : ('expr, 'expr scope_body_expr) Bindlib.binder;
|
||||
scope_body_expr : ('expr, ('expr, 'm) scope_body_expr) Bindlib.binder;
|
||||
}
|
||||
(** Instead of being a single expression, we give a little more ad-hoc structure
|
||||
to the scope body by decomposing it in an ordered list of let-bindings, and
|
||||
a result expression that uses the let-binded variables. The first binder is
|
||||
the argument of type [scope_body_input_struct]. *)
|
||||
|
||||
type 'expr scope_def = {
|
||||
type ('expr, 'm) scope_def = {
|
||||
scope_name : ScopeName.t;
|
||||
scope_body : 'expr scope_body;
|
||||
scope_next : ('expr, 'expr scopes) Bindlib.binder;
|
||||
scope_body : ('expr, 'm) scope_body;
|
||||
scope_next : ('expr, ('expr, 'm) scopes) Bindlib.binder;
|
||||
}
|
||||
|
||||
(** Finally, we do the same transformation for the whole program for the kinded
|
||||
lets. This permit us to use bindlib variables for scopes names. *)
|
||||
and 'a scopes = Nil | ScopeDef of 'a scope_def
|
||||
and ('expr, 'm) scopes = Nil | ScopeDef of ('expr, 'm) scope_def
|
||||
|
||||
type program = { decl_ctx : decl_ctx; scopes : expr scopes }
|
||||
type ('expr, 'm) program_generic = {
|
||||
decl_ctx : decl_ctx;
|
||||
scopes : ('expr, 'm) scopes;
|
||||
}
|
||||
|
||||
type 'm program = ('m expr, 'm) program_generic
|
||||
|
||||
(** {1 Helpers} *)
|
||||
|
||||
(** {2 Boxed constructors}*)
|
||||
(** {2 Manipulation of marks} *)
|
||||
|
||||
val evar : expr Bindlib.var -> Pos.t -> expr Pos.marked Bindlib.box
|
||||
val no_mark : 'm mark -> 'm mark
|
||||
val mark_pos : 'm mark -> Pos.t
|
||||
val pos : ('a, 'm) marked -> Pos.t
|
||||
val ty : ('a, typed) marked -> marked_typ
|
||||
val with_ty : marked_typ -> ('a, 'm) marked -> ('a, typed) marked
|
||||
|
||||
(** All the following functions will resolve the types if called on an
|
||||
[Inferring] type *)
|
||||
|
||||
val map_mark :
|
||||
(Pos.t -> Pos.t) -> (marked_typ -> marked_typ) -> 'm mark -> 'm mark
|
||||
|
||||
val map_mark2 :
|
||||
(Pos.t -> Pos.t -> Pos.t) ->
|
||||
(typed -> typed -> marked_typ) ->
|
||||
'm mark ->
|
||||
'm mark ->
|
||||
'm mark
|
||||
|
||||
val fold_marks :
|
||||
(Pos.t list -> Pos.t) -> (typed list -> marked_typ) -> 'm mark list -> 'm mark
|
||||
|
||||
val get_scope_body_mark : ('expr, 'm) scope_body -> 'm mark
|
||||
val untype_expr : 'm marked_expr -> untyped marked_expr Bindlib.box
|
||||
val untype_program : 'm program -> untyped program
|
||||
|
||||
(** {2 Boxed constructors} *)
|
||||
|
||||
val evar : 'm expr Bindlib.var -> 'm mark -> 'm marked_expr Bindlib.box
|
||||
|
||||
val etuple :
|
||||
expr Pos.marked Bindlib.box list ->
|
||||
'm marked_expr Bindlib.box list ->
|
||||
StructName.t option ->
|
||||
Pos.t ->
|
||||
expr Pos.marked Bindlib.box
|
||||
'm mark ->
|
||||
'm marked_expr Bindlib.box
|
||||
|
||||
val etupleaccess :
|
||||
expr Pos.marked Bindlib.box ->
|
||||
'm marked_expr Bindlib.box ->
|
||||
int ->
|
||||
StructName.t option ->
|
||||
typ Pos.marked list ->
|
||||
Pos.t ->
|
||||
expr Pos.marked Bindlib.box
|
||||
marked_typ list ->
|
||||
'm mark ->
|
||||
'm marked_expr Bindlib.box
|
||||
|
||||
val einj :
|
||||
expr Pos.marked Bindlib.box ->
|
||||
'm marked_expr Bindlib.box ->
|
||||
int ->
|
||||
EnumName.t ->
|
||||
typ Pos.marked list ->
|
||||
Pos.t ->
|
||||
expr Pos.marked Bindlib.box
|
||||
marked_typ list ->
|
||||
'm mark ->
|
||||
'm marked_expr Bindlib.box
|
||||
|
||||
val ematch :
|
||||
expr Pos.marked Bindlib.box ->
|
||||
expr Pos.marked Bindlib.box list ->
|
||||
'm marked_expr Bindlib.box ->
|
||||
'm marked_expr Bindlib.box list ->
|
||||
EnumName.t ->
|
||||
Pos.t ->
|
||||
expr Pos.marked Bindlib.box
|
||||
'm mark ->
|
||||
'm marked_expr Bindlib.box
|
||||
|
||||
val earray :
|
||||
expr Pos.marked Bindlib.box list -> Pos.t -> expr Pos.marked Bindlib.box
|
||||
'm marked_expr Bindlib.box list -> 'm mark -> 'm marked_expr Bindlib.box
|
||||
|
||||
val elit : lit -> Pos.t -> expr Pos.marked Bindlib.box
|
||||
val elit : lit -> 'm mark -> 'm marked_expr Bindlib.box
|
||||
|
||||
val eabs :
|
||||
(expr, expr Pos.marked) Bindlib.mbinder Bindlib.box ->
|
||||
Pos.t ->
|
||||
typ Pos.marked list ->
|
||||
Pos.t ->
|
||||
expr Pos.marked Bindlib.box
|
||||
('m expr, 'm marked_expr) Bindlib.mbinder Bindlib.box ->
|
||||
marked_typ list ->
|
||||
'm mark ->
|
||||
'm marked_expr Bindlib.box
|
||||
|
||||
val eapp :
|
||||
expr Pos.marked Bindlib.box ->
|
||||
expr Pos.marked Bindlib.box list ->
|
||||
Pos.t ->
|
||||
expr Pos.marked Bindlib.box
|
||||
'm marked_expr Bindlib.box ->
|
||||
'm marked_expr Bindlib.box list ->
|
||||
'm mark ->
|
||||
'm marked_expr Bindlib.box
|
||||
|
||||
val eassert :
|
||||
expr Pos.marked Bindlib.box -> Pos.t -> expr Pos.marked Bindlib.box
|
||||
'm marked_expr Bindlib.box -> 'm mark -> 'm marked_expr Bindlib.box
|
||||
|
||||
val eop : operator -> Pos.t -> expr Pos.marked Bindlib.box
|
||||
val eop : operator -> 'm mark -> 'm marked_expr Bindlib.box
|
||||
|
||||
val edefault :
|
||||
expr Pos.marked Bindlib.box list ->
|
||||
expr Pos.marked Bindlib.box ->
|
||||
expr Pos.marked Bindlib.box ->
|
||||
Pos.t ->
|
||||
expr Pos.marked Bindlib.box
|
||||
'm marked_expr Bindlib.box list ->
|
||||
'm marked_expr Bindlib.box ->
|
||||
'm marked_expr Bindlib.box ->
|
||||
'm mark ->
|
||||
'm marked_expr Bindlib.box
|
||||
|
||||
val eifthenelse :
|
||||
expr Pos.marked Bindlib.box ->
|
||||
expr Pos.marked Bindlib.box ->
|
||||
expr Pos.marked Bindlib.box ->
|
||||
Pos.t ->
|
||||
expr Pos.marked Bindlib.box
|
||||
'm marked_expr Bindlib.box ->
|
||||
'm marked_expr Bindlib.box ->
|
||||
'm marked_expr Bindlib.box ->
|
||||
'm mark ->
|
||||
'm marked_expr Bindlib.box
|
||||
|
||||
val eerroronempty :
|
||||
expr Pos.marked Bindlib.box -> Pos.t -> expr Pos.marked Bindlib.box
|
||||
'm marked_expr Bindlib.box -> 'm mark -> 'm marked_expr Bindlib.box
|
||||
|
||||
val box_expr : expr Pos.marked -> expr Pos.marked Bindlib.box
|
||||
type ('expr, 'm) box_expr_sig =
|
||||
('expr, 'm) marked -> ('expr, 'm) marked Bindlib.box
|
||||
|
||||
type 'expr box_expr_sig = 'expr Pos.marked -> 'expr Pos.marked Bindlib.box
|
||||
val box_expr : ('m expr, 'm) box_expr_sig
|
||||
|
||||
(**{2 Program traversal}*)
|
||||
|
||||
@ -270,9 +348,9 @@ type 'expr box_expr_sig = 'expr Pos.marked -> 'expr Pos.marked Bindlib.box
|
||||
|
||||
val map_expr :
|
||||
'a ->
|
||||
f:('a -> expr Pos.marked -> expr Pos.marked Bindlib.box) ->
|
||||
expr Pos.marked ->
|
||||
expr Pos.marked Bindlib.box
|
||||
f:('a -> 'm1 marked_expr -> 'm2 marked_expr Bindlib.box) ->
|
||||
('m1 expr, 'm2 mark) Marked.t ->
|
||||
'm2 marked_expr Bindlib.box
|
||||
(** If you want to apply a map transform to an expression, you can save up
|
||||
writing a painful match over all the cases of the AST. For instance, if you
|
||||
want to remove all errors on empty, you can write
|
||||
@ -280,7 +358,7 @@ val map_expr :
|
||||
{[
|
||||
let remove_error_empty =
|
||||
let rec f () e =
|
||||
match Pos.unmark e with
|
||||
match Marked.unmark e with
|
||||
| ErrorOnEmpty e1 -> map_expr () f e1
|
||||
| _ -> map_expr () f e
|
||||
in
|
||||
@ -290,10 +368,21 @@ val map_expr :
|
||||
The first argument of map_expr is an optional context that you can carry
|
||||
around during your map traversal. *)
|
||||
|
||||
val map_expr_top_down :
|
||||
f:('m1 marked_expr -> ('m1 expr, 'm2 mark) Marked.t) ->
|
||||
'm1 marked_expr ->
|
||||
'm2 marked_expr Bindlib.box
|
||||
(** Recursively applies [f] to the nodes of the expression tree. The type
|
||||
returned by [f] is hybrid since the mark at top-level has been rewritten,
|
||||
but not yet the marks in the subtrees. *)
|
||||
|
||||
val map_expr_marks :
|
||||
f:('m1 mark -> 'm2 mark) -> 'm1 marked_expr -> 'm2 marked_expr Bindlib.box
|
||||
|
||||
val fold_left_scope_lets :
|
||||
f:('a -> 'expr scope_let -> 'expr Bindlib.var -> 'a) ->
|
||||
f:('a -> ('expr, 'm) scope_let -> 'expr Bindlib.var -> 'a) ->
|
||||
init:'a ->
|
||||
'expr scope_body_expr ->
|
||||
('expr, 'm) scope_body_expr ->
|
||||
'a
|
||||
(** Usage:
|
||||
[fold_left_scope_lets ~f:(fun acc scope_let scope_let_var -> ...) ~init scope_lets],
|
||||
@ -301,9 +390,9 @@ val fold_left_scope_lets :
|
||||
scope lets to be examined. *)
|
||||
|
||||
val fold_right_scope_lets :
|
||||
f:('expr scope_let -> 'expr Bindlib.var -> 'a -> 'a) ->
|
||||
init:('expr Pos.marked -> 'a) ->
|
||||
'expr scope_body_expr ->
|
||||
f:(('expr1, 'm1) scope_let -> 'expr1 Bindlib.var -> 'a -> 'a) ->
|
||||
init:(('expr1, 'm1) marked -> 'a) ->
|
||||
('expr1, 'm1) scope_body_expr ->
|
||||
'a
|
||||
(** Usage:
|
||||
[fold_right_scope_lets ~f:(fun scope_let scope_let_var acc -> ...) ~init scope_lets],
|
||||
@ -311,14 +400,15 @@ val fold_right_scope_lets :
|
||||
scope lets to be examined (which are before in the program order). *)
|
||||
|
||||
val map_exprs_in_scope_lets :
|
||||
f:('expr Pos.marked -> 'expr Pos.marked Bindlib.box) ->
|
||||
'expr scope_body_expr ->
|
||||
'expr scope_body_expr Bindlib.box
|
||||
f:(('expr1, 'm1) marked -> ('expr2, 'm2) marked Bindlib.box) ->
|
||||
varf:('expr1 Bindlib.var -> 'expr2 Bindlib.var) ->
|
||||
('expr1, 'm1) scope_body_expr ->
|
||||
('expr2, 'm2) scope_body_expr Bindlib.box
|
||||
|
||||
val fold_left_scope_defs :
|
||||
f:('a -> 'expr scope_def -> 'expr Bindlib.var -> 'a) ->
|
||||
f:('a -> ('expr1, 'm1) scope_def -> 'expr1 Bindlib.var -> 'a) ->
|
||||
init:'a ->
|
||||
'expr scopes ->
|
||||
('expr1, 'm1) scopes ->
|
||||
'a
|
||||
(** Usage:
|
||||
[fold_left_scope_defs ~f:(fun acc scope_def scope_var -> ...) ~init scope_def],
|
||||
@ -326,9 +416,9 @@ val fold_left_scope_defs :
|
||||
be examined. *)
|
||||
|
||||
val fold_right_scope_defs :
|
||||
f:('expr scope_def -> 'expr Bindlib.var -> 'a -> 'a) ->
|
||||
f:(('expr1, 'm1) scope_def -> 'expr1 Bindlib.var -> 'a -> 'a) ->
|
||||
init:'a ->
|
||||
'expr scopes ->
|
||||
('expr1, 'm1) scopes ->
|
||||
'a
|
||||
(** Usage:
|
||||
[fold_right_scope_defs ~f:(fun scope_def scope_var acc -> ...) ~init scope_def],
|
||||
@ -336,96 +426,99 @@ val fold_right_scope_defs :
|
||||
be examined (which are before in the program order). *)
|
||||
|
||||
val map_scope_defs :
|
||||
f:('expr scope_def -> 'expr scope_def Bindlib.box) ->
|
||||
'expr scopes ->
|
||||
'expr scopes Bindlib.box
|
||||
f:(('expr, 'm) scope_def -> ('expr, 'm) scope_def Bindlib.box) ->
|
||||
('expr, 'm) scopes ->
|
||||
('expr, 'm) scopes Bindlib.box
|
||||
|
||||
val map_exprs_in_scopes :
|
||||
f:('expr Pos.marked -> 'expr Pos.marked Bindlib.box) ->
|
||||
'expr scopes ->
|
||||
'expr scopes Bindlib.box
|
||||
f:(('expr1, 'm1) marked -> ('expr2, 'm2) marked Bindlib.box) ->
|
||||
varf:('expr1 Bindlib.var -> 'expr2 Bindlib.var) ->
|
||||
('expr1, 'm1) scopes ->
|
||||
('expr2, 'm2) scopes Bindlib.box
|
||||
(** This is the main map visitor for all the expressions inside all the scopes
|
||||
of the program. *)
|
||||
|
||||
(** {2 Variables}*)
|
||||
(** {2 Variables} *)
|
||||
|
||||
type 'm var = 'm expr Bindlib.var
|
||||
|
||||
val new_var : string -> 'm var
|
||||
|
||||
val translate_var : 'm1 var -> 'm2 var
|
||||
(** used to convert between e.g. [untyped expr var] into a [typed expr var] *)
|
||||
|
||||
module Var : sig
|
||||
type t = expr Bindlib.var
|
||||
type t
|
||||
|
||||
val t : 'm expr Bindlib.var -> t
|
||||
(** Hides the marking type parameter annotation behind an existential type so
|
||||
that variables can be stored in non-polymorphic sets and maps *)
|
||||
|
||||
val get : t -> 'm expr Bindlib.var
|
||||
(** Be careful with this, it breaks the type abstraction by casting the
|
||||
existential type annotation. See [!Bindlib.copy_var] for more detail. *)
|
||||
|
||||
val make : string Pos.marked -> t
|
||||
val compare : t -> t -> int
|
||||
val eq : t -> t -> bool
|
||||
end
|
||||
|
||||
module VarMap : Map.S with type key = Var.t
|
||||
module VarSet : Set.S with type elt = Var.t
|
||||
|
||||
val free_vars_expr : expr Pos.marked -> VarSet.t
|
||||
val free_vars_scope_body_expr : expr scope_body_expr -> VarSet.t
|
||||
val free_vars_scope_body : expr scope_body -> VarSet.t
|
||||
val free_vars_scopes : expr scopes -> VarSet.t
|
||||
val free_vars_expr : 'm marked_expr -> VarSet.t
|
||||
val free_vars_scope_body_expr : ('m expr, 'm) scope_body_expr -> VarSet.t
|
||||
val free_vars_scope_body : ('m expr, 'm) scope_body -> VarSet.t
|
||||
val free_vars_scopes : ('m expr, 'm) scopes -> VarSet.t
|
||||
|
||||
type vars = expr Bindlib.mvar
|
||||
(* type vars = expr Bindlib.mvar *)
|
||||
|
||||
(** {2 Boxed term constructors}*)
|
||||
val make_var : ('m var, 'm) marked -> 'm marked_expr Bindlib.box
|
||||
|
||||
val make_var : Var.t Pos.marked -> expr Pos.marked Bindlib.box
|
||||
(** {2 Boxed term constructors} *)
|
||||
|
||||
val make_abs :
|
||||
vars ->
|
||||
expr Pos.marked Bindlib.box ->
|
||||
Pos.t ->
|
||||
typ Pos.marked list ->
|
||||
Pos.t ->
|
||||
expr Pos.marked Bindlib.box
|
||||
type ('e, 'm) make_abs_sig =
|
||||
'e Bindlib.mvar ->
|
||||
('e, 'm) marked Bindlib.box ->
|
||||
marked_typ list ->
|
||||
'm mark ->
|
||||
('e, 'm) marked Bindlib.box
|
||||
|
||||
val make_abs : ('m expr, 'm) make_abs_sig
|
||||
|
||||
val make_app :
|
||||
expr Pos.marked Bindlib.box ->
|
||||
expr Pos.marked Bindlib.box list ->
|
||||
Pos.t ->
|
||||
expr Pos.marked Bindlib.box
|
||||
'm marked_expr Bindlib.box ->
|
||||
'm marked_expr Bindlib.box list ->
|
||||
'm mark ->
|
||||
'm marked_expr Bindlib.box
|
||||
|
||||
val make_let_in :
|
||||
Var.t ->
|
||||
typ Pos.marked ->
|
||||
expr Pos.marked Bindlib.box ->
|
||||
expr Pos.marked Bindlib.box ->
|
||||
type ('expr, 'm) make_let_in_sig =
|
||||
'expr Bindlib.var ->
|
||||
marked_typ ->
|
||||
('expr, 'm) marked Bindlib.box ->
|
||||
('expr, 'm) marked Bindlib.box ->
|
||||
Pos.t ->
|
||||
expr Pos.marked Bindlib.box
|
||||
('expr, 'm) marked Bindlib.box
|
||||
|
||||
val make_let_in : ('m expr, 'm) make_let_in_sig
|
||||
|
||||
(**{2 Other}*)
|
||||
|
||||
val empty_thunked_term : expr Pos.marked
|
||||
val is_value : expr Pos.marked -> bool
|
||||
val empty_thunked_term : 'm mark -> 'm marked_expr
|
||||
val is_value : 'm marked_expr -> bool
|
||||
|
||||
val equal_exprs : expr Pos.marked -> expr Pos.marked -> bool
|
||||
val equal_exprs : 'm marked_expr -> 'm marked_expr -> bool
|
||||
(** Determines if two expressions are equal, omitting their position information *)
|
||||
|
||||
(** {1 AST manipulation helpers}*)
|
||||
|
||||
type 'expr make_let_in_sig =
|
||||
'expr Bindlib.var ->
|
||||
typ Pos.marked ->
|
||||
'expr Pos.marked Bindlib.box ->
|
||||
'expr Pos.marked Bindlib.box ->
|
||||
Pos.t ->
|
||||
'expr Pos.marked Bindlib.box
|
||||
|
||||
type 'expr make_abs_sig =
|
||||
'expr Bindlib.mvar ->
|
||||
'expr Pos.marked Bindlib.box ->
|
||||
Pos.t ->
|
||||
typ Pos.marked list ->
|
||||
Pos.t ->
|
||||
'expr Pos.marked Bindlib.box
|
||||
|
||||
val build_whole_scope_expr :
|
||||
box_expr:'expr box_expr_sig ->
|
||||
make_abs:'expr make_abs_sig ->
|
||||
make_let_in:'expr make_let_in_sig ->
|
||||
box_expr:('expr, 'm) box_expr_sig ->
|
||||
make_abs:('expr, 'm) make_abs_sig ->
|
||||
make_let_in:('expr, 'm) make_let_in_sig ->
|
||||
decl_ctx ->
|
||||
'expr scope_body ->
|
||||
Pos.t ->
|
||||
'expr Pos.marked Bindlib.box
|
||||
('expr, 'm) scope_body ->
|
||||
'm mark ->
|
||||
('expr, 'm) marked Bindlib.box
|
||||
(** Usage: [build_whole_scope_expr ctx body scope_position] where
|
||||
[scope_position] corresponds to the line of the scope declaration for
|
||||
instance. *)
|
||||
@ -435,23 +528,34 @@ type 'expr scope_name_or_var =
|
||||
| ScopeVar of 'expr Bindlib.var
|
||||
|
||||
val unfold_scopes :
|
||||
box_expr:'expr box_expr_sig ->
|
||||
make_abs:'expr make_abs_sig ->
|
||||
make_let_in:'expr make_let_in_sig ->
|
||||
box_expr:('expr, 'm) box_expr_sig ->
|
||||
make_abs:('expr, 'm) make_abs_sig ->
|
||||
make_let_in:('expr, 'm) make_let_in_sig ->
|
||||
decl_ctx ->
|
||||
'expr scopes ->
|
||||
('expr, 'm) scopes ->
|
||||
'm mark ->
|
||||
'expr scope_name_or_var ->
|
||||
'expr Pos.marked Bindlib.box
|
||||
('expr, 'm) marked Bindlib.box
|
||||
|
||||
val build_whole_program_expr :
|
||||
program -> ScopeName.t -> expr Pos.marked Bindlib.box
|
||||
box_expr:('expr, 'm) box_expr_sig ->
|
||||
make_abs:('expr, 'm) make_abs_sig ->
|
||||
make_let_in:('expr, 'm) make_let_in_sig ->
|
||||
('expr, 'm) program_generic ->
|
||||
ScopeName.t ->
|
||||
('expr, 'm) marked Bindlib.box
|
||||
(** Usage: [build_whole_program_expr program main_scope] builds an expression
|
||||
corresponding to the main program and returning the main scope as a
|
||||
function. *)
|
||||
|
||||
val expr_size : expr Pos.marked -> int
|
||||
val expr_size : 'm marked_expr -> int
|
||||
(** Used by the optimizer to know when to stop *)
|
||||
|
||||
val remove_logging_calls : expr Pos.marked -> expr Pos.marked Bindlib.box
|
||||
val remove_logging_calls : 'm marked_expr -> 'm marked_expr Bindlib.box
|
||||
(** Removes all calls to [Log] unary operators in the AST, replacing them by
|
||||
their argument. *)
|
||||
|
||||
val build_scope_typ_from_sig :
|
||||
decl_ctx -> StructName.t -> StructName.t -> Pos.t -> typ Marked.pos
|
||||
(** [build_scope_typ_from_sig ctx in_struct out_struct pos] builds the arrow
|
||||
type for the specified scope *)
|
||||
|
@ -1,7 +1,7 @@
|
||||
(library
|
||||
(name dcalc)
|
||||
(public_name catala.dcalc)
|
||||
(libraries bindlib unionFind utils re camomile runtime)
|
||||
(libraries bindlib unionFind utils re ubase catala.runtime_ocaml)
|
||||
(preprocess
|
||||
(pps visitors.ppx)))
|
||||
|
||||
|
@ -18,11 +18,12 @@
|
||||
|
||||
open Utils
|
||||
module A = Ast
|
||||
module Runtime = Runtime_ocaml.Runtime
|
||||
|
||||
(** {1 Helpers} *)
|
||||
|
||||
let is_empty_error (e : A.expr Pos.marked) : bool =
|
||||
match Pos.unmark e with ELit LEmptyError -> true | _ -> false
|
||||
let is_empty_error (e : 'm A.marked_expr) : bool =
|
||||
match Marked.unmark e with ELit LEmptyError -> true | _ -> false
|
||||
|
||||
let log_indent = ref 0
|
||||
|
||||
@ -30,390 +31,384 @@ let log_indent = ref 0
|
||||
|
||||
let rec evaluate_operator
|
||||
(ctx : Ast.decl_ctx)
|
||||
(op : A.operator Pos.marked)
|
||||
(args : A.expr Pos.marked list) : A.expr Pos.marked =
|
||||
(op : A.operator)
|
||||
(pos : Pos.t)
|
||||
(args : 'm A.marked_expr list) : 'm A.expr =
|
||||
(* Try to apply [div] and if a [Division_by_zero] exceptions is catched, use
|
||||
[op] to raise multispanned errors. *)
|
||||
let apply_div_or_raise_err (div : unit -> A.expr) (op : A.operator Pos.marked)
|
||||
: A.expr =
|
||||
let apply_div_or_raise_err (div : unit -> 'm A.expr) : 'm A.expr =
|
||||
try div ()
|
||||
with Division_by_zero ->
|
||||
Errors.raise_multispanned_error
|
||||
[
|
||||
Some "The division operator:", Pos.get_position op;
|
||||
Some "The null denominator:", Pos.get_position (List.nth args 1);
|
||||
Some "The division operator:", pos;
|
||||
Some "The null denominator:", Ast.pos (List.nth args 1);
|
||||
]
|
||||
"division by zero at runtime"
|
||||
in
|
||||
let get_binop_args_pos (args : (A.expr * Pos.t) list) :
|
||||
(string option * Pos.t) list =
|
||||
[
|
||||
None, Pos.get_position (List.nth args 0);
|
||||
None, Pos.get_position (List.nth args 1);
|
||||
]
|
||||
let get_binop_args_pos = function
|
||||
| (arg0 :: arg1 :: _ : 'm A.marked_expr list) ->
|
||||
[None, Ast.pos arg0; None, Ast.pos arg1]
|
||||
| _ -> assert false
|
||||
in
|
||||
(* Try to apply [cmp] and if a [UncomparableDurations] exceptions is catched,
|
||||
use [args] to raise multispanned errors. *)
|
||||
let apply_cmp_or_raise_err
|
||||
(cmp : unit -> A.expr)
|
||||
(args : (A.expr * Pos.t) list) : A.expr =
|
||||
(cmp : unit -> 'm A.expr)
|
||||
(args : 'm A.marked_expr list) : 'm A.expr =
|
||||
try cmp ()
|
||||
with Runtime.UncomparableDurations ->
|
||||
Errors.raise_multispanned_error (get_binop_args_pos args)
|
||||
"Cannot compare together durations that cannot be converted to a \
|
||||
precise number of days"
|
||||
in
|
||||
Pos.same_pos_as
|
||||
(match Pos.unmark op, List.map Pos.unmark args with
|
||||
| A.Ternop A.Fold, [_f; _init; EArray es] ->
|
||||
Pos.unmark
|
||||
(List.fold_left
|
||||
(fun acc e' ->
|
||||
match op, List.map Marked.unmark args with
|
||||
| A.Ternop A.Fold, [_f; _init; EArray es] ->
|
||||
Marked.unmark
|
||||
(List.fold_left
|
||||
(fun acc e' ->
|
||||
evaluate_expr ctx
|
||||
(Marked.same_mark_as (A.EApp (List.nth args 0, [acc; e'])) e'))
|
||||
(List.nth args 1) es)
|
||||
| A.Binop A.And, [ELit (LBool b1); ELit (LBool b2)] ->
|
||||
A.ELit (LBool (b1 && b2))
|
||||
| A.Binop A.Or, [ELit (LBool b1); ELit (LBool b2)] ->
|
||||
A.ELit (LBool (b1 || b2))
|
||||
| A.Binop A.Xor, [ELit (LBool b1); ELit (LBool b2)] ->
|
||||
A.ELit (LBool (b1 <> b2))
|
||||
| A.Binop (A.Add KInt), [ELit (LInt i1); ELit (LInt i2)] ->
|
||||
A.ELit (LInt Runtime.(i1 +! i2))
|
||||
| A.Binop (A.Sub KInt), [ELit (LInt i1); ELit (LInt i2)] ->
|
||||
A.ELit (LInt Runtime.(i1 -! i2))
|
||||
| A.Binop (A.Mult KInt), [ELit (LInt i1); ELit (LInt i2)] ->
|
||||
A.ELit (LInt Runtime.(i1 *! i2))
|
||||
| A.Binop (A.Div KInt), [ELit (LInt i1); ELit (LInt i2)] ->
|
||||
apply_div_or_raise_err (fun _ -> A.ELit (LInt Runtime.(i1 /! i2)))
|
||||
| A.Binop (A.Add KRat), [ELit (LRat i1); ELit (LRat i2)] ->
|
||||
A.ELit (LRat Runtime.(i1 +& i2))
|
||||
| A.Binop (A.Sub KRat), [ELit (LRat i1); ELit (LRat i2)] ->
|
||||
A.ELit (LRat Runtime.(i1 -& i2))
|
||||
| A.Binop (A.Mult KRat), [ELit (LRat i1); ELit (LRat i2)] ->
|
||||
A.ELit (LRat Runtime.(i1 *& i2))
|
||||
| A.Binop (A.Div KRat), [ELit (LRat i1); ELit (LRat i2)] ->
|
||||
apply_div_or_raise_err (fun _ -> A.ELit (LRat Runtime.(i1 /& i2)))
|
||||
| A.Binop (A.Add KMoney), [ELit (LMoney m1); ELit (LMoney m2)] ->
|
||||
A.ELit (LMoney Runtime.(m1 +$ m2))
|
||||
| A.Binop (A.Sub KMoney), [ELit (LMoney m1); ELit (LMoney m2)] ->
|
||||
A.ELit (LMoney Runtime.(m1 -$ m2))
|
||||
| A.Binop (A.Mult KMoney), [ELit (LMoney m1); ELit (LRat m2)] ->
|
||||
A.ELit (LMoney Runtime.(m1 *$ m2))
|
||||
| A.Binop (A.Div KMoney), [ELit (LMoney m1); ELit (LMoney m2)] ->
|
||||
apply_div_or_raise_err (fun _ -> A.ELit (LRat Runtime.(m1 /$ m2)))
|
||||
| A.Binop (A.Add KDuration), [ELit (LDuration d1); ELit (LDuration d2)] ->
|
||||
A.ELit (LDuration Runtime.(d1 +^ d2))
|
||||
| A.Binop (A.Sub KDuration), [ELit (LDuration d1); ELit (LDuration d2)] ->
|
||||
A.ELit (LDuration Runtime.(d1 -^ d2))
|
||||
| A.Binop (A.Sub KDate), [ELit (LDate d1); ELit (LDate d2)] ->
|
||||
A.ELit (LDuration Runtime.(d1 -@ d2))
|
||||
| A.Binop (A.Add KDate), [ELit (LDate d1); ELit (LDuration d2)] ->
|
||||
A.ELit (LDate Runtime.(d1 +@ d2))
|
||||
| A.Binop (A.Div KDuration), [ELit (LDuration d1); ELit (LDuration d2)] ->
|
||||
apply_div_or_raise_err (fun _ ->
|
||||
try A.ELit (LRat Runtime.(d1 /^ d2))
|
||||
with Runtime.IndivisableDurations ->
|
||||
Errors.raise_multispanned_error (get_binop_args_pos args)
|
||||
"Cannot divide durations that cannot be converted to a precise \
|
||||
number of days")
|
||||
| A.Binop (A.Mult KDuration), [ELit (LDuration d1); ELit (LInt i1)] ->
|
||||
A.ELit (LDuration Runtime.(d1 *^ i1))
|
||||
| A.Binop (A.Lt KInt), [ELit (LInt i1); ELit (LInt i2)] ->
|
||||
A.ELit (LBool Runtime.(i1 <! i2))
|
||||
| A.Binop (A.Lte KInt), [ELit (LInt i1); ELit (LInt i2)] ->
|
||||
A.ELit (LBool Runtime.(i1 <=! i2))
|
||||
| A.Binop (A.Gt KInt), [ELit (LInt i1); ELit (LInt i2)] ->
|
||||
A.ELit (LBool Runtime.(i1 >! i2))
|
||||
| A.Binop (A.Gte KInt), [ELit (LInt i1); ELit (LInt i2)] ->
|
||||
A.ELit (LBool Runtime.(i1 >=! i2))
|
||||
| A.Binop (A.Lt KRat), [ELit (LRat i1); ELit (LRat i2)] ->
|
||||
A.ELit (LBool Runtime.(i1 <& i2))
|
||||
| A.Binop (A.Lte KRat), [ELit (LRat i1); ELit (LRat i2)] ->
|
||||
A.ELit (LBool Runtime.(i1 <=& i2))
|
||||
| A.Binop (A.Gt KRat), [ELit (LRat i1); ELit (LRat i2)] ->
|
||||
A.ELit (LBool Runtime.(i1 >& i2))
|
||||
| A.Binop (A.Gte KRat), [ELit (LRat i1); ELit (LRat i2)] ->
|
||||
A.ELit (LBool Runtime.(i1 >=& i2))
|
||||
| A.Binop (A.Lt KMoney), [ELit (LMoney m1); ELit (LMoney m2)] ->
|
||||
A.ELit (LBool Runtime.(m1 <$ m2))
|
||||
| A.Binop (A.Lte KMoney), [ELit (LMoney m1); ELit (LMoney m2)] ->
|
||||
A.ELit (LBool Runtime.(m1 <=$ m2))
|
||||
| A.Binop (A.Gt KMoney), [ELit (LMoney m1); ELit (LMoney m2)] ->
|
||||
A.ELit (LBool Runtime.(m1 >$ m2))
|
||||
| A.Binop (A.Gte KMoney), [ELit (LMoney m1); ELit (LMoney m2)] ->
|
||||
A.ELit (LBool Runtime.(m1 >=$ m2))
|
||||
| A.Binop (A.Lt KDuration), [ELit (LDuration d1); ELit (LDuration d2)] ->
|
||||
apply_cmp_or_raise_err (fun _ -> A.ELit (LBool Runtime.(d1 <^ d2))) args
|
||||
| A.Binop (A.Lte KDuration), [ELit (LDuration d1); ELit (LDuration d2)] ->
|
||||
apply_cmp_or_raise_err (fun _ -> A.ELit (LBool Runtime.(d1 <=^ d2))) args
|
||||
| A.Binop (A.Gt KDuration), [ELit (LDuration d1); ELit (LDuration d2)] ->
|
||||
apply_cmp_or_raise_err (fun _ -> A.ELit (LBool Runtime.(d1 >^ d2))) args
|
||||
| A.Binop (A.Gte KDuration), [ELit (LDuration d1); ELit (LDuration d2)] ->
|
||||
apply_cmp_or_raise_err (fun _ -> A.ELit (LBool Runtime.(d1 >=^ d2))) args
|
||||
| A.Binop (A.Lt KDate), [ELit (LDate d1); ELit (LDate d2)] ->
|
||||
A.ELit (LBool Runtime.(d1 <@ d2))
|
||||
| A.Binop (A.Lte KDate), [ELit (LDate d1); ELit (LDate d2)] ->
|
||||
A.ELit (LBool Runtime.(d1 <=@ d2))
|
||||
| A.Binop (A.Gt KDate), [ELit (LDate d1); ELit (LDate d2)] ->
|
||||
A.ELit (LBool Runtime.(d1 >@ d2))
|
||||
| A.Binop (A.Gte KDate), [ELit (LDate d1); ELit (LDate d2)] ->
|
||||
A.ELit (LBool Runtime.(d1 >=@ d2))
|
||||
| A.Binop A.Eq, [ELit LUnit; ELit LUnit] -> A.ELit (LBool true)
|
||||
| A.Binop A.Eq, [ELit (LDuration d1); ELit (LDuration d2)] ->
|
||||
A.ELit (LBool Runtime.(d1 =^ d2))
|
||||
| A.Binop A.Eq, [ELit (LDate d1); ELit (LDate d2)] ->
|
||||
A.ELit (LBool Runtime.(d1 =@ d2))
|
||||
| A.Binop A.Eq, [ELit (LMoney m1); ELit (LMoney m2)] ->
|
||||
A.ELit (LBool Runtime.(m1 =$ m2))
|
||||
| A.Binop A.Eq, [ELit (LRat i1); ELit (LRat i2)] ->
|
||||
A.ELit (LBool Runtime.(i1 =& i2))
|
||||
| A.Binop A.Eq, [ELit (LInt i1); ELit (LInt i2)] ->
|
||||
A.ELit (LBool Runtime.(i1 =! i2))
|
||||
| A.Binop A.Eq, [ELit (LBool b1); ELit (LBool b2)] -> A.ELit (LBool (b1 = b2))
|
||||
| A.Binop A.Eq, [EArray es1; EArray es2] ->
|
||||
A.ELit
|
||||
(LBool
|
||||
(try
|
||||
List.for_all2
|
||||
(fun e1 e2 ->
|
||||
match evaluate_operator ctx op pos [e1; e2] with
|
||||
| A.ELit (LBool b) -> b
|
||||
| _ -> assert false
|
||||
(* should not happen *))
|
||||
es1 es2
|
||||
with Invalid_argument _ -> false))
|
||||
| A.Binop A.Eq, [ETuple (es1, s1); ETuple (es2, s2)] ->
|
||||
A.ELit
|
||||
(LBool
|
||||
(try
|
||||
s1 = s2
|
||||
&& List.for_all2
|
||||
(fun e1 e2 ->
|
||||
match evaluate_operator ctx op pos [e1; e2] with
|
||||
| A.ELit (LBool b) -> b
|
||||
| _ -> assert false
|
||||
(* should not happen *))
|
||||
es1 es2
|
||||
with Invalid_argument _ -> false))
|
||||
| A.Binop A.Eq, [EInj (e1, i1, en1, _ts1); EInj (e2, i2, en2, _ts2)] ->
|
||||
A.ELit
|
||||
(LBool
|
||||
(try
|
||||
en1 = en2
|
||||
&& i1 = i2
|
||||
&&
|
||||
match evaluate_operator ctx op pos [e1; e2] with
|
||||
| A.ELit (LBool b) -> b
|
||||
| _ -> assert false
|
||||
(* should not happen *)
|
||||
with Invalid_argument _ -> false))
|
||||
| A.Binop A.Eq, [_; _] ->
|
||||
A.ELit (LBool false) (* comparing anything else return false *)
|
||||
| A.Binop A.Neq, [_; _] -> (
|
||||
match evaluate_operator ctx (A.Binop A.Eq) pos args with
|
||||
| A.ELit (A.LBool b) -> A.ELit (A.LBool (not b))
|
||||
| _ -> assert false (*should not happen *))
|
||||
| A.Binop A.Concat, [A.EArray es1; A.EArray es2] -> A.EArray (es1 @ es2)
|
||||
| A.Binop A.Map, [_; A.EArray es] ->
|
||||
A.EArray
|
||||
(List.map
|
||||
(fun e' ->
|
||||
evaluate_expr ctx
|
||||
(Marked.same_mark_as (A.EApp (List.nth args 0, [e'])) e'))
|
||||
es)
|
||||
| A.Binop A.Filter, [_; A.EArray es] ->
|
||||
A.EArray
|
||||
(List.filter
|
||||
(fun e' ->
|
||||
match
|
||||
evaluate_expr ctx
|
||||
(Pos.same_pos_as (A.EApp (List.nth args 0, [acc; e'])) e'))
|
||||
(List.nth args 1) es)
|
||||
| A.Binop A.And, [ELit (LBool b1); ELit (LBool b2)] ->
|
||||
A.ELit (LBool (b1 && b2))
|
||||
| A.Binop A.Or, [ELit (LBool b1); ELit (LBool b2)] ->
|
||||
A.ELit (LBool (b1 || b2))
|
||||
| A.Binop A.Xor, [ELit (LBool b1); ELit (LBool b2)] ->
|
||||
A.ELit (LBool (b1 <> b2))
|
||||
| A.Binop (A.Add KInt), [ELit (LInt i1); ELit (LInt i2)] ->
|
||||
A.ELit (LInt Runtime.(i1 +! i2))
|
||||
| A.Binop (A.Sub KInt), [ELit (LInt i1); ELit (LInt i2)] ->
|
||||
A.ELit (LInt Runtime.(i1 -! i2))
|
||||
| A.Binop (A.Mult KInt), [ELit (LInt i1); ELit (LInt i2)] ->
|
||||
A.ELit (LInt Runtime.(i1 *! i2))
|
||||
| A.Binop (A.Div KInt), [ELit (LInt i1); ELit (LInt i2)] ->
|
||||
apply_div_or_raise_err (fun _ -> A.ELit (LInt Runtime.(i1 /! i2))) op
|
||||
| A.Binop (A.Add KRat), [ELit (LRat i1); ELit (LRat i2)] ->
|
||||
A.ELit (LRat Runtime.(i1 +& i2))
|
||||
| A.Binop (A.Sub KRat), [ELit (LRat i1); ELit (LRat i2)] ->
|
||||
A.ELit (LRat Runtime.(i1 -& i2))
|
||||
| A.Binop (A.Mult KRat), [ELit (LRat i1); ELit (LRat i2)] ->
|
||||
A.ELit (LRat Runtime.(i1 *& i2))
|
||||
| A.Binop (A.Div KRat), [ELit (LRat i1); ELit (LRat i2)] ->
|
||||
apply_div_or_raise_err (fun _ -> A.ELit (LRat Runtime.(i1 /& i2))) op
|
||||
| A.Binop (A.Add KMoney), [ELit (LMoney m1); ELit (LMoney m2)] ->
|
||||
A.ELit (LMoney Runtime.(m1 +$ m2))
|
||||
| A.Binop (A.Sub KMoney), [ELit (LMoney m1); ELit (LMoney m2)] ->
|
||||
A.ELit (LMoney Runtime.(m1 -$ m2))
|
||||
| A.Binop (A.Mult KMoney), [ELit (LMoney m1); ELit (LRat m2)] ->
|
||||
A.ELit (LMoney Runtime.(m1 *$ m2))
|
||||
| A.Binop (A.Div KMoney), [ELit (LMoney m1); ELit (LMoney m2)] ->
|
||||
apply_div_or_raise_err (fun _ -> A.ELit (LRat Runtime.(m1 /$ m2))) op
|
||||
| A.Binop (A.Add KDuration), [ELit (LDuration d1); ELit (LDuration d2)] ->
|
||||
A.ELit (LDuration Runtime.(d1 +^ d2))
|
||||
| A.Binop (A.Sub KDuration), [ELit (LDuration d1); ELit (LDuration d2)] ->
|
||||
A.ELit (LDuration Runtime.(d1 -^ d2))
|
||||
| A.Binop (A.Sub KDate), [ELit (LDate d1); ELit (LDate d2)] ->
|
||||
A.ELit (LDuration Runtime.(d1 -@ d2))
|
||||
| A.Binop (A.Add KDate), [ELit (LDate d1); ELit (LDuration d2)] ->
|
||||
A.ELit (LDate Runtime.(d1 +@ d2))
|
||||
(* | A.Binop (A.Div KDuration), [ELit (LDuration d1); ELit (LDuration d2)] ->
|
||||
* apply_div_or_raise_err
|
||||
* (fun _ ->
|
||||
* try A.ELit (LRat Runtime.(d1 /^ d2))
|
||||
* with Runtime.IndivisableDurations ->
|
||||
* Errors.raise_multispanned_error (get_binop_args_pos args)
|
||||
* "Cannot divide durations that cannot be converted to a precise \
|
||||
* number of days")
|
||||
* op *)
|
||||
| A.Binop (A.Mult KDuration), [ELit (LDuration d1); ELit (LInt i1)] ->
|
||||
A.ELit (LDuration Runtime.(d1 *^ i1))
|
||||
| A.Binop (A.Lt KInt), [ELit (LInt i1); ELit (LInt i2)] ->
|
||||
A.ELit (LBool Runtime.(i1 <! i2))
|
||||
| A.Binop (A.Lte KInt), [ELit (LInt i1); ELit (LInt i2)] ->
|
||||
A.ELit (LBool Runtime.(i1 <=! i2))
|
||||
| A.Binop (A.Gt KInt), [ELit (LInt i1); ELit (LInt i2)] ->
|
||||
A.ELit (LBool Runtime.(i1 >! i2))
|
||||
| A.Binop (A.Gte KInt), [ELit (LInt i1); ELit (LInt i2)] ->
|
||||
A.ELit (LBool Runtime.(i1 >=! i2))
|
||||
| A.Binop (A.Lt KRat), [ELit (LRat i1); ELit (LRat i2)] ->
|
||||
A.ELit (LBool Runtime.(i1 <& i2))
|
||||
| A.Binop (A.Lte KRat), [ELit (LRat i1); ELit (LRat i2)] ->
|
||||
A.ELit (LBool Runtime.(i1 <=& i2))
|
||||
| A.Binop (A.Gt KRat), [ELit (LRat i1); ELit (LRat i2)] ->
|
||||
A.ELit (LBool Runtime.(i1 >& i2))
|
||||
| A.Binop (A.Gte KRat), [ELit (LRat i1); ELit (LRat i2)] ->
|
||||
A.ELit (LBool Runtime.(i1 >=& i2))
|
||||
| A.Binop (A.Lt KMoney), [ELit (LMoney m1); ELit (LMoney m2)] ->
|
||||
A.ELit (LBool Runtime.(m1 <$ m2))
|
||||
| A.Binop (A.Lte KMoney), [ELit (LMoney m1); ELit (LMoney m2)] ->
|
||||
A.ELit (LBool Runtime.(m1 <=$ m2))
|
||||
| A.Binop (A.Gt KMoney), [ELit (LMoney m1); ELit (LMoney m2)] ->
|
||||
A.ELit (LBool Runtime.(m1 >$ m2))
|
||||
| A.Binop (A.Gte KMoney), [ELit (LMoney m1); ELit (LMoney m2)] ->
|
||||
A.ELit (LBool Runtime.(m1 >=$ m2))
|
||||
| A.Binop (A.Lt KDuration), [ELit (LDuration d1); ELit (LDuration d2)] ->
|
||||
apply_cmp_or_raise_err (fun _ -> A.ELit (LBool Runtime.(d1 <^ d2))) args
|
||||
| A.Binop (A.Lte KDuration), [ELit (LDuration d1); ELit (LDuration d2)] ->
|
||||
apply_cmp_or_raise_err (fun _ -> A.ELit (LBool Runtime.(d1 <=^ d2))) args
|
||||
| A.Binop (A.Gt KDuration), [ELit (LDuration d1); ELit (LDuration d2)] ->
|
||||
apply_cmp_or_raise_err (fun _ -> A.ELit (LBool Runtime.(d1 >^ d2))) args
|
||||
| A.Binop (A.Gte KDuration), [ELit (LDuration d1); ELit (LDuration d2)] ->
|
||||
apply_cmp_or_raise_err (fun _ -> A.ELit (LBool Runtime.(d1 >=^ d2))) args
|
||||
| A.Binop (A.Lt KDate), [ELit (LDate d1); ELit (LDate d2)] ->
|
||||
A.ELit (LBool Runtime.(d1 <@ d2))
|
||||
| A.Binop (A.Lte KDate), [ELit (LDate d1); ELit (LDate d2)] ->
|
||||
A.ELit (LBool Runtime.(d1 <=@ d2))
|
||||
| A.Binop (A.Gt KDate), [ELit (LDate d1); ELit (LDate d2)] ->
|
||||
A.ELit (LBool Runtime.(d1 >@ d2))
|
||||
| A.Binop (A.Gte KDate), [ELit (LDate d1); ELit (LDate d2)] ->
|
||||
A.ELit (LBool Runtime.(d1 >=@ d2))
|
||||
| A.Binop A.Eq, [ELit LUnit; ELit LUnit] -> A.ELit (LBool true)
|
||||
| A.Binop A.Eq, [ELit (LDuration d1); ELit (LDuration d2)] ->
|
||||
A.ELit (LBool Runtime.(d1 =^ d2))
|
||||
| A.Binop A.Eq, [ELit (LDate d1); ELit (LDate d2)] ->
|
||||
A.ELit (LBool Runtime.(d1 =@ d2))
|
||||
| A.Binop A.Eq, [ELit (LMoney m1); ELit (LMoney m2)] ->
|
||||
A.ELit (LBool Runtime.(m1 =$ m2))
|
||||
| A.Binop A.Eq, [ELit (LRat i1); ELit (LRat i2)] ->
|
||||
A.ELit (LBool Runtime.(i1 =& i2))
|
||||
| A.Binop A.Eq, [ELit (LInt i1); ELit (LInt i2)] ->
|
||||
A.ELit (LBool Runtime.(i1 =! i2))
|
||||
| A.Binop A.Eq, [ELit (LBool b1); ELit (LBool b2)] ->
|
||||
A.ELit (LBool (b1 = b2))
|
||||
| A.Binop A.Eq, [EArray es1; EArray es2] ->
|
||||
A.ELit
|
||||
(LBool
|
||||
(try
|
||||
List.for_all2
|
||||
(fun e1 e2 ->
|
||||
match Pos.unmark (evaluate_operator ctx op [e1; e2]) with
|
||||
| A.ELit (LBool b) -> b
|
||||
| _ -> assert false
|
||||
(* should not happen *))
|
||||
es1 es2
|
||||
with Invalid_argument _ -> false))
|
||||
| A.Binop A.Eq, [ETuple (es1, s1); ETuple (es2, s2)] ->
|
||||
A.ELit
|
||||
(LBool
|
||||
(try
|
||||
s1 = s2
|
||||
&& List.for_all2
|
||||
(fun e1 e2 ->
|
||||
match Pos.unmark (evaluate_operator ctx op [e1; e2]) with
|
||||
| A.ELit (LBool b) -> b
|
||||
| _ -> assert false
|
||||
(* should not happen *))
|
||||
es1 es2
|
||||
with Invalid_argument _ -> false))
|
||||
| A.Binop A.Eq, [EInj (e1, i1, en1, _ts1); EInj (e2, i2, en2, _ts2)] ->
|
||||
A.ELit
|
||||
(LBool
|
||||
(try
|
||||
en1 = en2 && i1 = i2
|
||||
&&
|
||||
match Pos.unmark (evaluate_operator ctx op [e1; e2]) with
|
||||
| A.ELit (LBool b) -> b
|
||||
| _ -> assert false
|
||||
(* should not happen *)
|
||||
with Invalid_argument _ -> false))
|
||||
| A.Binop A.Eq, [_; _] ->
|
||||
A.ELit (LBool false) (* comparing anything else return false *)
|
||||
| A.Binop A.Neq, [_; _] -> (
|
||||
match
|
||||
Pos.unmark
|
||||
(evaluate_operator ctx (Pos.same_pos_as (A.Binop A.Eq) op) args)
|
||||
with
|
||||
| A.ELit (A.LBool b) -> A.ELit (A.LBool (not b))
|
||||
| _ -> assert false (*should not happen *))
|
||||
| A.Binop A.Concat, [A.EArray es1; A.EArray es2] -> A.EArray (es1 @ es2)
|
||||
| A.Binop A.Map, [_; A.EArray es] ->
|
||||
A.EArray
|
||||
(List.map
|
||||
(fun e' ->
|
||||
evaluate_expr ctx
|
||||
(Pos.same_pos_as (A.EApp (List.nth args 0, [e'])) e'))
|
||||
es)
|
||||
| A.Binop A.Filter, [_; A.EArray es] ->
|
||||
A.EArray
|
||||
(List.filter
|
||||
(fun e' ->
|
||||
match
|
||||
evaluate_expr ctx
|
||||
(Pos.same_pos_as (A.EApp (List.nth args 0, [e'])) e')
|
||||
with
|
||||
| A.ELit (A.LBool b), _ -> b
|
||||
| _ ->
|
||||
Errors.raise_spanned_error
|
||||
(Pos.get_position (List.nth args 0))
|
||||
"This predicate evaluated to something else than a boolean \
|
||||
(should not happen if the term was well-typed)")
|
||||
es)
|
||||
| A.Binop _, ([ELit LEmptyError; _] | [_; ELit LEmptyError]) ->
|
||||
A.ELit LEmptyError
|
||||
| A.Unop (A.Minus KInt), [ELit (LInt i)] ->
|
||||
A.ELit (LInt Runtime.(integer_of_int 0 -! i))
|
||||
| A.Unop (A.Minus KRat), [ELit (LRat i)] ->
|
||||
A.ELit (LRat Runtime.(decimal_of_string "0" -& i))
|
||||
| A.Unop (A.Minus KMoney), [ELit (LMoney i)] ->
|
||||
A.ELit (LMoney Runtime.(money_of_units_int 0 -$ i))
|
||||
| A.Unop (A.Minus KDuration), [ELit (LDuration i)] ->
|
||||
A.ELit (LDuration Runtime.(~-^i))
|
||||
| A.Unop A.Not, [ELit (LBool b)] -> A.ELit (LBool (not b))
|
||||
| A.Unop A.Length, [EArray es] ->
|
||||
A.ELit (LInt (Runtime.integer_of_int (List.length es)))
|
||||
| A.Unop A.GetDay, [ELit (LDate d)] ->
|
||||
A.ELit (LInt Runtime.(day_of_month_of_date d))
|
||||
| A.Unop A.GetMonth, [ELit (LDate d)] ->
|
||||
A.ELit (LInt Runtime.(month_number_of_date d))
|
||||
| A.Unop A.GetYear, [ELit (LDate d)] ->
|
||||
A.ELit (LInt Runtime.(year_of_date d))
|
||||
| A.Unop A.IntToRat, [ELit (LInt i)] ->
|
||||
A.ELit (LRat Runtime.(decimal_of_integer i))
|
||||
| A.Unop A.RoundMoney, [ELit (LMoney m)] ->
|
||||
A.ELit (LMoney Runtime.(money_round m))
|
||||
| A.Unop A.RoundDecimal, [ELit (LRat m)] ->
|
||||
A.ELit (LRat Runtime.(decimal_round m))
|
||||
| A.Unop (A.Log (entry, infos)), [e'] ->
|
||||
if !Cli.trace_flag then (
|
||||
match entry with
|
||||
| VarDef _ ->
|
||||
(* TODO: this usage of Format is broken, Formatting requires that all
|
||||
is formatted in one pass, without going through intermediate
|
||||
"%s" *)
|
||||
Cli.log_format "%*s%a %a: %s" (!log_indent * 2) ""
|
||||
Print.format_log_entry entry Print.format_uid_list infos
|
||||
(match e' with
|
||||
(* | Ast.EAbs _ -> Cli.with_style [ ANSITerminal.green ]
|
||||
"<function>" *)
|
||||
| _ ->
|
||||
let expr_str =
|
||||
Format.asprintf "%a"
|
||||
(Print.format_expr ctx ~debug:false)
|
||||
(e', Pos.no_pos)
|
||||
in
|
||||
let expr_str =
|
||||
Re.Pcre.substitute ~rex:(Re.Pcre.regexp "\n\\s*")
|
||||
~subst:(fun _ -> " ")
|
||||
expr_str
|
||||
in
|
||||
Cli.with_style [ANSITerminal.green] "%s" expr_str)
|
||||
| PosRecordIfTrueBool -> (
|
||||
let pos = Pos.get_position op in
|
||||
match pos <> Pos.no_pos, e' with
|
||||
| true, ELit (LBool true) ->
|
||||
Cli.log_format "%*s%a%s:\n%s" (!log_indent * 2) ""
|
||||
Print.format_log_entry entry
|
||||
(Cli.with_style [ANSITerminal.green] "Definition applied")
|
||||
(Cli.add_prefix_to_each_line (Pos.retrieve_loc_text pos) (fun _ ->
|
||||
Format.asprintf "%*s" (!log_indent * 2) ""))
|
||||
| _ -> ())
|
||||
| BeginCall ->
|
||||
Cli.log_format "%*s%a %a" (!log_indent * 2) "" Print.format_log_entry
|
||||
entry Print.format_uid_list infos;
|
||||
log_indent := !log_indent + 1
|
||||
| EndCall ->
|
||||
log_indent := !log_indent - 1;
|
||||
Cli.log_format "%*s%a %a" (!log_indent * 2) "" Print.format_log_entry
|
||||
entry Print.format_uid_list infos)
|
||||
else ();
|
||||
e'
|
||||
| A.Unop _, [ELit LEmptyError] -> A.ELit LEmptyError
|
||||
| _ ->
|
||||
Errors.raise_multispanned_error
|
||||
([Some "Operator:", Pos.get_position op]
|
||||
@ List.mapi
|
||||
(fun i arg ->
|
||||
( Some
|
||||
(Format.asprintf "Argument n°%d, value %a" (i + 1)
|
||||
(Print.format_expr ctx ~debug:true)
|
||||
arg),
|
||||
Pos.get_position arg ))
|
||||
args)
|
||||
"Operator applied to the wrong arguments\n\
|
||||
(should not happen if the term was well-typed)")
|
||||
op
|
||||
(Marked.same_mark_as (A.EApp (List.nth args 0, [e'])) e')
|
||||
with
|
||||
| A.ELit (A.LBool b), _ -> b
|
||||
| _ ->
|
||||
Errors.raise_spanned_error
|
||||
(A.pos (List.nth args 0))
|
||||
"This predicate evaluated to something else than a boolean \
|
||||
(should not happen if the term was well-typed)")
|
||||
es)
|
||||
| A.Binop _, ([ELit LEmptyError; _] | [_; ELit LEmptyError]) ->
|
||||
A.ELit LEmptyError
|
||||
| A.Unop (A.Minus KInt), [ELit (LInt i)] ->
|
||||
A.ELit (LInt Runtime.(integer_of_int 0 -! i))
|
||||
| A.Unop (A.Minus KRat), [ELit (LRat i)] ->
|
||||
A.ELit (LRat Runtime.(decimal_of_string "0" -& i))
|
||||
| A.Unop (A.Minus KMoney), [ELit (LMoney i)] ->
|
||||
A.ELit (LMoney Runtime.(money_of_units_int 0 -$ i))
|
||||
| A.Unop (A.Minus KDuration), [ELit (LDuration i)] ->
|
||||
A.ELit (LDuration Runtime.(~-^i))
|
||||
| A.Unop A.Not, [ELit (LBool b)] -> A.ELit (LBool (not b))
|
||||
| A.Unop A.Length, [EArray es] ->
|
||||
A.ELit (LInt (Runtime.integer_of_int (List.length es)))
|
||||
| A.Unop A.GetDay, [ELit (LDate d)] ->
|
||||
A.ELit (LInt Runtime.(day_of_month_of_date d))
|
||||
| A.Unop A.GetMonth, [ELit (LDate d)] ->
|
||||
A.ELit (LInt Runtime.(month_number_of_date d))
|
||||
| A.Unop A.GetYear, [ELit (LDate d)] -> A.ELit (LInt Runtime.(year_of_date d))
|
||||
| A.Unop A.FirstDayOfMonth, [ELit (LDate d)] ->
|
||||
A.ELit (LDate Runtime.(first_day_of_month d))
|
||||
| A.Unop A.LastDayOfMonth, [ELit (LDate d)] ->
|
||||
A.ELit (LDate Runtime.(first_day_of_month d))
|
||||
| A.Unop A.IntToRat, [ELit (LInt i)] ->
|
||||
A.ELit (LRat Runtime.(decimal_of_integer i))
|
||||
| A.Unop A.MoneyToRat, [ELit (LMoney i)] ->
|
||||
A.ELit (LRat Runtime.(decimal_of_money i))
|
||||
| A.Unop A.RatToMoney, [ELit (LRat i)] ->
|
||||
A.ELit (LMoney Runtime.(money_of_decimal i))
|
||||
| A.Unop A.RoundMoney, [ELit (LMoney m)] ->
|
||||
A.ELit (LMoney Runtime.(money_round m))
|
||||
| A.Unop A.RoundDecimal, [ELit (LRat m)] ->
|
||||
A.ELit (LRat Runtime.(decimal_round m))
|
||||
| A.Unop (A.Log (entry, infos)), [e'] ->
|
||||
if !Cli.trace_flag then (
|
||||
match entry with
|
||||
| VarDef _ ->
|
||||
(* TODO: this usage of Format is broken, Formatting requires that all is
|
||||
formatted in one pass, without going through intermediate "%s" *)
|
||||
Cli.log_format "%*s%a %a: %s" (!log_indent * 2) ""
|
||||
Print.format_log_entry entry Print.format_uid_list infos
|
||||
(match e' with
|
||||
(* | Ast.EAbs _ -> Cli.with_style [ ANSITerminal.green ]
|
||||
"<function>" *)
|
||||
| _ ->
|
||||
let expr_str =
|
||||
Format.asprintf "%a"
|
||||
(Print.format_expr ctx ~debug:false)
|
||||
(List.hd args)
|
||||
in
|
||||
let expr_str =
|
||||
Re.Pcre.substitute ~rex:(Re.Pcre.regexp "\n\\s*")
|
||||
~subst:(fun _ -> " ")
|
||||
expr_str
|
||||
in
|
||||
Cli.with_style [ANSITerminal.green] "%s" expr_str)
|
||||
| PosRecordIfTrueBool -> (
|
||||
match pos <> Pos.no_pos, e' with
|
||||
| true, ELit (LBool true) ->
|
||||
Cli.log_format "%*s%a%s:\n%s" (!log_indent * 2) ""
|
||||
Print.format_log_entry entry
|
||||
(Cli.with_style [ANSITerminal.green] "Definition applied")
|
||||
(Cli.add_prefix_to_each_line (Pos.retrieve_loc_text pos) (fun _ ->
|
||||
Format.asprintf "%*s" (!log_indent * 2) ""))
|
||||
| _ -> ())
|
||||
| BeginCall ->
|
||||
Cli.log_format "%*s%a %a" (!log_indent * 2) "" Print.format_log_entry
|
||||
entry Print.format_uid_list infos;
|
||||
log_indent := !log_indent + 1
|
||||
| EndCall ->
|
||||
log_indent := !log_indent - 1;
|
||||
Cli.log_format "%*s%a %a" (!log_indent * 2) "" Print.format_log_entry
|
||||
entry Print.format_uid_list infos)
|
||||
else ();
|
||||
e'
|
||||
| A.Unop _, [ELit LEmptyError] -> A.ELit LEmptyError
|
||||
| _ ->
|
||||
Errors.raise_multispanned_error
|
||||
([Some "Operator:", pos]
|
||||
@ List.mapi
|
||||
(fun i arg ->
|
||||
( Some
|
||||
(Format.asprintf "Argument n°%d, value %a" (i + 1)
|
||||
(Print.format_expr ctx ~debug:true)
|
||||
arg),
|
||||
A.pos arg ))
|
||||
args)
|
||||
"Operator applied to the wrong arguments\n\
|
||||
(should not happen if the term was well-typed)"
|
||||
>>>>>>> master
|
||||
|
||||
and evaluate_expr (ctx : Ast.decl_ctx) (e : A.expr Pos.marked) :
|
||||
A.expr Pos.marked =
|
||||
match Pos.unmark e with
|
||||
and evaluate_expr (ctx : Ast.decl_ctx) (e : 'm A.marked_expr) : 'm A.marked_expr
|
||||
=
|
||||
match Marked.unmark e with
|
||||
| EVar _ ->
|
||||
Errors.raise_spanned_error (Pos.get_position e)
|
||||
Errors.raise_spanned_error (A.pos e)
|
||||
"free variable found at evaluation (should not happen if term was \
|
||||
well-typed"
|
||||
| EApp (e1, args) -> (
|
||||
let e1 = evaluate_expr ctx e1 in
|
||||
let args = List.map (evaluate_expr ctx) args in
|
||||
match Pos.unmark e1 with
|
||||
| EAbs ((binder, _), _) ->
|
||||
match Marked.unmark e1 with
|
||||
| EAbs (binder, _) ->
|
||||
if Bindlib.mbinder_arity binder = List.length args then
|
||||
evaluate_expr ctx
|
||||
(Bindlib.msubst binder (Array.of_list (List.map Pos.unmark args)))
|
||||
(Bindlib.msubst binder (Array.of_list (List.map Marked.unmark args)))
|
||||
else
|
||||
Errors.raise_spanned_error (Pos.get_position e)
|
||||
Errors.raise_spanned_error (A.pos e)
|
||||
"wrong function call, expected %d arguments, got %d"
|
||||
(Bindlib.mbinder_arity binder)
|
||||
(List.length args)
|
||||
| EOp op ->
|
||||
Pos.same_pos_as
|
||||
(Pos.unmark (evaluate_operator ctx (Pos.same_pos_as op e1) args))
|
||||
e
|
||||
| ELit LEmptyError -> Pos.same_pos_as (A.ELit LEmptyError) e
|
||||
| EOp op -> Marked.same_mark_as (evaluate_operator ctx op (A.pos e) args) e
|
||||
| ELit LEmptyError -> Marked.same_mark_as (A.ELit LEmptyError) e
|
||||
| _ ->
|
||||
Errors.raise_spanned_error (Pos.get_position e)
|
||||
Errors.raise_spanned_error (A.pos e)
|
||||
"function has not been reduced to a lambda at evaluation (should not \
|
||||
happen if the term was well-typed")
|
||||
| EAbs _ | ELit _ | EOp _ -> e (* these are values *)
|
||||
| ETuple (es, s) ->
|
||||
let new_es = List.map (evaluate_expr ctx) es in
|
||||
if List.exists is_empty_error new_es then
|
||||
Pos.same_pos_as (A.ELit LEmptyError) e
|
||||
else Pos.same_pos_as (A.ETuple (new_es, s)) e
|
||||
Marked.same_mark_as (A.ELit LEmptyError) e
|
||||
else Marked.same_mark_as (A.ETuple (new_es, s)) e
|
||||
| ETupleAccess (e1, n, s, _) -> (
|
||||
let e1 = evaluate_expr ctx e1 in
|
||||
match Pos.unmark e1 with
|
||||
match Marked.unmark e1 with
|
||||
| ETuple (es, s') -> (
|
||||
(match s, s' with
|
||||
| None, None -> ()
|
||||
| Some s, Some s' when s = s' -> ()
|
||||
| _ ->
|
||||
Errors.raise_multispanned_error
|
||||
[None, Pos.get_position e; None, Pos.get_position e1]
|
||||
[None, A.pos e; None, A.pos e1]
|
||||
"Error during tuple access: not the same structs (should not happen \
|
||||
if the term was well-typed)");
|
||||
match List.nth_opt es n with
|
||||
| Some e' -> e'
|
||||
| None ->
|
||||
Errors.raise_spanned_error (Pos.get_position e1)
|
||||
Errors.raise_spanned_error (A.pos e1)
|
||||
"The tuple has %d components but the %i-th element was requested \
|
||||
(should not happen if the term was well-type)"
|
||||
(List.length es) n)
|
||||
| ELit LEmptyError -> Pos.same_pos_as (A.ELit LEmptyError) e
|
||||
| ELit LEmptyError -> Marked.same_mark_as (A.ELit LEmptyError) e
|
||||
| _ ->
|
||||
Errors.raise_spanned_error (Pos.get_position e1)
|
||||
Errors.raise_spanned_error (A.pos e1)
|
||||
"The expression %a should be a tuple with %d components but is not \
|
||||
(should not happen if the term was well-typed)"
|
||||
(Print.format_expr ctx ~debug:true)
|
||||
e n)
|
||||
| EInj (e1, n, en, ts) ->
|
||||
let e1' = evaluate_expr ctx e1 in
|
||||
if is_empty_error e1' then Pos.same_pos_as (A.ELit LEmptyError) e
|
||||
else Pos.same_pos_as (A.EInj (e1', n, en, ts)) e
|
||||
if is_empty_error e1' then Marked.same_mark_as (A.ELit LEmptyError) e
|
||||
else Marked.same_mark_as (A.EInj (e1', n, en, ts)) e
|
||||
| EMatch (e1, es, e_name) -> (
|
||||
let e1 = evaluate_expr ctx e1 in
|
||||
match Pos.unmark e1 with
|
||||
match Marked.unmark e1 with
|
||||
| A.EInj (e1, n, e_name', _) ->
|
||||
if e_name <> e_name' then
|
||||
Errors.raise_multispanned_error
|
||||
[None, Pos.get_position e; None, Pos.get_position e1]
|
||||
[None, A.pos e; None, A.pos e1]
|
||||
"Error during match: two different enums found (should not happend \
|
||||
if the term was well-typed)";
|
||||
let es_n =
|
||||
match List.nth_opt es n with
|
||||
| Some es_n -> es_n
|
||||
| None ->
|
||||
Errors.raise_spanned_error (Pos.get_position e)
|
||||
Errors.raise_spanned_error (A.pos e)
|
||||
"sum type index error (should not happend if the term was \
|
||||
well-typed)"
|
||||
in
|
||||
let new_e = Pos.same_pos_as (A.EApp (es_n, [e1])) e in
|
||||
let new_e = Marked.same_mark_as (A.EApp (es_n, [e1])) e in
|
||||
evaluate_expr ctx new_e
|
||||
| A.ELit A.LEmptyError -> Pos.same_pos_as (A.ELit A.LEmptyError) e
|
||||
| A.ELit A.LEmptyError -> Marked.same_mark_as (A.ELit A.LEmptyError) e
|
||||
| _ ->
|
||||
Errors.raise_spanned_error (Pos.get_position e1)
|
||||
Errors.raise_spanned_error (A.pos e1)
|
||||
"Expected a term having a sum type as an argument to a match (should \
|
||||
not happend if the term was well-typed")
|
||||
| EDefault (exceptions, just, cons) -> (
|
||||
@ -422,12 +417,12 @@ and evaluate_expr (ctx : Ast.decl_ctx) (e : A.expr Pos.marked) :
|
||||
match List.length exceptions - empty_count with
|
||||
| 0 -> (
|
||||
let just = evaluate_expr ctx just in
|
||||
match Pos.unmark just with
|
||||
| ELit LEmptyError -> Pos.same_pos_as (A.ELit LEmptyError) e
|
||||
match Marked.unmark just with
|
||||
| ELit LEmptyError -> Marked.same_mark_as (A.ELit LEmptyError) e
|
||||
| ELit (LBool true) -> evaluate_expr ctx cons
|
||||
| ELit (LBool false) -> Pos.same_pos_as (A.ELit LEmptyError) e
|
||||
| ELit (LBool false) -> Marked.same_mark_as (A.ELit LEmptyError) e
|
||||
| _ ->
|
||||
Errors.raise_spanned_error (Pos.get_position e)
|
||||
Errors.raise_spanned_error (A.pos e)
|
||||
"Default justification has not been reduced to a boolean at \
|
||||
evaluation (should not happen if the term was well-typed")
|
||||
| 1 -> List.find (fun sub -> not (is_empty_error sub)) exceptions
|
||||
@ -435,80 +430,125 @@ and evaluate_expr (ctx : Ast.decl_ctx) (e : A.expr Pos.marked) :
|
||||
Errors.raise_multispanned_error
|
||||
(List.map
|
||||
(fun except ->
|
||||
( Some "This consequence has a valid justification:",
|
||||
Pos.get_position except ))
|
||||
Some "This consequence has a valid justification:", A.pos except)
|
||||
(List.filter (fun sub -> not (is_empty_error sub)) exceptions))
|
||||
"There is a conflict between multiple valid consequences for assigning \
|
||||
the same variable.")
|
||||
| EIfThenElse (cond, et, ef) -> (
|
||||
match Pos.unmark (evaluate_expr ctx cond) with
|
||||
match Marked.unmark (evaluate_expr ctx cond) with
|
||||
| ELit (LBool true) -> evaluate_expr ctx et
|
||||
| ELit (LBool false) -> evaluate_expr ctx ef
|
||||
| ELit LEmptyError -> Pos.same_pos_as (A.ELit LEmptyError) e
|
||||
| ELit LEmptyError -> Marked.same_mark_as (A.ELit LEmptyError) e
|
||||
| _ ->
|
||||
Errors.raise_spanned_error (Pos.get_position cond)
|
||||
Errors.raise_spanned_error (A.pos cond)
|
||||
"Expected a boolean literal for the result of this condition (should \
|
||||
not happen if the term was well-typed)")
|
||||
| EArray es ->
|
||||
let new_es = List.map (evaluate_expr ctx) es in
|
||||
if List.exists is_empty_error new_es then
|
||||
Pos.same_pos_as (A.ELit LEmptyError) e
|
||||
else Pos.same_pos_as (A.EArray new_es) e
|
||||
Marked.same_mark_as (A.ELit LEmptyError) e
|
||||
else Marked.same_mark_as (A.EArray new_es) e
|
||||
| ErrorOnEmpty e' ->
|
||||
let e' = evaluate_expr ctx e' in
|
||||
if Pos.unmark e' = A.ELit LEmptyError then
|
||||
Errors.raise_spanned_error (Pos.get_position e')
|
||||
if Marked.unmark e' = A.ELit LEmptyError then
|
||||
Errors.raise_spanned_error (A.pos e')
|
||||
"This variable evaluated to an empty term (no rule that defined it \
|
||||
applied in this situation)"
|
||||
else e'
|
||||
| EAssert e' -> (
|
||||
match Pos.unmark (evaluate_expr ctx e') with
|
||||
| ELit (LBool true) -> Pos.same_pos_as (Ast.ELit LUnit) e'
|
||||
match Marked.unmark (evaluate_expr ctx e') with
|
||||
| ELit (LBool true) -> Marked.same_mark_as (Ast.ELit LUnit) e'
|
||||
| ELit (LBool false) -> (
|
||||
match Pos.unmark e' with
|
||||
match Marked.unmark e' with
|
||||
| Ast.ErrorOnEmpty
|
||||
( EApp
|
||||
( (Ast.EOp (Binop op), pos_op),
|
||||
( (Ast.EOp (Binop op), _),
|
||||
[((ELit _, _) as e1); ((ELit _, _) as e2)] ),
|
||||
_ )
|
||||
| EApp
|
||||
( (Ast.EOp (Ast.Unop (Ast.Log _)), _),
|
||||
[
|
||||
( Ast.EApp
|
||||
( (Ast.EOp (Binop op), pos_op),
|
||||
( (Ast.EOp (Binop op), _),
|
||||
[((ELit _, _) as e1); ((ELit _, _) as e2)] ),
|
||||
_ );
|
||||
] )
|
||||
| EApp
|
||||
( (Ast.EOp (Binop op), pos_op),
|
||||
[((ELit _, _) as e1); ((ELit _, _) as e2)] ) ->
|
||||
Errors.raise_spanned_error (Pos.get_position e')
|
||||
"Assertion failed: %a %a %a"
|
||||
((Ast.EOp (Binop op), _), [((ELit _, _) as e1); ((ELit _, _) as e2)])
|
||||
->
|
||||
Errors.raise_spanned_error (A.pos e') "Assertion failed: %a %a %a"
|
||||
(Print.format_expr ctx ~debug:false)
|
||||
e1 Print.format_binop (op, pos_op)
|
||||
e1 Print.format_binop op
|
||||
(Print.format_expr ctx ~debug:false)
|
||||
e2
|
||||
| _ ->
|
||||
Cli.debug_format "%a" (Print.format_expr ctx) e';
|
||||
Errors.raise_spanned_error (Pos.get_position e') "Assertion failed")
|
||||
| ELit LEmptyError -> Pos.same_pos_as (A.ELit LEmptyError) e
|
||||
Errors.raise_spanned_error (A.pos e') "Assertion failed")
|
||||
| ELit LEmptyError -> Marked.same_mark_as (A.ELit LEmptyError) e
|
||||
| _ ->
|
||||
Errors.raise_spanned_error (Pos.get_position e')
|
||||
Errors.raise_spanned_error (A.pos e')
|
||||
"Expected a boolean literal for the result of this assertion (should \
|
||||
not happen if the term was well-typed)")
|
||||
|
||||
(** {1 API} *)
|
||||
|
||||
let interpret_program (ctx : Ast.decl_ctx) (e : Ast.expr Pos.marked) :
|
||||
(Uid.MarkedString.info * Ast.expr Pos.marked) list =
|
||||
match Pos.unmark (evaluate_expr ctx e) with
|
||||
| Ast.EAbs (_, [(Ast.TTuple (taus, Some s_in), _)]) -> (
|
||||
let application_term = List.map (fun _ -> Ast.empty_thunked_term) taus in
|
||||
let to_interpret =
|
||||
( Ast.EApp (e, [Ast.ETuple (application_term, Some s_in), Pos.no_pos]),
|
||||
Pos.no_pos )
|
||||
let interpret_program :
|
||||
'm.
|
||||
Ast.decl_ctx ->
|
||||
'm Ast.marked_expr ->
|
||||
(Uid.MarkedString.info * 'm Ast.marked_expr) list =
|
||||
fun (ctx : Ast.decl_ctx) (e : 'm Ast.marked_expr) :
|
||||
(Uid.MarkedString.info * 'm Ast.marked_expr) list ->
|
||||
match evaluate_expr ctx e with
|
||||
| Ast.EAbs (_, [((Ast.TTuple (taus, Some s_in), _) as targs)]), mark_e ->
|
||||
begin
|
||||
(* At this point, the interpreter seeks to execute the scope but does not
|
||||
have a way to retrieve input values from the command line. [taus] contain
|
||||
the types of the scope arguments. For [context] arguments, we cann
|
||||
provide an empty thunked term. But for [input] arguments of another type,
|
||||
we cannot provide anything so we have to fail. *)
|
||||
let application_term =
|
||||
List.map
|
||||
(fun ty ->
|
||||
match Marked.unmark ty with
|
||||
| A.TArrow ((A.TLit A.TUnit, _), ty_in) ->
|
||||
Ast.empty_thunked_term
|
||||
(A.map_mark (fun pos -> pos) (fun _ -> ty_in) mark_e)
|
||||
| _ ->
|
||||
Errors.raise_spanned_error (Marked.get_mark ty)
|
||||
"This scope needs input arguments to be executed. But the Catala \
|
||||
built-in interpreter does not have a way to retrieve input \
|
||||
values from the command line, so it cannot execute this scope. \
|
||||
Please create another scope thatprovide the input arguments to \
|
||||
this one and execute it instead. ")
|
||||
taus
|
||||
in
|
||||
match Pos.unmark (evaluate_expr ctx to_interpret) with
|
||||
let to_interpret =
|
||||
( Ast.EApp
|
||||
( e,
|
||||
[
|
||||
( Ast.ETuple (application_term, Some s_in),
|
||||
let pos =
|
||||
match application_term with
|
||||
| a :: _ -> A.pos a
|
||||
| [] -> Pos.no_pos
|
||||
in
|
||||
A.map_mark (fun _ -> pos) (fun _ -> targs) mark_e );
|
||||
] ),
|
||||
A.map_mark
|
||||
(fun pos -> pos)
|
||||
(fun ty ->
|
||||
match application_term, ty with
|
||||
| [], t_out -> t_out
|
||||
| _ :: _, (A.TArrow (_, t_out), _) -> t_out
|
||||
| _ :: _, (_, bad_pos) ->
|
||||
Errors.raise_spanned_error bad_pos
|
||||
"@[<hv 2>(bug) Result of interpretation doesn't have the \
|
||||
expected type:@ @[%a@]@]"
|
||||
(Print.format_typ ctx) (fst @@ ty))
|
||||
mark_e )
|
||||
in
|
||||
match Marked.unmark (evaluate_expr ctx to_interpret) with
|
||||
| Ast.ETuple (args, Some s_out) ->
|
||||
let s_out_fields =
|
||||
List.map
|
||||
@ -517,10 +557,11 @@ let interpret_program (ctx : Ast.decl_ctx) (e : Ast.expr Pos.marked) :
|
||||
in
|
||||
List.map2 (fun arg var -> var, arg) args s_out_fields
|
||||
| _ ->
|
||||
Errors.raise_spanned_error (Pos.get_position e)
|
||||
Errors.raise_spanned_error (A.pos e)
|
||||
"The interpretation of a program should always yield a struct \
|
||||
corresponding to the scope variables")
|
||||
corresponding to the scope variables"
|
||||
end
|
||||
| _ ->
|
||||
Errors.raise_spanned_error (Pos.get_position e)
|
||||
Errors.raise_spanned_error (A.pos e)
|
||||
"The interpreter can only interpret terms starting with functions having \
|
||||
thunked arguments"
|
||||
|
@ -18,13 +18,13 @@
|
||||
|
||||
open Utils
|
||||
|
||||
val evaluate_expr : Ast.decl_ctx -> Ast.expr Pos.marked -> Ast.expr Pos.marked
|
||||
val evaluate_expr : Ast.decl_ctx -> 'm Ast.marked_expr -> 'm Ast.marked_expr
|
||||
(** Evaluates an expression according to the semantics of the default calculus. *)
|
||||
|
||||
val interpret_program :
|
||||
Ast.decl_ctx ->
|
||||
Ast.expr Pos.marked ->
|
||||
(Uid.MarkedString.info * Ast.expr Pos.marked) list
|
||||
'm Ast.marked_expr ->
|
||||
(Uid.MarkedString.info * 'm Ast.marked_expr) list
|
||||
(** Interprets a program. This function expects an expression typed as a
|
||||
function whose argument are all thunked. The function is executed by
|
||||
providing for each argument a thunked empty default. Returns a list of all
|
||||
|
@ -18,15 +18,15 @@ open Utils
|
||||
open Ast
|
||||
|
||||
type partial_evaluation_ctx = {
|
||||
var_values : expr Pos.marked Ast.VarMap.t;
|
||||
var_values : typed marked_expr Ast.VarMap.t;
|
||||
decl_ctx : decl_ctx;
|
||||
}
|
||||
|
||||
let rec partial_evaluation (ctx : partial_evaluation_ctx) (e : expr Pos.marked)
|
||||
: expr Pos.marked Bindlib.box =
|
||||
let pos = Pos.get_position e in
|
||||
let rec partial_evaluation (ctx : partial_evaluation_ctx) (e : 'm marked_expr) :
|
||||
'm marked_expr Bindlib.box =
|
||||
let pos = Marked.get_mark e in
|
||||
let rec_helper = partial_evaluation ctx in
|
||||
match Pos.unmark e with
|
||||
match Marked.unmark e with
|
||||
| EApp
|
||||
( (( EOp (Unop Not), _
|
||||
| EApp ((EOp (Unop (Log _)), _), [(EOp (Unop Not), _)]), _ ) as op),
|
||||
@ -64,7 +64,7 @@ let rec partial_evaluation (ctx : partial_evaluation_ctx) (e : expr Pos.marked)
|
||||
ELit (LBool false), pos
|
||||
| _ -> EApp (op, [e1; e2]), pos))
|
||||
(rec_helper e1) (rec_helper e2)
|
||||
| EVar (x, _) -> Bindlib.box_apply (fun x -> x, pos) (Bindlib.box_var x)
|
||||
| EVar x -> Bindlib.box_apply (fun x -> x, pos) (Bindlib.box_var x)
|
||||
| ETuple (args, s_name) ->
|
||||
Bindlib.box_apply
|
||||
(fun args -> ETuple (args, s_name), pos)
|
||||
@ -93,18 +93,16 @@ let rec partial_evaluation (ctx : partial_evaluation_ctx) (e : expr Pos.marked)
|
||||
(fun args -> EArray args, pos)
|
||||
(List.map rec_helper args |> Bindlib.box_list)
|
||||
| ELit l -> Bindlib.box (ELit l, pos)
|
||||
| EAbs ((binder, binder_pos), typs) ->
|
||||
| EAbs (binder, typs) ->
|
||||
let vars, body = Bindlib.unmbind binder in
|
||||
let new_body = rec_helper body in
|
||||
let new_binder = Bindlib.bind_mvar vars new_body in
|
||||
Bindlib.box_apply
|
||||
(fun binder -> EAbs ((binder, binder_pos), typs), pos)
|
||||
new_binder
|
||||
Bindlib.box_apply (fun binder -> EAbs (binder, typs), pos) new_binder
|
||||
| EApp (f, args) ->
|
||||
Bindlib.box_apply2
|
||||
(fun f args ->
|
||||
match Pos.unmark f with
|
||||
| EAbs ((binder, _pos_binder), _ts) ->
|
||||
match Marked.unmark f with
|
||||
| EAbs (binder, _ts) ->
|
||||
(* beta reduction *)
|
||||
Bindlib.msubst binder (List.map fst args |> Array.of_list)
|
||||
| _ -> EApp (f, args), pos)
|
||||
@ -119,7 +117,7 @@ let rec partial_evaluation (ctx : partial_evaluation_ctx) (e : expr Pos.marked)
|
||||
match
|
||||
( List.filter
|
||||
(fun except ->
|
||||
match Pos.unmark except with
|
||||
match Marked.unmark except with
|
||||
| ELit LEmptyError -> false
|
||||
| _ -> true)
|
||||
exceptions
|
||||
@ -166,7 +164,7 @@ let rec partial_evaluation (ctx : partial_evaluation_ctx) (e : expr Pos.marked)
|
||||
| EIfThenElse (e1, e2, e3) ->
|
||||
Bindlib.box_apply3
|
||||
(fun e1 e2 e3 ->
|
||||
match Pos.unmark e1, Pos.unmark e2, Pos.unmark e3 with
|
||||
match Marked.unmark e1, Marked.unmark e2, Marked.unmark e3 with
|
||||
| ELit (LBool true), _, _
|
||||
| EApp ((EOp (Unop (Log _)), _), [(ELit (LBool true), _)]), _, _ ->
|
||||
e2
|
||||
@ -185,14 +183,14 @@ let rec partial_evaluation (ctx : partial_evaluation_ctx) (e : expr Pos.marked)
|
||||
| ErrorOnEmpty e1 ->
|
||||
Bindlib.box_apply (fun e1 -> ErrorOnEmpty e1, pos) (rec_helper e1)
|
||||
|
||||
let optimize_expr (decl_ctx : decl_ctx) (e : expr Pos.marked) =
|
||||
let optimize_expr (decl_ctx : decl_ctx) (e : 'm marked_expr) =
|
||||
partial_evaluation { var_values = VarMap.empty; decl_ctx } e
|
||||
|
||||
let rec scope_lets_map
|
||||
(t : 'a -> expr Pos.marked -> expr Pos.marked Bindlib.box)
|
||||
(t : 'a -> 'm marked_expr -> 'm marked_expr Bindlib.box)
|
||||
(ctx : 'a)
|
||||
(scope_body_expr : expr scope_body_expr) : expr scope_body_expr Bindlib.box
|
||||
=
|
||||
(scope_body_expr : ('m expr, 'm) scope_body_expr) :
|
||||
('m expr, 'm) scope_body_expr Bindlib.box =
|
||||
match scope_body_expr with
|
||||
| Result e -> Bindlib.box_apply (fun e' -> Result e') (t ctx e)
|
||||
| ScopeLet scope_let ->
|
||||
@ -211,9 +209,9 @@ let rec scope_lets_map
|
||||
new_scope_let_expr new_next
|
||||
|
||||
let rec scopes_map
|
||||
(t : 'a -> expr Pos.marked -> expr Pos.marked Bindlib.box)
|
||||
(t : 'a -> 'm marked_expr -> 'm marked_expr Bindlib.box)
|
||||
(ctx : 'a)
|
||||
(scopes : expr scopes) : expr scopes Bindlib.box =
|
||||
(scopes : ('m expr, 'm) scopes) : ('m expr, 'm) scopes Bindlib.box =
|
||||
match scopes with
|
||||
| Nil -> Bindlib.box Nil
|
||||
| ScopeDef scope_def ->
|
||||
@ -242,15 +240,16 @@ let rec scopes_map
|
||||
new_scope_body_expr new_scope_next
|
||||
|
||||
let program_map
|
||||
(t : 'a -> expr Pos.marked -> expr Pos.marked Bindlib.box)
|
||||
(t : 'a -> 'm marked_expr -> 'm marked_expr Bindlib.box)
|
||||
(ctx : 'a)
|
||||
(p : program) : program Bindlib.box =
|
||||
(p : 'm program) : 'm program Bindlib.box =
|
||||
Bindlib.box_apply
|
||||
(fun new_scopes -> { p with scopes = new_scopes })
|
||||
(scopes_map t ctx p.scopes)
|
||||
|
||||
let optimize_program (p : program) : program =
|
||||
let optimize_program (p : 'm program) : untyped program =
|
||||
Bindlib.unbox
|
||||
(program_map partial_evaluation
|
||||
{ var_values = VarMap.empty; decl_ctx = p.decl_ctx }
|
||||
p)
|
||||
|> untype_program
|
||||
|
@ -17,8 +17,7 @@
|
||||
|
||||
(** Optimization passes for default calculus programs and expressions *)
|
||||
|
||||
open Utils
|
||||
open Ast
|
||||
|
||||
val optimize_expr : decl_ctx -> expr Pos.marked -> expr Pos.marked Bindlib.box
|
||||
val optimize_program : program -> program
|
||||
val optimize_expr : decl_ctx -> 'm marked_expr -> 'm marked_expr Bindlib.box
|
||||
val optimize_program : 'm program -> untyped program
|
||||
|
@ -16,21 +16,10 @@
|
||||
|
||||
open Utils
|
||||
open Ast
|
||||
open String_common
|
||||
|
||||
let typ_needs_parens (e : typ Pos.marked) : bool =
|
||||
match Pos.unmark e with TArrow _ | TArray _ -> true | _ -> false
|
||||
|
||||
let is_uppercase (x : CamomileLibraryDefault.Camomile.UChar.t) : bool =
|
||||
try
|
||||
match CamomileLibraryDefault.Camomile.UCharInfo.general_category x with
|
||||
| `Ll -> false
|
||||
| `Lu -> true
|
||||
| _ -> false
|
||||
with _ -> true
|
||||
|
||||
let begins_with_uppercase (s : string) : bool =
|
||||
let first_letter = CamomileLibraryDefault.Camomile.UTF8.get s 0 in
|
||||
is_uppercase first_letter
|
||||
let typ_needs_parens (e : typ) : bool =
|
||||
match e with TArrow _ | TArray _ -> true | _ -> false
|
||||
|
||||
let format_uid_list
|
||||
(fmt : Format.formatter)
|
||||
@ -41,7 +30,7 @@ let format_uid_list
|
||||
(fun fmt info ->
|
||||
Format.fprintf fmt "%a"
|
||||
(Utils.Cli.format_with_style
|
||||
(if begins_with_uppercase (Pos.unmark info) then
|
||||
(if begins_with_uppercase (Marked.unmark info) then
|
||||
[ANSITerminal.red]
|
||||
else []))
|
||||
(Format.asprintf "%a" Utils.Uid.MarkedString.format_info info)))
|
||||
@ -79,23 +68,21 @@ let format_enum_constructor (fmt : Format.formatter) (c : EnumConstructor.t) :
|
||||
(Utils.Cli.format_with_style [ANSITerminal.magenta])
|
||||
(Format.asprintf "%a" EnumConstructor.format_t c)
|
||||
|
||||
let rec format_typ
|
||||
(ctx : Ast.decl_ctx)
|
||||
(fmt : Format.formatter)
|
||||
(typ : typ Pos.marked) : unit =
|
||||
let rec format_typ (ctx : Ast.decl_ctx) (fmt : Format.formatter) (typ : typ) :
|
||||
unit =
|
||||
let format_typ = format_typ ctx in
|
||||
let format_typ_with_parens (fmt : Format.formatter) (t : typ Pos.marked) =
|
||||
let format_typ_with_parens (fmt : Format.formatter) (t : typ) =
|
||||
if typ_needs_parens t then Format.fprintf fmt "(%a)" format_typ t
|
||||
else Format.fprintf fmt "%a" format_typ t
|
||||
in
|
||||
match Pos.unmark typ with
|
||||
match typ with
|
||||
| TLit l -> Format.fprintf fmt "%a" format_tlit l
|
||||
| TTuple (ts, None) ->
|
||||
Format.fprintf fmt "@[<hov 2>(%a)@]"
|
||||
(Format.pp_print_list
|
||||
~pp_sep:(fun fmt () -> Format.fprintf fmt "@ %a@ " format_operator "*")
|
||||
(fun fmt t -> Format.fprintf fmt "%a" format_typ t))
|
||||
ts
|
||||
(List.map Marked.unmark ts)
|
||||
| TTuple (_args, Some s) ->
|
||||
Format.fprintf fmt "@[<hov 2>%a%a%a%a@]" Ast.StructName.format_t s
|
||||
format_punctuation "{"
|
||||
@ -106,7 +93,9 @@ let rec format_typ
|
||||
Format.fprintf fmt "%a%a%a%a@ %a" format_punctuation "\""
|
||||
StructFieldName.format_t field format_punctuation "\""
|
||||
format_punctuation ":" format_typ typ))
|
||||
(StructMap.find s ctx.ctx_structs)
|
||||
(List.map
|
||||
(fun (c, t) -> c, Marked.unmark t)
|
||||
(StructMap.find s ctx.ctx_structs))
|
||||
format_punctuation "}"
|
||||
| TEnum (_, e) ->
|
||||
Format.fprintf fmt "@[<hov 2>%a%a%a%a@]" Ast.EnumName.format_t e
|
||||
@ -117,19 +106,21 @@ let rec format_typ
|
||||
(fun fmt (case, typ) ->
|
||||
Format.fprintf fmt "%a%a@ %a" format_enum_constructor case
|
||||
format_punctuation ":" format_typ typ))
|
||||
(EnumMap.find e ctx.ctx_enums)
|
||||
(List.map
|
||||
(fun (c, t) -> c, Marked.unmark t)
|
||||
(EnumMap.find e ctx.ctx_enums))
|
||||
format_punctuation "]"
|
||||
| TArrow (t1, t2) ->
|
||||
Format.fprintf fmt "@[<hov 2>%a %a@ %a@]" format_typ_with_parens t1
|
||||
format_operator "→" format_typ t2
|
||||
Format.fprintf fmt "@[<hov 2>%a %a@ %a@]" format_typ_with_parens
|
||||
(Marked.unmark t1) format_operator "→" format_typ (Marked.unmark t2)
|
||||
| TArray t1 ->
|
||||
Format.fprintf fmt "@[<hov 2>%a@ %a@]" format_base_type "array" format_typ
|
||||
t1
|
||||
(Marked.unmark t1)
|
||||
| TAny -> format_base_type fmt "any"
|
||||
|
||||
(* (EmileRolley) NOTE: seems to be factorizable with Lcalc.Print.format_lit. *)
|
||||
let format_lit (fmt : Format.formatter) (l : lit Pos.marked) : unit =
|
||||
match Pos.unmark l with
|
||||
let format_lit (fmt : Format.formatter) (l : lit) : unit =
|
||||
match l with
|
||||
| LBool b -> format_lit_style fmt (string_of_bool b)
|
||||
| LInt i -> format_lit_style fmt (Runtime.integer_to_string i)
|
||||
| LEmptyError -> format_lit_style fmt "∅ "
|
||||
@ -158,9 +149,9 @@ let format_op_kind (fmt : Format.formatter) (k : op_kind) =
|
||||
| KDate -> "@"
|
||||
| KDuration -> "^")
|
||||
|
||||
let format_binop (fmt : Format.formatter) (op : binop Pos.marked) : unit =
|
||||
let format_binop (fmt : Format.formatter) (op : binop) : unit =
|
||||
format_operator fmt
|
||||
(match Pos.unmark op with
|
||||
(match op with
|
||||
| Add k -> Format.asprintf "+%a" format_op_kind k
|
||||
| Sub k -> Format.asprintf "-%a" format_op_kind k
|
||||
| Mult k -> Format.asprintf "*%a" format_op_kind k
|
||||
@ -178,8 +169,8 @@ let format_binop (fmt : Format.formatter) (op : binop Pos.marked) : unit =
|
||||
| Map -> "map"
|
||||
| Filter -> "filter")
|
||||
|
||||
let format_ternop (fmt : Format.formatter) (op : ternop Pos.marked) : unit =
|
||||
match Pos.unmark op with Fold -> format_keyword fmt "fold"
|
||||
let format_ternop (fmt : Format.formatter) (op : ternop) : unit =
|
||||
match op with Fold -> format_keyword fmt "fold"
|
||||
|
||||
let format_log_entry (fmt : Format.formatter) (entry : log_entry) : unit =
|
||||
Format.fprintf fmt "@<2>%s"
|
||||
@ -189,9 +180,9 @@ let format_log_entry (fmt : Format.formatter) (entry : log_entry) : unit =
|
||||
| EndCall -> Utils.Cli.with_style [ANSITerminal.yellow] "← "
|
||||
| PosRecordIfTrueBool -> Utils.Cli.with_style [ANSITerminal.green] "☛ ")
|
||||
|
||||
let format_unop (fmt : Format.formatter) (op : unop Pos.marked) : unit =
|
||||
let format_unop (fmt : Format.formatter) (op : unop) : unit =
|
||||
Format.fprintf fmt "%s"
|
||||
(match Pos.unmark op with
|
||||
(match op with
|
||||
| Minus _ -> "-"
|
||||
| Not -> "~"
|
||||
| Log (entry, infos) ->
|
||||
@ -202,32 +193,36 @@ let format_unop (fmt : Format.formatter) (op : unop Pos.marked) : unit =
|
||||
infos
|
||||
| Length -> "length"
|
||||
| IntToRat -> "int_to_rat"
|
||||
| MoneyToRat -> "money_to_rat"
|
||||
| RatToMoney -> "rat_to_money"
|
||||
| GetDay -> "get_day"
|
||||
| GetMonth -> "get_month"
|
||||
| GetYear -> "get_year"
|
||||
| FirstDayOfMonth -> "first_day_of_month"
|
||||
| LastDayOfMonth -> "last_day_of_month"
|
||||
| RoundMoney -> "round_money"
|
||||
| RoundDecimal -> "round_decimal")
|
||||
|
||||
let needs_parens (e : expr Pos.marked) : bool =
|
||||
match Pos.unmark e with EAbs _ | ETuple (_, Some _) -> true | _ -> false
|
||||
let needs_parens (e : 'm marked_expr) : bool =
|
||||
match Marked.unmark e with EAbs _ | ETuple (_, Some _) -> true | _ -> false
|
||||
|
||||
let format_var (fmt : Format.formatter) (v : Var.t) : unit =
|
||||
let format_var (fmt : Format.formatter) (v : 'm Ast.var) : unit =
|
||||
Format.fprintf fmt "%s_%d" (Bindlib.name_of v) (Bindlib.uid_of v)
|
||||
|
||||
let rec format_expr
|
||||
?(debug : bool = false)
|
||||
(ctx : Ast.decl_ctx)
|
||||
(fmt : Format.formatter)
|
||||
(e : expr Pos.marked) : unit =
|
||||
(e : 'm marked_expr) : unit =
|
||||
let format_expr = format_expr ~debug ctx in
|
||||
let format_with_parens (fmt : Format.formatter) (e : expr Pos.marked) =
|
||||
let format_with_parens (fmt : Format.formatter) (e : 'm marked_expr) =
|
||||
if needs_parens e then
|
||||
Format.fprintf fmt "%a%a%a" format_punctuation "(" format_expr e
|
||||
format_punctuation ")"
|
||||
else Format.fprintf fmt "%a" format_expr e
|
||||
in
|
||||
match Pos.unmark e with
|
||||
| EVar v -> Format.fprintf fmt "%a" format_var (Pos.unmark v)
|
||||
match Marked.unmark e with
|
||||
| EVar v -> Format.fprintf fmt "%a" format_var v
|
||||
| ETuple (es, None) ->
|
||||
Format.fprintf fmt "@[<hov 2>%a%a%a@]" format_punctuation "("
|
||||
(Format.pp_print_list
|
||||
@ -274,10 +269,12 @@ let rec format_expr
|
||||
Format.fprintf fmt "@[<hov 2>%a %a%a@ %a@]" format_punctuation "|"
|
||||
format_enum_constructor c format_punctuation ":" format_expr e))
|
||||
(List.combine es (List.map fst (Ast.EnumMap.find e_name ctx.ctx_enums)))
|
||||
| ELit l -> format_lit fmt (Pos.same_pos_as l e)
|
||||
| EApp ((EAbs ((binder, _), taus), _), args) ->
|
||||
| ELit l -> format_lit fmt l
|
||||
| EApp ((EAbs (binder, taus), _), args) ->
|
||||
let xs, body = Bindlib.unmbind binder in
|
||||
let xs_tau = List.map2 (fun x tau -> x, tau) (Array.to_list xs) taus in
|
||||
let xs_tau =
|
||||
List.map2 (fun x tau -> x, Marked.unmark tau) (Array.to_list xs) taus
|
||||
in
|
||||
let xs_tau_arg = List.map2 (fun (x, tau) arg -> x, tau, arg) xs_tau args in
|
||||
Format.fprintf fmt "%a%a"
|
||||
(Format.pp_print_list
|
||||
@ -288,9 +285,11 @@ let rec format_expr
|
||||
(format_typ ctx) tau format_punctuation "=" format_expr arg
|
||||
format_keyword "in"))
|
||||
xs_tau_arg format_expr body
|
||||
| EAbs ((binder, _), taus) ->
|
||||
| EAbs (binder, taus) ->
|
||||
let xs, body = Bindlib.unmbind binder in
|
||||
let xs_tau = List.map2 (fun x tau -> x, tau) (Array.to_list xs) taus in
|
||||
let xs_tau =
|
||||
List.map2 (fun x tau -> x, Marked.unmark tau) (Array.to_list xs) taus
|
||||
in
|
||||
Format.fprintf fmt "@[<hov 2>%a @[<hov 2>%a@] %a@ %a@]" format_punctuation
|
||||
"λ"
|
||||
(Format.pp_print_list
|
||||
@ -300,16 +299,16 @@ let rec format_expr
|
||||
format_punctuation ":" (format_typ ctx) tau format_punctuation ")"))
|
||||
xs_tau format_punctuation "→" format_expr body
|
||||
| EApp ((EOp (Binop ((Ast.Map | Ast.Filter) as op)), _), [arg1; arg2]) ->
|
||||
Format.fprintf fmt "@[<hov 2>%a@ %a@ %a@]" format_binop (op, Pos.no_pos)
|
||||
Format.fprintf fmt "@[<hov 2>%a@ %a@ %a@]" format_binop op
|
||||
format_with_parens arg1 format_with_parens arg2
|
||||
| EApp ((EOp (Binop op), _), [arg1; arg2]) ->
|
||||
Format.fprintf fmt "@[<hov 2>%a@ %a@ %a@]" format_with_parens arg1
|
||||
format_binop (op, Pos.no_pos) format_with_parens arg2
|
||||
format_binop op format_with_parens arg2
|
||||
| EApp ((EOp (Unop (Log _)), _), [arg1]) when not debug ->
|
||||
format_expr fmt arg1
|
||||
| EApp ((EOp (Unop op), _), [arg1]) ->
|
||||
Format.fprintf fmt "@[<hov 2>%a@ %a@]" format_unop (op, Pos.no_pos)
|
||||
format_with_parens arg1
|
||||
Format.fprintf fmt "@[<hov 2>%a@ %a@]" format_unop op format_with_parens
|
||||
arg1
|
||||
| EApp (f, args) ->
|
||||
Format.fprintf fmt "@[<hov 2>%a@ %a@]" format_expr f
|
||||
(Format.pp_print_list
|
||||
@ -320,9 +319,9 @@ let rec format_expr
|
||||
Format.fprintf fmt "@[<hov 2>%a@ %a@ %a@ %a@ %a@ %a@]" format_keyword "if"
|
||||
format_expr e1 format_keyword "then" format_expr e2 format_keyword "else"
|
||||
format_expr e3
|
||||
| EOp (Ternop op) -> Format.fprintf fmt "%a" format_ternop (op, Pos.no_pos)
|
||||
| EOp (Binop op) -> Format.fprintf fmt "%a" format_binop (op, Pos.no_pos)
|
||||
| EOp (Unop op) -> Format.fprintf fmt "%a" format_unop (op, Pos.no_pos)
|
||||
| EOp (Ternop op) -> Format.fprintf fmt "%a" format_ternop op
|
||||
| EOp (Binop op) -> Format.fprintf fmt "%a" format_binop op
|
||||
| EOp (Unop op) -> Format.fprintf fmt "%a" format_unop op
|
||||
| EDefault (exceptions, just, cons) ->
|
||||
if List.length exceptions = 0 then
|
||||
Format.fprintf fmt "@[<hov 2>%a%a@ %a@ %a%a@]" format_punctuation "⟨"
|
||||
@ -348,10 +347,13 @@ let format_scope
|
||||
?(debug : bool = false)
|
||||
(ctx : decl_ctx)
|
||||
(fmt : Format.formatter)
|
||||
((n, s) : Ast.ScopeName.t * Ast.expr scope_body) =
|
||||
((n, s) : Ast.ScopeName.t * ('m Ast.expr, 'm) scope_body) =
|
||||
Format.fprintf fmt "@[<hov 2>%a %a =@ %a@]" format_keyword "let"
|
||||
Ast.ScopeName.format_t n (format_expr ctx ~debug)
|
||||
(Bindlib.unbox
|
||||
(Ast.build_whole_scope_expr ~make_abs:Ast.make_abs
|
||||
~make_let_in:Ast.make_let_in ~box_expr:Ast.box_expr ctx s
|
||||
(Pos.get_position (Ast.ScopeName.get_info n))))
|
||||
(Ast.map_mark
|
||||
(fun _ -> Marked.get_mark (Ast.ScopeName.get_info n))
|
||||
(fun ty -> ty)
|
||||
(Ast.get_scope_body_mark s))))
|
||||
|
@ -18,11 +18,6 @@
|
||||
|
||||
open Utils
|
||||
|
||||
(** {1 Helpers} *)
|
||||
|
||||
val is_uppercase : CamomileLibraryDefault.Camomile.UChar.t -> bool
|
||||
val begins_with_uppercase : string -> bool
|
||||
|
||||
(** {1 Common syntax highlighting helpers}*)
|
||||
|
||||
val format_base_type : Format.formatter -> string -> unit
|
||||
@ -36,25 +31,25 @@ val format_lit_style : Format.formatter -> string -> unit
|
||||
val format_uid_list : Format.formatter -> Uid.MarkedString.info list -> unit
|
||||
val format_enum_constructor : Format.formatter -> Ast.EnumConstructor.t -> unit
|
||||
val format_tlit : Format.formatter -> Ast.typ_lit -> unit
|
||||
val format_typ : Ast.decl_ctx -> Format.formatter -> Ast.typ Pos.marked -> unit
|
||||
val format_lit : Format.formatter -> Ast.lit Pos.marked -> unit
|
||||
val format_typ : Ast.decl_ctx -> Format.formatter -> Ast.typ -> unit
|
||||
val format_lit : Format.formatter -> Ast.lit -> unit
|
||||
val format_op_kind : Format.formatter -> Ast.op_kind -> unit
|
||||
val format_binop : Format.formatter -> Ast.binop Pos.marked -> unit
|
||||
val format_ternop : Format.formatter -> Ast.ternop Pos.marked -> unit
|
||||
val format_binop : Format.formatter -> Ast.binop -> unit
|
||||
val format_ternop : Format.formatter -> Ast.ternop -> unit
|
||||
val format_log_entry : Format.formatter -> Ast.log_entry -> unit
|
||||
val format_unop : Format.formatter -> Ast.unop Pos.marked -> unit
|
||||
val format_var : Format.formatter -> Ast.Var.t -> unit
|
||||
val format_unop : Format.formatter -> Ast.unop -> unit
|
||||
val format_var : Format.formatter -> 'm Ast.var -> unit
|
||||
|
||||
val format_expr :
|
||||
?debug:bool (** [true] for debug printing *) ->
|
||||
Ast.decl_ctx ->
|
||||
Format.formatter ->
|
||||
Ast.expr Pos.marked ->
|
||||
'm Ast.marked_expr ->
|
||||
unit
|
||||
|
||||
val format_scope :
|
||||
?debug:bool (** [true] for debug printing *) ->
|
||||
Ast.decl_ctx ->
|
||||
Format.formatter ->
|
||||
Ast.ScopeName.t * Ast.expr Ast.scope_body ->
|
||||
Ast.ScopeName.t * ('m Ast.expr, 'm) Ast.scope_body ->
|
||||
unit
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -17,8 +17,18 @@
|
||||
(** Typing for the default calculus. Because of the error terms, we perform type
|
||||
inference using the classical W algorithm with union-find unification. *)
|
||||
|
||||
val infer_type :
|
||||
Ast.decl_ctx -> Ast.expr Utils.Pos.marked -> Ast.typ Utils.Pos.marked
|
||||
val infer_types :
|
||||
Ast.decl_ctx ->
|
||||
Ast.untyped Ast.marked_expr ->
|
||||
Ast.typed Ast.marked_expr Bindlib.box
|
||||
(** Infers types everywhere on the given expression, and adds (or replaces) type
|
||||
annotations on each node *)
|
||||
|
||||
val infer_type : Ast.decl_ctx -> 'm Ast.marked_expr -> Ast.typ Utils.Marked.pos
|
||||
(** Gets the outer type of the given expression, using either the existing
|
||||
annotations or inference *)
|
||||
|
||||
val check_type :
|
||||
Ast.decl_ctx -> Ast.expr Utils.Pos.marked -> Ast.typ Utils.Pos.marked -> unit
|
||||
Ast.decl_ctx -> 'm Ast.marked_expr -> Ast.typ Utils.Marked.pos -> unit
|
||||
|
||||
val infer_types_program : Ast.untyped Ast.program -> Ast.typed Ast.program
|
||||
|
@ -69,10 +69,10 @@ module ScopeDef = struct
|
||||
|
||||
let get_position x =
|
||||
match x with
|
||||
| Var (x, None) -> Pos.get_position (ScopeVar.get_info x)
|
||||
| Var (_, Some sx) -> Pos.get_position (StateName.get_info sx)
|
||||
| Var (x, None) -> Marked.get_mark (ScopeVar.get_info x)
|
||||
| Var (_, Some sx) -> Marked.get_mark (StateName.get_info sx)
|
||||
| SubScopeVar (x, _) ->
|
||||
Pos.get_position (Scopelang.Ast.SubScopeName.get_info x)
|
||||
Marked.get_mark (Scopelang.Ast.SubScopeName.get_info x)
|
||||
|
||||
let format_t fmt x =
|
||||
match x with
|
||||
@ -97,22 +97,22 @@ module ScopeDefSet : Set.S with type elt = ScopeDef.t = Set.Make (ScopeDef)
|
||||
(** {1 AST} *)
|
||||
|
||||
type location =
|
||||
| ScopeVar of ScopeVar.t Pos.marked * StateName.t option
|
||||
| ScopeVar of ScopeVar.t Marked.pos * StateName.t option
|
||||
| SubScopeVar of
|
||||
Scopelang.Ast.ScopeName.t
|
||||
* Scopelang.Ast.SubScopeName.t Pos.marked
|
||||
* ScopeVar.t Pos.marked
|
||||
* Scopelang.Ast.SubScopeName.t Marked.pos
|
||||
* ScopeVar.t Marked.pos
|
||||
|
||||
module LocationSet : Set.S with type elt = location Pos.marked =
|
||||
module LocationSet : Set.S with type elt = location Marked.pos =
|
||||
Set.Make (struct
|
||||
type t = location Pos.marked
|
||||
type t = location Marked.pos
|
||||
|
||||
let compare x y =
|
||||
match Pos.unmark x, Pos.unmark y with
|
||||
match Marked.unmark x, Marked.unmark y with
|
||||
| ScopeVar (vx, None), ScopeVar (vy, None)
|
||||
| ScopeVar (vx, Some _), ScopeVar (vy, None)
|
||||
| ScopeVar (vx, None), ScopeVar (vy, Some _) ->
|
||||
ScopeVar.compare (Pos.unmark vx) (Pos.unmark vy)
|
||||
ScopeVar.compare (Marked.unmark vx) (Marked.unmark vy)
|
||||
| ScopeVar ((x, _), Some sx), ScopeVar ((y, _), Some sy) ->
|
||||
let cmp = ScopeVar.compare x y in
|
||||
if cmp = 0 then StateName.compare sx sy else cmp
|
||||
@ -124,36 +124,32 @@ Set.Make (struct
|
||||
| SubScopeVar _, ScopeVar _ -> 1
|
||||
end)
|
||||
|
||||
type marked_expr = expr Marked.pos
|
||||
(** The expressions use the {{:https://lepigre.fr/ocaml-bindlib/} Bindlib}
|
||||
library, based on higher-order abstract syntax*)
|
||||
type expr =
|
||||
|
||||
and expr =
|
||||
| ELocation of location
|
||||
| EVar of expr Bindlib.var Pos.marked
|
||||
| EVar of expr Bindlib.var
|
||||
| EStruct of
|
||||
Scopelang.Ast.StructName.t
|
||||
* expr Pos.marked Scopelang.Ast.StructFieldMap.t
|
||||
Scopelang.Ast.StructName.t * marked_expr Scopelang.Ast.StructFieldMap.t
|
||||
| EStructAccess of
|
||||
expr Pos.marked
|
||||
* Scopelang.Ast.StructFieldName.t
|
||||
* Scopelang.Ast.StructName.t
|
||||
marked_expr * Scopelang.Ast.StructFieldName.t * Scopelang.Ast.StructName.t
|
||||
| EEnumInj of
|
||||
expr Pos.marked
|
||||
* Scopelang.Ast.EnumConstructor.t
|
||||
* Scopelang.Ast.EnumName.t
|
||||
marked_expr * Scopelang.Ast.EnumConstructor.t * Scopelang.Ast.EnumName.t
|
||||
| EMatch of
|
||||
expr Pos.marked
|
||||
marked_expr
|
||||
* Scopelang.Ast.EnumName.t
|
||||
* expr Pos.marked Scopelang.Ast.EnumConstructorMap.t
|
||||
* marked_expr Scopelang.Ast.EnumConstructorMap.t
|
||||
| ELit of Dcalc.Ast.lit
|
||||
| EAbs of
|
||||
(expr, expr Pos.marked) Bindlib.mbinder Pos.marked
|
||||
* Scopelang.Ast.typ Pos.marked list
|
||||
| EApp of expr Pos.marked * expr Pos.marked list
|
||||
(expr, marked_expr) Bindlib.mbinder * Scopelang.Ast.typ Marked.pos list
|
||||
| EApp of marked_expr * marked_expr list
|
||||
| EOp of Dcalc.Ast.operator
|
||||
| EDefault of expr Pos.marked list * expr Pos.marked * expr Pos.marked
|
||||
| EIfThenElse of expr Pos.marked * expr Pos.marked * expr Pos.marked
|
||||
| EArray of expr Pos.marked list
|
||||
| ErrorOnEmpty of expr Pos.marked
|
||||
| EDefault of marked_expr list * marked_expr * marked_expr
|
||||
| EIfThenElse of marked_expr * marked_expr * marked_expr
|
||||
| EArray of marked_expr list
|
||||
| ErrorOnEmpty of marked_expr
|
||||
|
||||
module Expr = struct
|
||||
type t = expr
|
||||
@ -172,13 +168,12 @@ module Expr = struct
|
||||
in
|
||||
match e1, e2 with
|
||||
| ELocation _, ELocation _ -> 0
|
||||
| EVar (v1, _), EVar (v2, _) -> Bindlib.compare_vars v1 v2
|
||||
| EVar v1, EVar v2 -> Bindlib.compare_vars v1 v2
|
||||
| EStruct (name1, field_map1), EStruct (name2, field_map2) -> (
|
||||
match Scopelang.Ast.StructName.compare name1 name2 with
|
||||
| 0 ->
|
||||
Scopelang.Ast.StructFieldMap.compare
|
||||
(Pos.compare_marked compare)
|
||||
field_map1 field_map2
|
||||
Scopelang.Ast.StructFieldMap.compare (Marked.compare compare) field_map1
|
||||
field_map2
|
||||
| n -> n)
|
||||
| ( EStructAccess ((e1, _), field_name1, struct_name1),
|
||||
EStructAccess ((e2, _), field_name2, struct_name2) ) -> (
|
||||
@ -200,15 +195,14 @@ module Expr = struct
|
||||
| 0 -> (
|
||||
match Scopelang.Ast.EnumName.compare name1 name2 with
|
||||
| 0 ->
|
||||
Scopelang.Ast.EnumConstructorMap.compare
|
||||
(Pos.compare_marked compare)
|
||||
Scopelang.Ast.EnumConstructorMap.compare (Marked.compare compare)
|
||||
emap1 emap2
|
||||
| n -> n)
|
||||
| n -> n)
|
||||
| ELit l1, ELit l2 -> Stdlib.compare l1 l2
|
||||
| EAbs ((binder1, _), typs1), EAbs ((binder2, _), typs2) -> (
|
||||
| EAbs (binder1, typs1), EAbs (binder2, typs2) -> (
|
||||
match
|
||||
list_compare (Pos.compare_marked Scopelang.Ast.Typ.compare) typs1 typs2
|
||||
list_compare (Marked.compare Scopelang.Ast.Typ.compare) typs1 typs2
|
||||
with
|
||||
| 0 ->
|
||||
let _, (e1, _), (e2, _) = Bindlib.unmbind2 binder1 binder2 in
|
||||
@ -224,7 +218,7 @@ module Expr = struct
|
||||
match compare just1 just2 with
|
||||
| 0 -> (
|
||||
match compare cons1 cons2 with
|
||||
| 0 -> list_compare (Pos.compare_marked compare) exs1 exs2
|
||||
| 0 -> list_compare (Marked.compare compare) exs1 exs2
|
||||
| n -> n)
|
||||
| n -> n)
|
||||
| ( EIfThenElse ((i1, _), (t1, _), (e1, _)),
|
||||
@ -268,22 +262,28 @@ module ExprMap = Map.Make (Expr)
|
||||
module Var = struct
|
||||
type t = expr Bindlib.var
|
||||
|
||||
let make (s : string Pos.marked) : t =
|
||||
Bindlib.new_var
|
||||
(fun (x : expr Bindlib.var) : expr -> EVar (x, Pos.get_position s))
|
||||
(Pos.unmark s)
|
||||
let make (s : string) : t =
|
||||
Bindlib.new_var (fun (x : expr Bindlib.var) : expr -> EVar x) s
|
||||
|
||||
let compare x y = Bindlib.compare_vars x y
|
||||
end
|
||||
|
||||
type vars = expr Bindlib.mvar
|
||||
|
||||
type exception_situation =
|
||||
| BaseCase
|
||||
| ExceptionToLabel of LabelName.t Marked.pos
|
||||
| ExceptionToRule of RuleName.t Marked.pos
|
||||
|
||||
type label_situation = ExplicitlyLabeled of LabelName.t Marked.pos | Unlabeled
|
||||
|
||||
type rule = {
|
||||
rule_id : RuleName.t;
|
||||
rule_just : expr Pos.marked Bindlib.box;
|
||||
rule_cons : expr Pos.marked Bindlib.box;
|
||||
rule_parameter : (Var.t * Scopelang.Ast.typ Pos.marked) option;
|
||||
rule_exception_to_rules : RuleSet.t Pos.marked;
|
||||
rule_just : expr Marked.pos Bindlib.box;
|
||||
rule_cons : expr Marked.pos Bindlib.box;
|
||||
rule_parameter : (Var.t * Scopelang.Ast.typ Marked.pos) option;
|
||||
rule_exception : exception_situation;
|
||||
rule_label : label_situation;
|
||||
}
|
||||
|
||||
module Rule = struct
|
||||
@ -323,46 +323,47 @@ end
|
||||
|
||||
let empty_rule
|
||||
(pos : Pos.t)
|
||||
(have_parameter : Scopelang.Ast.typ Pos.marked option) : rule =
|
||||
(have_parameter : Scopelang.Ast.typ Marked.pos option) : rule =
|
||||
{
|
||||
rule_just = Bindlib.box (ELit (Dcalc.Ast.LBool false), pos);
|
||||
rule_cons = Bindlib.box (ELit Dcalc.Ast.LEmptyError, pos);
|
||||
rule_parameter =
|
||||
(match have_parameter with
|
||||
| Some typ -> Some (Var.make ("dummy", pos), typ)
|
||||
| Some typ -> Some (Var.make "dummy", typ)
|
||||
| None -> None);
|
||||
rule_exception_to_rules = RuleSet.empty, pos;
|
||||
rule_exception = BaseCase;
|
||||
rule_id = RuleName.fresh ("empty", pos);
|
||||
rule_label = Unlabeled;
|
||||
}
|
||||
|
||||
let always_false_rule
|
||||
(pos : Pos.t)
|
||||
(have_parameter : Scopelang.Ast.typ Pos.marked option) : rule =
|
||||
(have_parameter : Scopelang.Ast.typ Marked.pos option) : rule =
|
||||
{
|
||||
rule_just = Bindlib.box (ELit (Dcalc.Ast.LBool true), pos);
|
||||
rule_cons = Bindlib.box (ELit (Dcalc.Ast.LBool false), pos);
|
||||
rule_parameter =
|
||||
(match have_parameter with
|
||||
| Some typ -> Some (Var.make ("dummy", pos), typ)
|
||||
| Some typ -> Some (Var.make "dummy", typ)
|
||||
| None -> None);
|
||||
rule_exception_to_rules = RuleSet.empty, pos;
|
||||
rule_exception = BaseCase;
|
||||
rule_id = RuleName.fresh ("always_false", pos);
|
||||
rule_label = Unlabeled;
|
||||
}
|
||||
|
||||
type assertion = expr Pos.marked Bindlib.box
|
||||
type assertion = expr Marked.pos Bindlib.box
|
||||
type variation_typ = Increasing | Decreasing
|
||||
type reference_typ = Decree | Law
|
||||
|
||||
type meta_assertion =
|
||||
| FixedBy of reference_typ Pos.marked
|
||||
| VariesWith of unit * variation_typ Pos.marked option
|
||||
| FixedBy of reference_typ Marked.pos
|
||||
| VariesWith of unit * variation_typ Marked.pos option
|
||||
|
||||
type scope_def = {
|
||||
scope_def_rules : rule RuleMap.t;
|
||||
scope_def_typ : Scopelang.Ast.typ Pos.marked;
|
||||
scope_def_typ : Scopelang.Ast.typ Marked.pos;
|
||||
scope_def_is_condition : bool;
|
||||
scope_def_io : Scopelang.Ast.io;
|
||||
scope_def_label_groups : RuleSet.t LabelMap.t;
|
||||
}
|
||||
|
||||
type var_or_states = WholeVar | States of StateName.t list
|
||||
@ -382,11 +383,11 @@ type program = {
|
||||
program_structs : Scopelang.Ast.struct_ctx;
|
||||
}
|
||||
|
||||
let rec locations_used (e : expr Pos.marked) : LocationSet.t =
|
||||
match Pos.unmark e with
|
||||
| ELocation l -> LocationSet.singleton (l, Pos.get_position e)
|
||||
let rec locations_used (e : expr Marked.pos) : LocationSet.t =
|
||||
match Marked.unmark e with
|
||||
| ELocation l -> LocationSet.singleton (l, Marked.get_mark e)
|
||||
| EVar _ | ELit _ | EOp _ -> LocationSet.empty
|
||||
| EAbs ((binder, _), _) ->
|
||||
| EAbs (binder, _) ->
|
||||
let _, body = Bindlib.unmbind binder in
|
||||
locations_used body
|
||||
| EStruct (_, es) ->
|
||||
@ -424,9 +425,9 @@ let free_variables (def : rule RuleMap.t) : Pos.t ScopeDefMap.t =
|
||||
(fun (loc, loc_pos) acc ->
|
||||
ScopeDefMap.add
|
||||
(match loc with
|
||||
| ScopeVar (v, st) -> ScopeDef.Var (Pos.unmark v, st)
|
||||
| ScopeVar (v, st) -> ScopeDef.Var (Marked.unmark v, st)
|
||||
| SubScopeVar (_, sub_index, sub_var) ->
|
||||
ScopeDef.SubScopeVar (Pos.unmark sub_index, Pos.unmark sub_var))
|
||||
ScopeDef.SubScopeVar (Marked.unmark sub_index, Marked.unmark sub_var))
|
||||
loc_pos acc)
|
||||
locs acc
|
||||
in
|
||||
@ -440,36 +441,30 @@ let free_variables (def : rule RuleMap.t) : Pos.t ScopeDefMap.t =
|
||||
add_locs acc locs)
|
||||
def ScopeDefMap.empty
|
||||
|
||||
let make_var ((x, pos) : Var.t Pos.marked) : expr Pos.marked Bindlib.box =
|
||||
let make_var ((x, pos) : Var.t Marked.pos) : expr Marked.pos Bindlib.box =
|
||||
Bindlib.box_apply (fun v -> v, pos) (Bindlib.box_var x)
|
||||
|
||||
let make_abs
|
||||
(xs : vars)
|
||||
(e : expr Pos.marked Bindlib.box)
|
||||
(pos_binder : Pos.t)
|
||||
(taus : Scopelang.Ast.typ Pos.marked list)
|
||||
(pos : Pos.t) : expr Pos.marked Bindlib.box =
|
||||
Bindlib.box_apply
|
||||
(fun b -> EAbs ((b, pos_binder), taus), pos)
|
||||
(Bindlib.bind_mvar xs e)
|
||||
(e : expr Marked.pos Bindlib.box)
|
||||
(taus : Scopelang.Ast.typ Marked.pos list)
|
||||
(pos : Pos.t) : expr Marked.pos Bindlib.box =
|
||||
Bindlib.box_apply (fun b -> EAbs (b, taus), pos) (Bindlib.bind_mvar xs e)
|
||||
|
||||
let make_app
|
||||
(e : expr Pos.marked Bindlib.box)
|
||||
(u : expr Pos.marked Bindlib.box list)
|
||||
(pos : Pos.t) : expr Pos.marked Bindlib.box =
|
||||
(e : expr Marked.pos Bindlib.box)
|
||||
(u : expr Marked.pos Bindlib.box list)
|
||||
(pos : Pos.t) : expr Marked.pos Bindlib.box =
|
||||
Bindlib.box_apply2 (fun e u -> EApp (e, u), pos) e (Bindlib.box_list u)
|
||||
|
||||
let make_let_in
|
||||
(x : Var.t)
|
||||
(tau : Scopelang.Ast.typ Pos.marked)
|
||||
(e1 : expr Pos.marked Bindlib.box)
|
||||
(e2 : expr Pos.marked Bindlib.box) : expr Pos.marked Bindlib.box =
|
||||
(tau : Scopelang.Ast.typ Marked.pos)
|
||||
(e1 : expr Marked.pos Bindlib.box)
|
||||
(e2 : expr Marked.pos Bindlib.box) : expr Marked.pos Bindlib.box =
|
||||
Bindlib.box_apply2
|
||||
(fun e u -> EApp (e, u), Pos.get_position (Bindlib.unbox e2))
|
||||
(make_abs (Array.of_list [x]) e2
|
||||
(Pos.get_position (Bindlib.unbox e2))
|
||||
[tau]
|
||||
(Pos.get_position (Bindlib.unbox e2)))
|
||||
(fun e u -> EApp (e, u), Marked.get_mark (Bindlib.unbox e2))
|
||||
(make_abs (Array.of_list [x]) e2 [tau] (Marked.get_mark (Bindlib.unbox e2)))
|
||||
(Bindlib.box_list [e1])
|
||||
|
||||
module VarMap = Map.Make (Var)
|
||||
|
@ -52,44 +52,40 @@ module ScopeDefSet : Set.S with type elt = ScopeDef.t
|
||||
|
||||
(**{2 Expressions}*)
|
||||
type location =
|
||||
| ScopeVar of ScopeVar.t Pos.marked * StateName.t option
|
||||
| ScopeVar of ScopeVar.t Marked.pos * StateName.t option
|
||||
| SubScopeVar of
|
||||
Scopelang.Ast.ScopeName.t
|
||||
* Scopelang.Ast.SubScopeName.t Pos.marked
|
||||
* ScopeVar.t Pos.marked
|
||||
* Scopelang.Ast.SubScopeName.t Marked.pos
|
||||
* ScopeVar.t Marked.pos
|
||||
|
||||
module LocationSet : Set.S with type elt = location Pos.marked
|
||||
module LocationSet : Set.S with type elt = location Marked.pos
|
||||
|
||||
type marked_expr = expr Marked.pos
|
||||
(** The expressions use the {{:https://lepigre.fr/ocaml-bindlib/} Bindlib}
|
||||
library, based on higher-order abstract syntax*)
|
||||
type expr =
|
||||
|
||||
and expr =
|
||||
| ELocation of location
|
||||
| EVar of expr Bindlib.var Pos.marked
|
||||
| EVar of expr Bindlib.var
|
||||
| EStruct of
|
||||
Scopelang.Ast.StructName.t
|
||||
* expr Pos.marked Scopelang.Ast.StructFieldMap.t
|
||||
Scopelang.Ast.StructName.t * marked_expr Scopelang.Ast.StructFieldMap.t
|
||||
| EStructAccess of
|
||||
expr Pos.marked
|
||||
* Scopelang.Ast.StructFieldName.t
|
||||
* Scopelang.Ast.StructName.t
|
||||
marked_expr * Scopelang.Ast.StructFieldName.t * Scopelang.Ast.StructName.t
|
||||
| EEnumInj of
|
||||
expr Pos.marked
|
||||
* Scopelang.Ast.EnumConstructor.t
|
||||
* Scopelang.Ast.EnumName.t
|
||||
marked_expr * Scopelang.Ast.EnumConstructor.t * Scopelang.Ast.EnumName.t
|
||||
| EMatch of
|
||||
expr Pos.marked
|
||||
marked_expr
|
||||
* Scopelang.Ast.EnumName.t
|
||||
* expr Pos.marked Scopelang.Ast.EnumConstructorMap.t
|
||||
* marked_expr Scopelang.Ast.EnumConstructorMap.t
|
||||
| ELit of Dcalc.Ast.lit
|
||||
| EAbs of
|
||||
(expr, expr Pos.marked) Bindlib.mbinder Pos.marked
|
||||
* Scopelang.Ast.typ Pos.marked list
|
||||
| EApp of expr Pos.marked * expr Pos.marked list
|
||||
(expr, marked_expr) Bindlib.mbinder * Scopelang.Ast.typ Marked.pos list
|
||||
| EApp of marked_expr * marked_expr list
|
||||
| EOp of Dcalc.Ast.operator
|
||||
| EDefault of expr Pos.marked list * expr Pos.marked * expr Pos.marked
|
||||
| EIfThenElse of expr Pos.marked * expr Pos.marked * expr Pos.marked
|
||||
| EArray of expr Pos.marked list
|
||||
| ErrorOnEmpty of expr Pos.marked
|
||||
| EDefault of marked_expr list * marked_expr * marked_expr
|
||||
| EIfThenElse of marked_expr * marked_expr * marked_expr
|
||||
| EArray of marked_expr list
|
||||
| ErrorOnEmpty of marked_expr
|
||||
|
||||
module ExprMap : Map.S with type key = expr
|
||||
|
||||
@ -98,7 +94,7 @@ module ExprMap : Map.S with type key = expr
|
||||
module Var : sig
|
||||
type t = expr Bindlib.var
|
||||
|
||||
val make : string Pos.marked -> t
|
||||
val make : string -> t
|
||||
val compare : t -> t -> int
|
||||
end
|
||||
|
||||
@ -106,58 +102,64 @@ module VarMap : Map.S with type key = Var.t
|
||||
|
||||
type vars = expr Bindlib.mvar
|
||||
|
||||
val make_var : Var.t Pos.marked -> expr Pos.marked Bindlib.box
|
||||
val make_var : Var.t Marked.pos -> expr Marked.pos Bindlib.box
|
||||
|
||||
val make_abs :
|
||||
vars ->
|
||||
expr Pos.marked Bindlib.box ->
|
||||
expr Marked.pos Bindlib.box ->
|
||||
Scopelang.Ast.typ Marked.pos list ->
|
||||
Pos.t ->
|
||||
Scopelang.Ast.typ Pos.marked list ->
|
||||
Pos.t ->
|
||||
expr Pos.marked Bindlib.box
|
||||
expr Marked.pos Bindlib.box
|
||||
|
||||
val make_app :
|
||||
expr Pos.marked Bindlib.box ->
|
||||
expr Pos.marked Bindlib.box list ->
|
||||
expr Marked.pos Bindlib.box ->
|
||||
expr Marked.pos Bindlib.box list ->
|
||||
Pos.t ->
|
||||
expr Pos.marked Bindlib.box
|
||||
expr Marked.pos Bindlib.box
|
||||
|
||||
val make_let_in :
|
||||
Var.t ->
|
||||
Scopelang.Ast.typ Pos.marked ->
|
||||
expr Pos.marked Bindlib.box ->
|
||||
expr Pos.marked Bindlib.box ->
|
||||
expr Pos.marked Bindlib.box
|
||||
Scopelang.Ast.typ Marked.pos ->
|
||||
expr Marked.pos Bindlib.box ->
|
||||
expr Marked.pos Bindlib.box ->
|
||||
expr Marked.pos Bindlib.box
|
||||
|
||||
(** {2 Rules and scopes}*)
|
||||
|
||||
type exception_situation =
|
||||
| BaseCase
|
||||
| ExceptionToLabel of LabelName.t Marked.pos
|
||||
| ExceptionToRule of RuleName.t Marked.pos
|
||||
|
||||
type label_situation = ExplicitlyLabeled of LabelName.t Marked.pos | Unlabeled
|
||||
|
||||
type rule = {
|
||||
rule_id : RuleName.t;
|
||||
rule_just : expr Pos.marked Bindlib.box;
|
||||
rule_cons : expr Pos.marked Bindlib.box;
|
||||
rule_parameter : (Var.t * Scopelang.Ast.typ Pos.marked) option;
|
||||
rule_exception_to_rules : RuleSet.t Pos.marked;
|
||||
rule_just : expr Marked.pos Bindlib.box;
|
||||
rule_cons : expr Marked.pos Bindlib.box;
|
||||
rule_parameter : (Var.t * Scopelang.Ast.typ Marked.pos) option;
|
||||
rule_exception : exception_situation;
|
||||
rule_label : label_situation;
|
||||
}
|
||||
|
||||
module Rule : Set.OrderedType with type t = rule
|
||||
|
||||
val empty_rule : Pos.t -> Scopelang.Ast.typ Pos.marked option -> rule
|
||||
val always_false_rule : Pos.t -> Scopelang.Ast.typ Pos.marked option -> rule
|
||||
val empty_rule : Pos.t -> Scopelang.Ast.typ Marked.pos option -> rule
|
||||
val always_false_rule : Pos.t -> Scopelang.Ast.typ Marked.pos option -> rule
|
||||
|
||||
type assertion = expr Pos.marked Bindlib.box
|
||||
type assertion = expr Marked.pos Bindlib.box
|
||||
type variation_typ = Increasing | Decreasing
|
||||
type reference_typ = Decree | Law
|
||||
|
||||
type meta_assertion =
|
||||
| FixedBy of reference_typ Pos.marked
|
||||
| VariesWith of unit * variation_typ Pos.marked option
|
||||
| FixedBy of reference_typ Marked.pos
|
||||
| VariesWith of unit * variation_typ Marked.pos option
|
||||
|
||||
type scope_def = {
|
||||
scope_def_rules : rule RuleMap.t;
|
||||
scope_def_typ : Scopelang.Ast.typ Pos.marked;
|
||||
scope_def_typ : Scopelang.Ast.typ Marked.pos;
|
||||
scope_def_is_condition : bool;
|
||||
scope_def_io : Scopelang.Ast.io;
|
||||
scope_def_label_groups : RuleSet.t LabelMap.t;
|
||||
}
|
||||
|
||||
type var_or_states = WholeVar | States of StateName.t list
|
||||
@ -179,5 +181,5 @@ type program = {
|
||||
|
||||
(** {1 Helpers} *)
|
||||
|
||||
val locations_used : expr Pos.marked -> LocationSet.t
|
||||
val locations_used : expr Marked.pos -> LocationSet.t
|
||||
val free_variables : rule RuleMap.t -> Pos.t ScopeDefMap.t
|
||||
|
@ -129,10 +129,11 @@ let check_for_cycle (scope : Ast.scope) (g : ScopeDependencies.t) : unit =
|
||||
in
|
||||
[
|
||||
( Some ("Cycle variable " ^ var_str ^ ", declared:"),
|
||||
Pos.get_position var_info );
|
||||
Marked.get_mark var_info );
|
||||
( Some
|
||||
("Used here in the definition of another cycle variable "
|
||||
^ succ_str ^ ":"),
|
||||
^ succ_str
|
||||
^ ":"),
|
||||
edge_pos );
|
||||
])
|
||||
scc)
|
||||
@ -240,8 +241,17 @@ module ExceptionVertex = struct
|
||||
let equal x y = compare x y = 0
|
||||
end
|
||||
|
||||
module EdgeExceptions = struct
|
||||
type t = Pos.t list
|
||||
|
||||
let compare = compare
|
||||
let default = [Pos.no_pos]
|
||||
end
|
||||
|
||||
module ExceptionsDependencies =
|
||||
Graph.Persistent.Digraph.ConcreteBidirectionalLabeled (ExceptionVertex) (Edge)
|
||||
Graph.Persistent.Digraph.ConcreteBidirectionalLabeled
|
||||
(ExceptionVertex)
|
||||
(EdgeExceptions)
|
||||
(** Module of the graph, provided by OCamlGraph. [x -> y] if [y] is an exception
|
||||
to [x] *)
|
||||
|
||||
@ -250,95 +260,190 @@ module ExceptionsSCC = Graph.Components.Make (ExceptionsDependencies)
|
||||
|
||||
(** {2 Graph computations} *)
|
||||
|
||||
type exception_edge = {
|
||||
label_from : Ast.LabelName.t;
|
||||
label_to : Ast.LabelName.t;
|
||||
edge_positions : Pos.t list;
|
||||
}
|
||||
|
||||
let build_exceptions_graph
|
||||
(def : Ast.rule Ast.RuleMap.t)
|
||||
(def_info : Ast.ScopeDef.t) : ExceptionsDependencies.t =
|
||||
(* first we collect all the rule sets referred by exceptions *)
|
||||
let all_rule_sets_pointed_to_by_exceptions : Ast.RuleSet.t list =
|
||||
(* First we partition the definitions into groups bearing the same label. To
|
||||
handle the rules that were not labeled by the user, we create implicit
|
||||
labels. *)
|
||||
|
||||
(* All the rules of the form [definition x ...] are base case with no explicit
|
||||
label, so they should share this implicit label. *)
|
||||
let base_case_implicit_label =
|
||||
Ast.LabelName.fresh ("base_case", Pos.no_pos)
|
||||
in
|
||||
(* When declaring [exception definition x ...], it means there is a unique
|
||||
rule [R] to which this can be an exception to. So we give a unique label to
|
||||
all the rules that are implicitly exceptions to rule [R]. *)
|
||||
let exception_to_rule_implicit_labels : Ast.LabelName.t Ast.RuleMap.t =
|
||||
Ast.RuleMap.fold
|
||||
(fun _rule_name rule acc ->
|
||||
if Ast.RuleSet.is_empty (Pos.unmark rule.Ast.rule_exception_to_rules)
|
||||
then acc
|
||||
else Pos.unmark rule.Ast.rule_exception_to_rules :: acc)
|
||||
(fun _ rule_from exception_to_rule_implicit_labels ->
|
||||
match rule_from.Ast.rule_exception with
|
||||
| Ast.ExceptionToRule (rule_to, _) -> (
|
||||
match
|
||||
Ast.RuleMap.find_opt rule_to exception_to_rule_implicit_labels
|
||||
with
|
||||
| Some _ ->
|
||||
(* we already created the label *) exception_to_rule_implicit_labels
|
||||
| None ->
|
||||
Ast.RuleMap.add rule_to
|
||||
(Ast.LabelName.fresh
|
||||
( "exception_to_"
|
||||
^ Marked.unmark (Ast.RuleName.get_info rule_to),
|
||||
Pos.no_pos ))
|
||||
exception_to_rule_implicit_labels)
|
||||
| _ -> exception_to_rule_implicit_labels)
|
||||
def Ast.RuleMap.empty
|
||||
in
|
||||
(* When declaring [exception foo_l definition x ...], the rule is exception to
|
||||
all the rules sharing label [foo_l]. So we give a unique label to all the
|
||||
rules that are implicitly exceptions to rule [foo_l]. *)
|
||||
let exception_to_label_implicit_labels : Ast.LabelName.t Ast.LabelMap.t =
|
||||
Ast.RuleMap.fold
|
||||
(fun _ rule_from
|
||||
(exception_to_label_implicit_labels : Ast.LabelName.t Ast.LabelMap.t) ->
|
||||
match rule_from.Ast.rule_exception with
|
||||
| Ast.ExceptionToLabel (label_to, _) -> (
|
||||
match
|
||||
Ast.LabelMap.find_opt label_to exception_to_label_implicit_labels
|
||||
with
|
||||
| Some _ ->
|
||||
(* we already created the label *)
|
||||
exception_to_label_implicit_labels
|
||||
| None ->
|
||||
Ast.LabelMap.add label_to
|
||||
(Ast.LabelName.fresh
|
||||
( "exception_to_"
|
||||
^ Marked.unmark (Ast.LabelName.get_info label_to),
|
||||
Pos.no_pos ))
|
||||
exception_to_label_implicit_labels)
|
||||
| _ -> exception_to_label_implicit_labels)
|
||||
def Ast.LabelMap.empty
|
||||
in
|
||||
|
||||
(* Now we have all the labels necessary to partition our rules into sets, each
|
||||
one corresponding to a label relating to the structure of the exception
|
||||
DAG. *)
|
||||
let label_to_rule_sets =
|
||||
Ast.RuleMap.fold
|
||||
(fun rule_name rule rule_sets ->
|
||||
let label_of_rule =
|
||||
match rule.Ast.rule_label with
|
||||
| Ast.ExplicitlyLabeled (l, _) -> l
|
||||
| Ast.Unlabeled -> (
|
||||
match rule.Ast.rule_exception with
|
||||
| BaseCase -> base_case_implicit_label
|
||||
| ExceptionToRule (r, _) ->
|
||||
Ast.RuleMap.find r exception_to_rule_implicit_labels
|
||||
| ExceptionToLabel (l', _) ->
|
||||
Ast.LabelMap.find l' exception_to_label_implicit_labels)
|
||||
in
|
||||
Ast.LabelMap.update label_of_rule
|
||||
(fun rule_set ->
|
||||
match rule_set with
|
||||
| None -> Some (Ast.RuleSet.singleton rule_name)
|
||||
| Some rule_set -> Some (Ast.RuleSet.add rule_name rule_set))
|
||||
rule_sets)
|
||||
def Ast.LabelMap.empty
|
||||
in
|
||||
let find_label_of_rule (r : Ast.RuleName.t) : Ast.LabelName.t =
|
||||
fst
|
||||
(Ast.LabelMap.choose
|
||||
(Ast.LabelMap.filter
|
||||
(fun _ rule_set -> Ast.RuleSet.mem r rule_set)
|
||||
label_to_rule_sets))
|
||||
in
|
||||
(* Next, we collect the exception edges between those groups of rules referred
|
||||
by their labels. This is also at this step that we check consistency of the
|
||||
edges as they are declared at each rule but should be the same for all the
|
||||
rules of the same group. *)
|
||||
let exception_edges : exception_edge list =
|
||||
Ast.RuleMap.fold
|
||||
(fun rule_name rule exception_edges ->
|
||||
let label_from = find_label_of_rule rule_name in
|
||||
let label_to_and_pos =
|
||||
match rule.Ast.rule_exception with
|
||||
| Ast.BaseCase -> None
|
||||
| Ast.ExceptionToRule (r', pos) -> Some (find_label_of_rule r', pos)
|
||||
| Ast.ExceptionToLabel (l', pos) -> Some (l', pos)
|
||||
in
|
||||
match label_to_and_pos with
|
||||
| None -> exception_edges
|
||||
| Some (label_to, edge_pos) -> (
|
||||
let other_edges_originating_from_same_label =
|
||||
List.filter
|
||||
(fun edge -> Ast.LabelName.compare edge.label_from label_from = 0)
|
||||
exception_edges
|
||||
in
|
||||
(* We check the consistency*)
|
||||
if Ast.LabelName.compare label_from label_to = 0 then
|
||||
Errors.raise_spanned_error edge_pos
|
||||
"Cannot define rule as an exception to itself";
|
||||
List.iter
|
||||
(fun edge ->
|
||||
if Ast.LabelName.compare edge.label_to label_to <> 0 then
|
||||
Errors.raise_multispanned_error
|
||||
(( Some
|
||||
"This declaration contradicts another exception \
|
||||
declarations:",
|
||||
edge_pos )
|
||||
:: List.map
|
||||
(fun pos ->
|
||||
Some "Here is another exception declaration:", pos)
|
||||
edge.edge_positions)
|
||||
"The declaration of exceptions are inconsistent for variable \
|
||||
%a."
|
||||
Ast.ScopeDef.format_t def_info)
|
||||
other_edges_originating_from_same_label;
|
||||
(* Now we add the edge to the list*)
|
||||
let existing_edge =
|
||||
List.find_opt
|
||||
(fun edge ->
|
||||
Ast.LabelName.compare edge.label_from label_from = 0
|
||||
&& Ast.LabelName.compare edge.label_to label_to = 0)
|
||||
exception_edges
|
||||
in
|
||||
match existing_edge with
|
||||
| None ->
|
||||
{ label_from; label_to; edge_positions = [edge_pos] }
|
||||
:: exception_edges
|
||||
| Some existing_edge ->
|
||||
{
|
||||
label_from;
|
||||
label_to;
|
||||
edge_positions = edge_pos :: existing_edge.edge_positions;
|
||||
}
|
||||
:: List.filter (fun edge -> edge <> existing_edge) exception_edges))
|
||||
def []
|
||||
in
|
||||
(* we make sure these sets are either disjoint or equal ; should be a
|
||||
syntactic invariant since you currently can't assign two labels to a single
|
||||
rule but an extra check is valuable since this is a required invariant for
|
||||
the graph to be sound *)
|
||||
List.iter
|
||||
(fun rule_set1 ->
|
||||
List.iter
|
||||
(fun rule_set2 ->
|
||||
if Ast.RuleSet.equal rule_set1 rule_set2 then ()
|
||||
else if Ast.RuleSet.disjoint rule_set1 rule_set2 then ()
|
||||
else
|
||||
let spans =
|
||||
List.of_seq
|
||||
(Seq.map
|
||||
(fun rule ->
|
||||
( Some "Rule or definition from the first group:",
|
||||
Pos.get_position (Ast.RuleName.get_info rule) ))
|
||||
(Ast.RuleSet.to_seq rule_set1))
|
||||
@ List.of_seq
|
||||
(Seq.map
|
||||
(fun rule ->
|
||||
( Some "Rule or definition from the second group:",
|
||||
Pos.get_position (Ast.RuleName.get_info rule) ))
|
||||
(Ast.RuleSet.to_seq rule_set2))
|
||||
in
|
||||
Errors.raise_multispanned_error spans
|
||||
"Definitions or rules grouped by different labels overlap, \
|
||||
whereas these groups shoule be disjoint")
|
||||
all_rule_sets_pointed_to_by_exceptions)
|
||||
all_rule_sets_pointed_to_by_exceptions;
|
||||
(* Then we add the exception graph vertices by taking all those sets of rules
|
||||
pointed to by exceptions, and adding the remaining rules not pointed as
|
||||
separate singleton set vertices *)
|
||||
(* We've got the vertices and the edges, let's build the graph! *)
|
||||
let g =
|
||||
List.fold_left
|
||||
(fun g rule_set -> ExceptionsDependencies.add_vertex g rule_set)
|
||||
ExceptionsDependencies.empty all_rule_sets_pointed_to_by_exceptions
|
||||
in
|
||||
let g =
|
||||
Ast.RuleMap.fold
|
||||
(fun (rule_name : Ast.RuleName.t) _ g ->
|
||||
if
|
||||
List.exists
|
||||
(fun rule_set_pointed_to_by_exceptions ->
|
||||
Ast.RuleSet.mem rule_name rule_set_pointed_to_by_exceptions)
|
||||
all_rule_sets_pointed_to_by_exceptions
|
||||
then g
|
||||
else
|
||||
ExceptionsDependencies.add_vertex g (Ast.RuleSet.singleton rule_name))
|
||||
def g
|
||||
Ast.LabelMap.fold
|
||||
(fun _label rule_set g -> ExceptionsDependencies.add_vertex g rule_set)
|
||||
label_to_rule_sets ExceptionsDependencies.empty
|
||||
in
|
||||
(* then we add the edges *)
|
||||
let g =
|
||||
Ast.RuleMap.fold
|
||||
(fun rule_name rule g ->
|
||||
(* Right now, exceptions can only consist of one rule, we may want to
|
||||
relax that constraint later in the development of Catala. *)
|
||||
let exception_to_ruleset, pos = rule.Ast.rule_exception_to_rules in
|
||||
if Ast.RuleSet.is_empty exception_to_ruleset then g
|
||||
(* we don't add an edge*)
|
||||
else if ExceptionsDependencies.mem_vertex g exception_to_ruleset then
|
||||
if exception_to_ruleset = Ast.RuleSet.singleton rule_name then
|
||||
Errors.raise_spanned_error pos
|
||||
"Cannot define rule as an exception to itself"
|
||||
else
|
||||
let edge =
|
||||
ExceptionsDependencies.E.create
|
||||
(Ast.RuleSet.singleton rule_name)
|
||||
pos exception_to_ruleset
|
||||
in
|
||||
ExceptionsDependencies.add_edge_e g edge
|
||||
else
|
||||
Errors.raise_spanned_error pos
|
||||
"This rule has been declared as an exception to an incorrect \
|
||||
label: this label is not attached to a definition of \"%a\""
|
||||
Ast.ScopeDef.format_t def_info)
|
||||
def g
|
||||
List.fold_left
|
||||
(fun g edge ->
|
||||
let rule_group_from =
|
||||
Ast.LabelMap.find edge.label_from label_to_rule_sets
|
||||
in
|
||||
let rule_group_to =
|
||||
Ast.LabelMap.find edge.label_to label_to_rule_sets
|
||||
in
|
||||
let edge =
|
||||
ExceptionsDependencies.E.create rule_group_from edge.edge_positions
|
||||
rule_group_to
|
||||
in
|
||||
ExceptionsDependencies.add_edge_e g edge)
|
||||
g exception_edges
|
||||
in
|
||||
g
|
||||
|
||||
@ -364,13 +469,16 @@ let check_for_exception_cycle (g : ExceptionsDependencies.t) : unit =
|
||||
in
|
||||
[
|
||||
( Some
|
||||
("Cyclic exception for definition of variable \"" ^ var_str
|
||||
^ "\", declared here:"),
|
||||
Pos.get_position var_info );
|
||||
("Cyclic exception for definition of variable \""
|
||||
^ var_str
|
||||
^ "\", declared here:"),
|
||||
Marked.get_mark var_info );
|
||||
( Some
|
||||
("Used here in the definition of another cyclic exception \
|
||||
for defining \"" ^ var_str ^ "\":"),
|
||||
edge_pos );
|
||||
for defining \""
|
||||
^ var_str
|
||||
^ "\":"),
|
||||
List.hd edge_pos );
|
||||
])
|
||||
scc)
|
||||
in
|
||||
|
@ -68,8 +68,10 @@ val build_scope_dependencies : Ast.scope -> ScopeDependencies.t
|
||||
|
||||
(** {1 Exceptions dependency graph} *)
|
||||
|
||||
module EdgeExceptions : Graph.Sig.ORDERED_TYPE_DFT with type t = Pos.t list
|
||||
|
||||
module ExceptionsDependencies :
|
||||
Graph.Sig.P with type V.t = Ast.RuleSet.t and type E.label = Edge.t
|
||||
Graph.Sig.P with type V.t = Ast.RuleSet.t and type E.label = EdgeExceptions.t
|
||||
|
||||
val build_exceptions_graph :
|
||||
Ast.rule Ast.RuleMap.t -> Ast.ScopeDef.t -> ExceptionsDependencies.t
|
||||
|
@ -30,84 +30,83 @@ type ctx = {
|
||||
}
|
||||
|
||||
let tag_with_log_entry
|
||||
(e : Scopelang.Ast.expr Pos.marked)
|
||||
(e : Scopelang.Ast.expr Marked.pos)
|
||||
(l : Dcalc.Ast.log_entry)
|
||||
(markings : Utils.Uid.MarkedString.info list) :
|
||||
Scopelang.Ast.expr Pos.marked =
|
||||
Scopelang.Ast.expr Marked.pos =
|
||||
( Scopelang.Ast.EApp
|
||||
( ( Scopelang.Ast.EOp (Dcalc.Ast.Unop (Dcalc.Ast.Log (l, markings))),
|
||||
Pos.get_position e ),
|
||||
Marked.get_mark e ),
|
||||
[e] ),
|
||||
Pos.get_position e )
|
||||
Marked.get_mark e )
|
||||
|
||||
let rec translate_expr (ctx : ctx) (e : Ast.expr Pos.marked) :
|
||||
Scopelang.Ast.expr Pos.marked Bindlib.box =
|
||||
match Pos.unmark e with
|
||||
let rec translate_expr (ctx : ctx) (e : Ast.expr Marked.pos) :
|
||||
Scopelang.Ast.expr Marked.pos Bindlib.box =
|
||||
let m = Marked.get_mark e in
|
||||
match Marked.unmark e with
|
||||
| Ast.ELocation (SubScopeVar (s_name, ss_name, s_var)) ->
|
||||
(* When referring to a subscope variable in an expression, we are referring
|
||||
to the output, hence we take the last state. *)
|
||||
let new_s_var =
|
||||
match Ast.ScopeVarMap.find (Pos.unmark s_var) ctx.scope_var_mapping with
|
||||
| WholeVar new_s_var -> Pos.same_pos_as new_s_var s_var
|
||||
| States states -> Pos.same_pos_as (snd (List.hd (List.rev states))) s_var
|
||||
match
|
||||
Ast.ScopeVarMap.find (Marked.unmark s_var) ctx.scope_var_mapping
|
||||
with
|
||||
| WholeVar new_s_var -> Marked.same_mark_as new_s_var s_var
|
||||
| States states ->
|
||||
Marked.same_mark_as (snd (List.hd (List.rev states))) s_var
|
||||
in
|
||||
Bindlib.box
|
||||
( Scopelang.Ast.ELocation (SubScopeVar (s_name, ss_name, new_s_var)),
|
||||
Pos.get_position e )
|
||||
(Scopelang.Ast.ELocation (SubScopeVar (s_name, ss_name, new_s_var)), m)
|
||||
| Ast.ELocation (ScopeVar (s_var, None)) ->
|
||||
Bindlib.box
|
||||
( Scopelang.Ast.ELocation
|
||||
(ScopeVar
|
||||
(match
|
||||
Ast.ScopeVarMap.find (Pos.unmark s_var) ctx.scope_var_mapping
|
||||
Ast.ScopeVarMap.find (Marked.unmark s_var) ctx.scope_var_mapping
|
||||
with
|
||||
| WholeVar new_s_var -> Pos.same_pos_as new_s_var s_var
|
||||
| WholeVar new_s_var -> Marked.same_mark_as new_s_var s_var
|
||||
| States _ -> failwith "should not happen")),
|
||||
Pos.get_position e )
|
||||
m )
|
||||
| Ast.ELocation (ScopeVar (s_var, Some state)) ->
|
||||
Bindlib.box
|
||||
( Scopelang.Ast.ELocation
|
||||
(ScopeVar
|
||||
(match
|
||||
Ast.ScopeVarMap.find (Pos.unmark s_var) ctx.scope_var_mapping
|
||||
Ast.ScopeVarMap.find (Marked.unmark s_var) ctx.scope_var_mapping
|
||||
with
|
||||
| WholeVar _ -> failwith "should not happen"
|
||||
| States states -> Pos.same_pos_as (List.assoc state states) s_var)),
|
||||
Pos.get_position e )
|
||||
| States states ->
|
||||
Marked.same_mark_as (List.assoc state states) s_var)),
|
||||
m )
|
||||
| Ast.EVar v ->
|
||||
Bindlib.box_apply
|
||||
(fun v -> Pos.same_pos_as v e)
|
||||
(Bindlib.box_var (Ast.VarMap.find (Pos.unmark v) ctx.var_mapping))
|
||||
(fun v -> Marked.same_mark_as v e)
|
||||
(Bindlib.box_var (Ast.VarMap.find v ctx.var_mapping))
|
||||
| EStruct (s_name, fields) ->
|
||||
Bindlib.box_apply
|
||||
(fun new_fields ->
|
||||
Scopelang.Ast.EStruct (s_name, new_fields), Pos.get_position e)
|
||||
(fun new_fields -> Scopelang.Ast.EStruct (s_name, new_fields), m)
|
||||
(Scopelang.Ast.StructFieldMapLift.lift_box
|
||||
(Scopelang.Ast.StructFieldMap.map (translate_expr ctx) fields))
|
||||
| EStructAccess (e1, s_name, f_name) ->
|
||||
Bindlib.box_apply
|
||||
(fun new_e1 ->
|
||||
Scopelang.Ast.EStructAccess (new_e1, s_name, f_name), Pos.get_position e)
|
||||
(fun new_e1 -> Scopelang.Ast.EStructAccess (new_e1, s_name, f_name), m)
|
||||
(translate_expr ctx e1)
|
||||
| EEnumInj (e1, cons, e_name) ->
|
||||
Bindlib.box_apply
|
||||
(fun new_e1 ->
|
||||
Scopelang.Ast.EEnumInj (new_e1, cons, e_name), Pos.get_position e)
|
||||
(fun new_e1 -> Scopelang.Ast.EEnumInj (new_e1, cons, e_name), m)
|
||||
(translate_expr ctx e1)
|
||||
| EMatch (e1, e_name, arms) ->
|
||||
Bindlib.box_apply2
|
||||
(fun new_e1 new_arms ->
|
||||
Scopelang.Ast.EMatch (new_e1, e_name, new_arms), Pos.get_position e)
|
||||
Scopelang.Ast.EMatch (new_e1, e_name, new_arms), m)
|
||||
(translate_expr ctx e1)
|
||||
(Scopelang.Ast.EnumConstructorMapLift.lift_box
|
||||
(Scopelang.Ast.EnumConstructorMap.map (translate_expr ctx) arms))
|
||||
| ELit l -> Bindlib.box (Scopelang.Ast.ELit l, Pos.get_position e)
|
||||
| EAbs ((binder, binder_pos), typs) ->
|
||||
| ELit l -> Bindlib.box (Scopelang.Ast.ELit l, m)
|
||||
| EAbs (binder, typs) ->
|
||||
let vars, body = Bindlib.unmbind binder in
|
||||
let new_vars =
|
||||
Array.map
|
||||
(fun var -> Scopelang.Ast.Var.make (Bindlib.name_of var, binder_pos))
|
||||
vars
|
||||
Array.map (fun var -> Scopelang.Ast.Var.make (Bindlib.name_of var)) vars
|
||||
in
|
||||
let ctx =
|
||||
List.fold_left2
|
||||
@ -116,35 +115,32 @@ let rec translate_expr (ctx : ctx) (e : Ast.expr Pos.marked) :
|
||||
ctx (Array.to_list vars) (Array.to_list new_vars)
|
||||
in
|
||||
Bindlib.box_apply
|
||||
(fun new_binder ->
|
||||
Scopelang.Ast.EAbs ((new_binder, binder_pos), typs), Pos.get_position e)
|
||||
(fun new_binder -> Scopelang.Ast.EAbs (new_binder, typs), m)
|
||||
(Bindlib.bind_mvar new_vars (translate_expr ctx body))
|
||||
| EApp (e1, args) ->
|
||||
Bindlib.box_apply2
|
||||
(fun new_e1 new_args ->
|
||||
Scopelang.Ast.EApp (new_e1, new_args), Pos.get_position e)
|
||||
(fun new_e1 new_args -> Scopelang.Ast.EApp (new_e1, new_args), m)
|
||||
(translate_expr ctx e1)
|
||||
(Bindlib.box_list (List.map (translate_expr ctx) args))
|
||||
| EOp op -> Bindlib.box (Scopelang.Ast.EOp op, Pos.get_position e)
|
||||
| EOp op -> Bindlib.box (Scopelang.Ast.EOp op, m)
|
||||
| EDefault (excepts, just, cons) ->
|
||||
Bindlib.box_apply3
|
||||
(fun new_excepts new_just new_cons ->
|
||||
Scopelang.Ast.make_default ~pos:(Pos.get_position e) new_excepts
|
||||
new_just new_cons)
|
||||
Scopelang.Ast.make_default ~pos:m new_excepts new_just new_cons)
|
||||
(Bindlib.box_list (List.map (translate_expr ctx) excepts))
|
||||
(translate_expr ctx just) (translate_expr ctx cons)
|
||||
| EIfThenElse (e1, e2, e3) ->
|
||||
Bindlib.box_apply3
|
||||
(fun new_e1 new_e2 new_e3 ->
|
||||
Scopelang.Ast.EIfThenElse (new_e1, new_e2, new_e3), Pos.get_position e)
|
||||
Scopelang.Ast.EIfThenElse (new_e1, new_e2, new_e3), m)
|
||||
(translate_expr ctx e1) (translate_expr ctx e2) (translate_expr ctx e3)
|
||||
| EArray args ->
|
||||
Bindlib.box_apply
|
||||
(fun new_args -> Scopelang.Ast.EArray new_args, Pos.get_position e)
|
||||
(fun new_args -> Scopelang.Ast.EArray new_args, m)
|
||||
(Bindlib.box_list (List.map (translate_expr ctx) args))
|
||||
| ErrorOnEmpty e1 ->
|
||||
Bindlib.box_apply
|
||||
(fun new_e1 -> Scopelang.Ast.ErrorOnEmpty new_e1, Pos.get_position e)
|
||||
(fun new_e1 -> Scopelang.Ast.ErrorOnEmpty new_e1, m)
|
||||
(translate_expr ctx e1)
|
||||
|
||||
(** {1 Rule tree construction} *)
|
||||
@ -155,8 +151,8 @@ type rule_tree =
|
||||
| Leaf of Ast.rule list
|
||||
(** Rules defining a base case piecewise. List is non-empty. *)
|
||||
| Node of rule_tree list * Ast.rule list
|
||||
(** A list of exceptions to a non-empty list of rules defining a base case
|
||||
piecewise. *)
|
||||
(** [Node (exceptions, base_case)] is a list of exceptions to a non-empty
|
||||
list of rules defining a base case piecewise. *)
|
||||
|
||||
(** Transforms a flat list of rules into a tree, taking into account the
|
||||
priorities declared between rules *)
|
||||
@ -197,7 +193,7 @@ let rec rule_tree_to_expr
|
||||
(ctx : ctx)
|
||||
(def_pos : Pos.t)
|
||||
(is_func : Ast.Var.t option)
|
||||
(tree : rule_tree) : Scopelang.Ast.expr Pos.marked Bindlib.box =
|
||||
(tree : rule_tree) : Scopelang.Ast.expr Marked.pos Bindlib.box =
|
||||
let exceptions, base_rules =
|
||||
match tree with Leaf r -> [], r | Node (exceptions, r) -> exceptions, r
|
||||
in
|
||||
@ -205,8 +201,8 @@ let rec rule_tree_to_expr
|
||||
whole rule tree into a function, we need to perform some alpha-renaming of
|
||||
all the expressions *)
|
||||
let substitute_parameter
|
||||
(e : Ast.expr Pos.marked Bindlib.box)
|
||||
(rule : Ast.rule) : Ast.expr Pos.marked Bindlib.box =
|
||||
(e : Ast.expr Marked.pos Bindlib.box)
|
||||
(rule : Ast.rule) : Ast.expr Marked.pos Bindlib.box =
|
||||
match is_func, rule.Ast.rule_parameter with
|
||||
| Some new_param, Some (old_param, _) ->
|
||||
let binder = Bindlib.bind_var old_param e in
|
||||
@ -225,7 +221,7 @@ let rec rule_tree_to_expr
|
||||
match Ast.VarMap.find_opt new_param ctx.var_mapping with
|
||||
| None ->
|
||||
let new_param_scope =
|
||||
Scopelang.Ast.Var.make (Bindlib.name_of new_param, def_pos)
|
||||
Scopelang.Ast.Var.make (Bindlib.name_of new_param)
|
||||
in
|
||||
{
|
||||
ctx with
|
||||
@ -248,8 +244,8 @@ let rec rule_tree_to_expr
|
||||
(fun rule -> substitute_parameter rule.Ast.rule_cons rule)
|
||||
base_rules
|
||||
in
|
||||
let translate_and_unbox_list (list : Ast.expr Pos.marked Bindlib.box list) :
|
||||
Scopelang.Ast.expr Pos.marked Bindlib.box list =
|
||||
let translate_and_unbox_list (list : Ast.expr Marked.pos Bindlib.box list) :
|
||||
Scopelang.Ast.expr Marked.pos Bindlib.box list =
|
||||
List.map
|
||||
(fun e ->
|
||||
(* There are two levels of boxing here, the outermost is introduced by
|
||||
@ -303,7 +299,7 @@ let rec rule_tree_to_expr
|
||||
in
|
||||
Scopelang.Ast.make_abs
|
||||
(Array.of_list [Ast.VarMap.find new_param ctx.var_mapping])
|
||||
default def_pos [typ] def_pos
|
||||
default [typ] def_pos
|
||||
else default
|
||||
| _ -> (* should not happen *) assert false
|
||||
|
||||
@ -315,13 +311,15 @@ let translate_def
|
||||
(ctx : ctx)
|
||||
(def_info : Ast.ScopeDef.t)
|
||||
(def : Ast.rule Ast.RuleMap.t)
|
||||
(typ : Scopelang.Ast.typ Pos.marked)
|
||||
(typ : Scopelang.Ast.typ Marked.pos)
|
||||
(io : Scopelang.Ast.io)
|
||||
~(is_cond : bool)
|
||||
~(is_subscope_var : bool) : Scopelang.Ast.expr Pos.marked =
|
||||
~(is_subscope_var : bool) : Scopelang.Ast.expr Marked.pos =
|
||||
(* Here, we have to transform this list of rules into a default tree. *)
|
||||
let is_def_func =
|
||||
match Pos.unmark typ with Scopelang.Ast.TArrow (_, _) -> true | _ -> false
|
||||
match Marked.unmark typ with
|
||||
| Scopelang.Ast.TArrow (_, _) -> true
|
||||
| _ -> false
|
||||
in
|
||||
let is_rule_func _ (r : Ast.rule) : bool =
|
||||
Option.is_some r.Ast.rule_parameter
|
||||
@ -330,12 +328,12 @@ let translate_def
|
||||
let all_rules_not_func =
|
||||
Ast.RuleMap.for_all (fun n r -> not (is_rule_func n r)) def
|
||||
in
|
||||
let is_def_func_param_typ : Scopelang.Ast.typ Pos.marked option =
|
||||
let is_def_func_param_typ : Scopelang.Ast.typ Marked.pos option =
|
||||
if is_def_func && all_rules_func then
|
||||
match Pos.unmark typ with
|
||||
match Marked.unmark typ with
|
||||
| Scopelang.Ast.TArrow (t_param, _) -> Some t_param
|
||||
| _ ->
|
||||
Errors.raise_spanned_error (Pos.get_position typ)
|
||||
Errors.raise_spanned_error (Marked.get_mark typ)
|
||||
"The definitions of %a are function but its type, %a, is not a \
|
||||
function type"
|
||||
Ast.ScopeDef.format_t def_info Scopelang.Print.format_typ typ
|
||||
@ -345,12 +343,12 @@ let translate_def
|
||||
List.map
|
||||
(fun (_, r) ->
|
||||
( Some "This definition is a function:",
|
||||
Pos.get_position (Bindlib.unbox r.Ast.rule_cons) ))
|
||||
Marked.get_mark (Bindlib.unbox r.Ast.rule_cons) ))
|
||||
(Ast.RuleMap.bindings (Ast.RuleMap.filter is_rule_func def))
|
||||
@ List.map
|
||||
(fun (_, r) ->
|
||||
( Some "This definition is not a function:",
|
||||
Pos.get_position (Bindlib.unbox r.Ast.rule_cons) ))
|
||||
Marked.get_mark (Bindlib.unbox r.Ast.rule_cons) ))
|
||||
(Ast.RuleMap.bindings
|
||||
(Ast.RuleMap.filter (fun n r -> not (is_rule_func n r)) def))
|
||||
in
|
||||
@ -360,8 +358,12 @@ let translate_def
|
||||
in
|
||||
let top_list = def_map_to_tree def_info def in
|
||||
let top_value =
|
||||
(if is_cond then Ast.always_false_rule else Ast.empty_rule)
|
||||
(Pos.get_position typ) is_def_func_param_typ
|
||||
if is_cond then
|
||||
Some
|
||||
(Ast.always_false_rule
|
||||
(Ast.ScopeDef.get_position def_info)
|
||||
is_def_func_param_typ)
|
||||
else None
|
||||
in
|
||||
if
|
||||
Ast.RuleMap.cardinal def = 0
|
||||
@ -386,27 +388,37 @@ let translate_def
|
||||
&& not
|
||||
(is_cond
|
||||
&&
|
||||
match Pos.unmark io.Scopelang.Ast.io_input with
|
||||
match Marked.unmark io.Scopelang.Ast.io_input with
|
||||
| OnlyInput -> true
|
||||
| _ -> false)
|
||||
(* However, this special case suffers from an exception: when a condition is
|
||||
defined as an OnlyInput to a subscope, since the [false] default value
|
||||
will not be provided by the calee scope, it has to be placed in the
|
||||
caller. *)
|
||||
then ELit LEmptyError, Pos.no_pos
|
||||
then ELit LEmptyError, Ast.ScopeDef.get_position def_info
|
||||
else
|
||||
Bindlib.unbox
|
||||
(rule_tree_to_expr ~toplevel:true ctx
|
||||
(Ast.ScopeDef.get_position def_info)
|
||||
(Option.map
|
||||
(fun _ ->
|
||||
Ast.Var.make ("param", Ast.ScopeDef.get_position def_info))
|
||||
is_def_func_param_typ)
|
||||
(match top_list with
|
||||
| [] ->
|
||||
(* In this case, there are no rules to define the expression *)
|
||||
(Option.map (fun _ -> Ast.Var.make "param") is_def_func_param_typ)
|
||||
(match top_list, top_value with
|
||||
| [], None ->
|
||||
(* In this case, there are no rules to define the expression and no
|
||||
default value so we put an empty rule. *)
|
||||
Leaf [Ast.empty_rule (Marked.get_mark typ) is_def_func_param_typ]
|
||||
| [], Some top_value ->
|
||||
(* In this case, there are no rules to define the expression but a
|
||||
default value so we put it. *)
|
||||
Leaf [top_value]
|
||||
| _ -> Node (top_list, [top_value])))
|
||||
| _, Some top_value ->
|
||||
(* When there are rules + a default value, we put the rules as
|
||||
exceptions to the default value *)
|
||||
Node (top_list, [top_value])
|
||||
| [top_tree], None -> top_tree
|
||||
| _, None ->
|
||||
Node
|
||||
( top_list,
|
||||
[Ast.empty_rule (Marked.get_mark typ) is_def_func_param_typ] )))
|
||||
|
||||
(** Translates a scope *)
|
||||
let translate_scope (ctx : ctx) (scope : Ast.scope) : Scopelang.Ast.scope_decl =
|
||||
@ -429,17 +441,17 @@ let translate_scope (ctx : ctx) (scope : Ast.scope) : Scopelang.Ast.scope_decl =
|
||||
let var_def = scope_def.scope_def_rules in
|
||||
let var_typ = scope_def.scope_def_typ in
|
||||
let is_cond = scope_def.scope_def_is_condition in
|
||||
match Pos.unmark scope_def.Ast.scope_def_io.io_input with
|
||||
match Marked.unmark scope_def.Ast.scope_def_io.io_input with
|
||||
| OnlyInput when not (Ast.RuleMap.is_empty var_def) ->
|
||||
(* If the variable is tagged as input, then it shall not be
|
||||
redefined. *)
|
||||
Errors.raise_multispanned_error
|
||||
(( Some "Incriminated variable:",
|
||||
Pos.get_position (Ast.ScopeVar.get_info var) )
|
||||
Marked.get_mark (Ast.ScopeVar.get_info var) )
|
||||
:: List.map
|
||||
(fun (rule, _) ->
|
||||
( Some "Incriminated variable definition:",
|
||||
Pos.get_position (Ast.RuleName.get_info rule) ))
|
||||
Marked.get_mark (Ast.RuleName.get_info rule) ))
|
||||
(Ast.RuleMap.bindings var_def))
|
||||
"It is impossible to give a definition to a scope variable \
|
||||
tagged as input."
|
||||
@ -465,9 +477,9 @@ let translate_scope (ctx : ctx) (scope : Ast.scope) : Scopelang.Ast.scope_decl =
|
||||
Scopelang.Ast.Definition
|
||||
( ( Scopelang.Ast.ScopeVar
|
||||
( scope_var,
|
||||
Pos.get_position
|
||||
Marked.get_mark
|
||||
(Scopelang.Ast.ScopeVar.get_info scope_var) ),
|
||||
Pos.get_position
|
||||
Marked.get_mark
|
||||
(Scopelang.Ast.ScopeVar.get_info scope_var) ),
|
||||
var_typ,
|
||||
scope_def.Ast.scope_def_io,
|
||||
@ -491,7 +503,7 @@ let translate_scope (ctx : ctx) (scope : Ast.scope) : Scopelang.Ast.scope_decl =
|
||||
and are not visible in the input of the subscope *)
|
||||
&& not
|
||||
((match
|
||||
Pos.unmark scope_def.Ast.scope_def_io.io_input
|
||||
Marked.unmark scope_def.Ast.scope_def_io.io_input
|
||||
with
|
||||
| Scopelang.Ast.NoInput -> true
|
||||
| _ -> false)
|
||||
@ -511,20 +523,21 @@ let translate_scope (ctx : ctx) (scope : Ast.scope) : Scopelang.Ast.scope_decl =
|
||||
subscope. But we have to check that this redefinition is
|
||||
allowed with respect to the io parameters of that
|
||||
subscope variable. *)
|
||||
(match Pos.unmark scope_def.Ast.scope_def_io.io_input with
|
||||
(match
|
||||
Marked.unmark scope_def.Ast.scope_def_io.io_input
|
||||
with
|
||||
| Scopelang.Ast.NoInput ->
|
||||
Errors.raise_multispanned_error
|
||||
(( Some "Incriminated subscope:",
|
||||
Ast.ScopeDef.get_position def_key )
|
||||
:: ( Some "Incriminated variable:",
|
||||
Pos.get_position
|
||||
Marked.get_mark
|
||||
(Ast.ScopeVar.get_info sub_scope_var) )
|
||||
:: List.map
|
||||
(fun (rule, _) ->
|
||||
( Some
|
||||
"Incriminated subscope variable definition:",
|
||||
Pos.get_position (Ast.RuleName.get_info rule)
|
||||
))
|
||||
Marked.get_mark (Ast.RuleName.get_info rule) ))
|
||||
(Ast.RuleMap.bindings def))
|
||||
"It is impossible to give a definition to a subscope \
|
||||
variable not tagged as input or context."
|
||||
@ -536,7 +549,7 @@ let translate_scope (ctx : ctx) (scope : Ast.scope) : Scopelang.Ast.scope_decl =
|
||||
( Some "Incriminated subscope:",
|
||||
Ast.ScopeDef.get_position def_key );
|
||||
( Some "Incriminated variable:",
|
||||
Pos.get_position
|
||||
Marked.get_mark
|
||||
(Ast.ScopeVar.get_info sub_scope_var) );
|
||||
]
|
||||
"This subscope variable is a mandatory input but no \
|
||||
@ -554,7 +567,7 @@ let translate_scope (ctx : ctx) (scope : Ast.scope) : Scopelang.Ast.scope_decl =
|
||||
scope.scope_sub_scopes
|
||||
in
|
||||
let var_pos =
|
||||
Pos.get_position (Ast.ScopeVar.get_info sub_scope_var)
|
||||
Marked.get_mark (Ast.ScopeVar.get_info sub_scope_var)
|
||||
in
|
||||
Scopelang.Ast.Definition
|
||||
( ( Scopelang.Ast.SubScopeVar
|
||||
@ -673,8 +686,10 @@ let translate_program (pgrm : Ast.program) : Scopelang.Ast.program =
|
||||
(let state_name, state_pos =
|
||||
Ast.StateName.get_info state
|
||||
in
|
||||
( Pos.unmark (Ast.ScopeVar.get_info scope_var)
|
||||
^ "_" ^ state_name,
|
||||
( Marked.unmark
|
||||
(Ast.ScopeVar.get_info scope_var)
|
||||
^ "_"
|
||||
^ state_name,
|
||||
state_pos )) ))
|
||||
states))
|
||||
ctx.scope_var_mapping;
|
||||
|
@ -81,20 +81,12 @@ let driver source_file (options : Cli.options) : int =
|
||||
Surface.Parser_driver.parse_top_level_file source_file language
|
||||
in
|
||||
let prgm = Surface.Fill_positions.fill_pos_with_legislative_info prgm in
|
||||
let get_output ?ext () =
|
||||
match options.output_file, ext with
|
||||
| Some "-", _ | None, None -> None, fun f -> f stdout
|
||||
| Some f, _ -> Some f, File.with_out_channel f
|
||||
| None, Some ext ->
|
||||
let src =
|
||||
match source_file with FileName f -> f | Contents _ -> "a"
|
||||
in
|
||||
let f = Filename.remove_extension src ^ ext in
|
||||
Some f, File.with_out_channel f
|
||||
let get_output ?ext =
|
||||
File.get_out_channel ~source_file ~output_file:options.output_file ?ext
|
||||
in
|
||||
let get_output_format ?ext () =
|
||||
let f, with_ = get_output ?ext () in
|
||||
f, fun f -> with_ (fun oc -> File.with_formatter_of_out_channel oc f)
|
||||
let get_output_format ?ext =
|
||||
File.get_formatter_of_out_channel ~source_file
|
||||
~output_file:options.output_file ?ext
|
||||
in
|
||||
(match backend with
|
||||
| `Makefile ->
|
||||
@ -109,7 +101,8 @@ let driver source_file (options : Cli.options) : int =
|
||||
let output_file, with_output = get_output ~ext:".d" () in
|
||||
Cli.debug_print "Writing list of dependencies to %s..."
|
||||
(Option.value ~default:"stdout" output_file);
|
||||
with_output @@ fun oc ->
|
||||
with_output
|
||||
@@ fun oc ->
|
||||
Printf.fprintf oc "%s:\\\n%s\n%s:"
|
||||
(String.concat "\\\n"
|
||||
(Option.value ~default:"stdout" output_file
|
||||
@ -173,7 +166,8 @@ let driver source_file (options : Cli.options) : int =
|
||||
match backend with
|
||||
| `Scopelang ->
|
||||
let _output_file, with_output = get_output_format () in
|
||||
with_output @@ fun fmt ->
|
||||
with_output
|
||||
@@ fun fmt ->
|
||||
if Option.is_some options.ex_scope then
|
||||
Format.fprintf fmt "%a\n"
|
||||
(Scopelang.Print.format_scope ~debug:options.debug)
|
||||
@ -196,13 +190,11 @@ let driver source_file (options : Cli.options) : int =
|
||||
end
|
||||
else prgm
|
||||
in
|
||||
let prgrm_dcalc_expr =
|
||||
Bindlib.unbox (Dcalc.Ast.build_whole_program_expr prgm scope_uid)
|
||||
in
|
||||
match backend with
|
||||
| `Dcalc ->
|
||||
let _output_file, with_output = get_output_format () in
|
||||
with_output @@ fun fmt ->
|
||||
with_output
|
||||
@@ fun fmt ->
|
||||
if Option.is_some options.ex_scope then
|
||||
Format.fprintf fmt "%a\n"
|
||||
(Dcalc.Print.format_scope ~debug:options.debug prgm.decl_ctx)
|
||||
@ -218,13 +210,19 @@ let driver source_file (options : Cli.options) : int =
|
||||
else acc)
|
||||
prgm.scopes) )
|
||||
else
|
||||
let prgrm_dcalc_expr =
|
||||
Bindlib.unbox
|
||||
(Dcalc.Ast.build_whole_program_expr ~box_expr:Dcalc.Ast.box_expr
|
||||
~make_abs:Dcalc.Ast.make_abs
|
||||
~make_let_in:Dcalc.Ast.make_let_in prgm scope_uid)
|
||||
in
|
||||
Format.fprintf fmt "%a\n"
|
||||
(Dcalc.Print.format_expr prgm.decl_ctx)
|
||||
prgrm_dcalc_expr
|
||||
| ( `Interpret | `Typecheck | `OCaml | `Python | `Scalc | `Lcalc
|
||||
| `Proof | `Plugin _ ) as backend -> (
|
||||
Cli.debug_print "Typechecking...";
|
||||
let _typ = Dcalc.Typing.infer_type prgm.decl_ctx prgrm_dcalc_expr in
|
||||
let prgm = Dcalc.Typing.infer_types_program prgm in
|
||||
(* Cli.debug_print (Format.asprintf "Typechecking results :@\n%a"
|
||||
(Dcalc.Print.format_typ prgm.decl_ctx) typ); *)
|
||||
match backend with
|
||||
@ -242,6 +240,12 @@ let driver source_file (options : Cli.options) : int =
|
||||
Verification.Solver.solve_vc prgm.decl_ctx vcs
|
||||
| `Interpret ->
|
||||
Cli.debug_print "Starting interpretation...";
|
||||
let prgrm_dcalc_expr =
|
||||
Bindlib.unbox
|
||||
(Dcalc.Ast.build_whole_program_expr ~box_expr:Dcalc.Ast.box_expr
|
||||
~make_abs:Dcalc.Ast.make_abs
|
||||
~make_let_in:Dcalc.Ast.make_let_in prgm scope_uid)
|
||||
in
|
||||
let results =
|
||||
Dcalc.Interpreter.interpret_program prgm.decl_ctx prgrm_dcalc_expr
|
||||
in
|
||||
@ -281,7 +285,7 @@ let driver source_file (options : Cli.options) : int =
|
||||
Cli.debug_print "Optimizing lambda calculus...";
|
||||
Lcalc.Optimizations.optimize_program prgm
|
||||
end
|
||||
else prgm
|
||||
else Lcalc.Ast.untype_program prgm
|
||||
in
|
||||
let prgm =
|
||||
if options.closure_conversion then (
|
||||
@ -294,7 +298,8 @@ let driver source_file (options : Cli.options) : int =
|
||||
match backend with
|
||||
| `Lcalc ->
|
||||
let _output_file, with_output = get_output_format () in
|
||||
with_output @@ fun fmt ->
|
||||
with_output
|
||||
@@ fun fmt ->
|
||||
if Option.is_some options.ex_scope then
|
||||
Format.fprintf fmt "%a\n"
|
||||
(Lcalc.Print.format_scope ~debug:options.debug prgm.decl_ctx)
|
||||
@ -310,39 +315,42 @@ let driver source_file (options : Cli.options) : int =
|
||||
else acc)
|
||||
prgm.scopes) )
|
||||
else
|
||||
ignore
|
||||
(Dcalc.Ast.fold_left_scope_defs ~init:0
|
||||
~f:(fun i scope_def _ ->
|
||||
Format.fprintf fmt "%s%a"
|
||||
(if i = 0 then "" else "\n")
|
||||
(Lcalc.Print.format_scope prgm.decl_ctx)
|
||||
(scope_uid, scope_def.scope_body);
|
||||
i + 1)
|
||||
prgm.scopes)
|
||||
let prgrm_lcalc_expr =
|
||||
Bindlib.unbox
|
||||
(Dcalc.Ast.build_whole_program_expr
|
||||
~box_expr:Lcalc.Ast.box_expr ~make_abs:Lcalc.Ast.make_abs
|
||||
~make_let_in:Lcalc.Ast.make_let_in prgm scope_uid)
|
||||
in
|
||||
Format.fprintf fmt "%a\n"
|
||||
(Lcalc.Print.format_expr prgm.decl_ctx)
|
||||
prgrm_lcalc_expr
|
||||
| (`OCaml | `Python | `Scalc | `Plugin _) as backend -> (
|
||||
match backend with
|
||||
| `OCaml ->
|
||||
let output_file, with_output =
|
||||
get_output_format ~ext:".ml" ()
|
||||
in
|
||||
with_output @@ fun fmt ->
|
||||
with_output
|
||||
@@ fun fmt ->
|
||||
Cli.debug_print "Compiling program into OCaml...";
|
||||
Cli.debug_print "Writing to %s..."
|
||||
(Option.value ~default:"stdout" output_file);
|
||||
Lcalc.To_ocaml.format_program fmt prgm type_ordering
|
||||
| `Plugin (Plugin.Lcalc p) ->
|
||||
let output_file, _ = get_output ~ext:p.Plugin.extension () in
|
||||
let output_file, _ =
|
||||
get_output_format ~ext:p.Plugin.extension ()
|
||||
in
|
||||
Cli.debug_print "Compiling program through backend \"%s\"..."
|
||||
p.Plugin.name;
|
||||
Cli.debug_print "Writing to %s..."
|
||||
(Option.value ~default:"stdout" output_file);
|
||||
p.Plugin.apply output_file prgm type_ordering
|
||||
p.Plugin.apply ~source_file ~output_file ~scope:options.ex_scope
|
||||
prgm type_ordering
|
||||
| (`Python | `Scalc | `Plugin (Plugin.Scalc _)) as backend -> (
|
||||
let prgm = Scalc.Compile_from_lambda.translate_program prgm in
|
||||
match backend with
|
||||
| `Scalc ->
|
||||
let _output_file, with_output = get_output_format () in
|
||||
with_output @@ fun fmt ->
|
||||
with_output
|
||||
@@ fun fmt ->
|
||||
if Option.is_some options.ex_scope then
|
||||
Format.fprintf fmt "%a\n"
|
||||
(Scalc.Print.format_scope ~debug:options.debug
|
||||
@ -365,7 +373,8 @@ let driver source_file (options : Cli.options) : int =
|
||||
Cli.debug_print "Compiling program into Python...";
|
||||
Cli.debug_print "Writing to %s..."
|
||||
(Option.value ~default:"stdout" output_file);
|
||||
with_output @@ fun fmt ->
|
||||
with_output
|
||||
@@ fun fmt ->
|
||||
Scalc.To_python.format_program fmt prgm type_ordering
|
||||
| `Plugin (Plugin.Lcalc _) -> assert false
|
||||
| `Plugin (Plugin.Scalc p) ->
|
||||
@ -374,14 +383,19 @@ let driver source_file (options : Cli.options) : int =
|
||||
p.Plugin.name;
|
||||
Cli.debug_print "Writing to %s..."
|
||||
(Option.value ~default:"stdout" output_file);
|
||||
p.Plugin.apply output_file prgm type_ordering)))))));
|
||||
p.Plugin.apply ~source_file ~output_file
|
||||
~scope:options.ex_scope prgm type_ordering)))))));
|
||||
0
|
||||
with
|
||||
| Errors.StructuredError (msg, pos) ->
|
||||
let bt = Printexc.get_raw_backtrace () in
|
||||
Cli.error_print "%s" (Errors.print_structured_error msg pos);
|
||||
if Printexc.backtrace_status () then Printexc.print_raw_backtrace stderr bt;
|
||||
-1
|
||||
| Sys_error msg ->
|
||||
let bt = Printexc.get_raw_backtrace () in
|
||||
Cli.error_print "System error: %s" msg;
|
||||
if Printexc.backtrace_status () then Printexc.print_raw_backtrace stderr bt;
|
||||
-1
|
||||
|
||||
let main () =
|
||||
|
@ -10,18 +10,10 @@
|
||||
dcalc
|
||||
lcalc
|
||||
scalc
|
||||
runtime
|
||||
catala.runtime_ocaml
|
||||
verification)
|
||||
(modules plugin driver))
|
||||
|
||||
(library
|
||||
(name runtime)
|
||||
(public_name catala.runtime)
|
||||
(preprocess
|
||||
(pps ppx_yojson_conv))
|
||||
(libraries dates_calc zarith zarith_stubs_js)
|
||||
(modules runtime))
|
||||
|
||||
(executable
|
||||
(name catala_web_interpreter)
|
||||
(modes byte js)
|
||||
@ -30,11 +22,26 @@
|
||||
(modules catala_web_interpreter)
|
||||
(preprocess
|
||||
(pps js_of_ocaml-ppx))
|
||||
(libraries catala.driver js_of_ocaml))
|
||||
(libraries
|
||||
catala.driver
|
||||
js_of_ocaml
|
||||
catala.runtime_ocaml
|
||||
catala.runtime_jsoo))
|
||||
|
||||
(rule
|
||||
(target custom_linking.sexp)
|
||||
(mode fallback)
|
||||
(action
|
||||
(with-stdout-to
|
||||
%{target}
|
||||
(echo "()"))))
|
||||
|
||||
(executable
|
||||
(name catala)
|
||||
(modes native js)
|
||||
(flags
|
||||
(:standard
|
||||
(:include custom_linking.sexp)))
|
||||
(package catala)
|
||||
(modules catala)
|
||||
(public_name catala)
|
||||
|
@ -106,9 +106,9 @@ Two more modules contain additional features for the compiler:
|
||||
{li {{: utils.html} Compiler utilities}}
|
||||
}
|
||||
|
||||
The Catala runtime documentation is available here:
|
||||
The Catala runtimes documentation is available here:
|
||||
|
||||
{!modules: Runtime}
|
||||
{!modules: Runtime_ocaml.Runtime Runtime_jsoo.Runtime}
|
||||
|
||||
Last, it is possible to customize the backend to the compiler using a plugin
|
||||
mechanism. The API is defined inside the following module:
|
||||
|
@ -15,6 +15,7 @@
|
||||
the License. *)
|
||||
|
||||
open Utils
|
||||
module Runtime = Runtime_ocaml.Runtime
|
||||
module D = Dcalc.Ast
|
||||
|
||||
type lit =
|
||||
@ -27,197 +28,181 @@ type lit =
|
||||
| LDuration of Runtime.duration
|
||||
|
||||
type except = ConflictError | EmptyError | NoValueProvided | Crash
|
||||
type 'm mark = 'm D.mark
|
||||
|
||||
type expr =
|
||||
| EVar of expr Bindlib.var Pos.marked
|
||||
| ETuple of expr Pos.marked list * D.StructName.t option
|
||||
type 'm marked_expr = ('m expr, 'm) D.marked
|
||||
|
||||
and 'm expr =
|
||||
| EVar of 'm expr Bindlib.var
|
||||
| ETuple of 'm marked_expr list * D.StructName.t option
|
||||
(** The [MarkedString.info] is the former struct field name*)
|
||||
| ETupleAccess of
|
||||
expr Pos.marked * int * D.StructName.t option * D.typ Pos.marked list
|
||||
'm marked_expr * int * D.StructName.t option * D.typ Marked.pos list
|
||||
(** The [MarkedString.info] is the former struct field name *)
|
||||
| EInj of expr Pos.marked * int * D.EnumName.t * D.typ Pos.marked list
|
||||
| EInj of 'm marked_expr * int * D.EnumName.t * D.typ Marked.pos list
|
||||
(** The [MarkedString.info] is the former enum case name *)
|
||||
| EMatch of expr Pos.marked * expr Pos.marked list * D.EnumName.t
|
||||
| EMatch of 'm marked_expr * 'm marked_expr list * D.EnumName.t
|
||||
(** The [MarkedString.info] is the former enum case name *)
|
||||
| EArray of expr Pos.marked list
|
||||
| EArray of 'm marked_expr list
|
||||
| ELit of lit
|
||||
| EAbs of
|
||||
(expr, expr Pos.marked) Bindlib.mbinder Pos.marked * D.typ Pos.marked list
|
||||
| EApp of expr Pos.marked * expr Pos.marked list
|
||||
| EAssert of expr Pos.marked
|
||||
| EAbs of ('m expr, 'm marked_expr) Bindlib.mbinder * D.typ Marked.pos list
|
||||
| EApp of 'm marked_expr * 'm marked_expr list
|
||||
| EAssert of 'm marked_expr
|
||||
| EOp of D.operator
|
||||
| EIfThenElse of expr Pos.marked * expr Pos.marked * expr Pos.marked
|
||||
| EIfThenElse of 'm marked_expr * 'm marked_expr * 'm marked_expr
|
||||
| ERaise of except
|
||||
| ECatch of expr Pos.marked * except * expr Pos.marked
|
||||
| ECatch of 'm marked_expr * except * 'm marked_expr
|
||||
|
||||
type program = { decl_ctx : Dcalc.Ast.decl_ctx; scopes : expr Dcalc.Ast.scopes }
|
||||
type 'm program = ('m expr, 'm) Dcalc.Ast.program_generic
|
||||
|
||||
let evar (v : expr Bindlib.var) (pos : Pos.t) : expr Pos.marked Bindlib.box =
|
||||
Bindlib.box_apply (fun v' -> v', pos) (Bindlib.box_var v)
|
||||
(* <copy-paste from dcalc/ast.ml> *)
|
||||
|
||||
let etuple
|
||||
(args : expr Pos.marked Bindlib.box list)
|
||||
(s : Dcalc.Ast.StructName.t option)
|
||||
(pos : Pos.t) : expr Pos.marked Bindlib.box =
|
||||
Bindlib.box_apply (fun args -> ETuple (args, s), pos) (Bindlib.box_list args)
|
||||
let evar v mark = Bindlib.box_apply (Marked.mark mark) (Bindlib.box_var v)
|
||||
|
||||
let etupleaccess
|
||||
(e1 : expr Pos.marked Bindlib.box)
|
||||
(i : int)
|
||||
(s : Dcalc.Ast.StructName.t option)
|
||||
(typs : Dcalc.Ast.typ Pos.marked list)
|
||||
(pos : Pos.t) : expr Pos.marked Bindlib.box =
|
||||
Bindlib.box_apply (fun e1 -> ETupleAccess (e1, i, s, typs), pos) e1
|
||||
let etuple args s mark =
|
||||
Bindlib.box_apply (fun args -> ETuple (args, s), mark) (Bindlib.box_list args)
|
||||
|
||||
let einj
|
||||
(e1 : expr Pos.marked Bindlib.box)
|
||||
(i : int)
|
||||
(e_name : Dcalc.Ast.EnumName.t)
|
||||
(typs : Dcalc.Ast.typ Pos.marked list)
|
||||
(pos : Pos.t) : expr Pos.marked Bindlib.box =
|
||||
Bindlib.box_apply (fun e1 -> EInj (e1, i, e_name, typs), pos) e1
|
||||
let etupleaccess e1 i s typs mark =
|
||||
Bindlib.box_apply (fun e1 -> ETupleAccess (e1, i, s, typs), mark) e1
|
||||
|
||||
let ematch
|
||||
(arg : expr Pos.marked Bindlib.box)
|
||||
(arms : expr Pos.marked Bindlib.box list)
|
||||
(e_name : Dcalc.Ast.EnumName.t)
|
||||
(pos : Pos.t) : expr Pos.marked Bindlib.box =
|
||||
let einj e1 i e_name typs mark =
|
||||
Bindlib.box_apply (fun e1 -> EInj (e1, i, e_name, typs), mark) e1
|
||||
|
||||
let ematch arg arms e_name mark =
|
||||
Bindlib.box_apply2
|
||||
(fun arg arms -> EMatch (arg, arms, e_name), pos)
|
||||
(fun arg arms -> EMatch (arg, arms, e_name), mark)
|
||||
arg (Bindlib.box_list arms)
|
||||
|
||||
let earray (args : expr Pos.marked Bindlib.box list) (pos : Pos.t) :
|
||||
expr Pos.marked Bindlib.box =
|
||||
Bindlib.box_apply (fun args -> EArray args, pos) (Bindlib.box_list args)
|
||||
let earray args mark =
|
||||
Bindlib.box_apply (fun args -> EArray args, mark) (Bindlib.box_list args)
|
||||
|
||||
let elit (l : lit) (pos : Pos.t) : expr Pos.marked Bindlib.box =
|
||||
Bindlib.box (ELit l, pos)
|
||||
let elit l mark = Bindlib.box (ELit l, mark)
|
||||
|
||||
let eabs
|
||||
(binder : (expr, expr Pos.marked) Bindlib.mbinder Bindlib.box)
|
||||
(pos_binder : Pos.t)
|
||||
(typs : Dcalc.Ast.typ Pos.marked list)
|
||||
(pos : Pos.t) : expr Pos.marked Bindlib.box =
|
||||
Bindlib.box_apply
|
||||
(fun binder -> EAbs ((binder, pos_binder), typs), pos)
|
||||
binder
|
||||
let eabs binder typs mark =
|
||||
Bindlib.box_apply (fun binder -> EAbs (binder, typs), mark) binder
|
||||
|
||||
let eapp
|
||||
(e1 : expr Pos.marked Bindlib.box)
|
||||
(args : expr Pos.marked Bindlib.box list)
|
||||
(pos : Pos.t) : expr Pos.marked Bindlib.box =
|
||||
let eapp e1 args mark =
|
||||
Bindlib.box_apply2
|
||||
(fun e1 args -> EApp (e1, args), pos)
|
||||
(fun e1 args -> EApp (e1, args), mark)
|
||||
e1 (Bindlib.box_list args)
|
||||
|
||||
let eassert (e1 : expr Pos.marked Bindlib.box) (pos : Pos.t) :
|
||||
expr Pos.marked Bindlib.box =
|
||||
Bindlib.box_apply (fun e1 -> EAssert e1, pos) e1
|
||||
let eassert e1 mark = Bindlib.box_apply (fun e1 -> EAssert e1, mark) e1
|
||||
let eop op mark = Bindlib.box (EOp op, mark)
|
||||
|
||||
let eop (op : Dcalc.Ast.operator) (pos : Pos.t) : expr Pos.marked Bindlib.box =
|
||||
Bindlib.box (EOp op, pos)
|
||||
|
||||
let eraise (e1 : except) (pos : Pos.t) : expr Pos.marked Bindlib.box =
|
||||
Bindlib.box (ERaise e1, pos)
|
||||
|
||||
let ecatch
|
||||
(e1 : expr Pos.marked Bindlib.box)
|
||||
(exn : except)
|
||||
(e2 : expr Pos.marked Bindlib.box)
|
||||
(pos : Pos.t) : expr Pos.marked Bindlib.box =
|
||||
Bindlib.box_apply2 (fun e1 e2 -> ECatch (e1, exn, e2), pos) e1 e2
|
||||
|
||||
let eifthenelse
|
||||
(e1 : expr Pos.marked Bindlib.box)
|
||||
(e2 : expr Pos.marked Bindlib.box)
|
||||
(e3 : expr Pos.marked Bindlib.box)
|
||||
(pos : Pos.t) : expr Pos.marked Bindlib.box =
|
||||
let eifthenelse e1 e2 e3 pos =
|
||||
Bindlib.box_apply3 (fun e1 e2 e3 -> EIfThenElse (e1, e2, e3), pos) e1 e2 e3
|
||||
|
||||
type 'm var = 'm expr Bindlib.var
|
||||
type 'm vars = 'm expr Bindlib.mvar
|
||||
|
||||
let new_var s = Bindlib.new_var (fun x -> EVar x) s
|
||||
|
||||
module Var = struct
|
||||
type t = expr Bindlib.var
|
||||
type t = V : 'a var -> t
|
||||
(* See Dcalc.Ast.var *)
|
||||
|
||||
let make (s : string Pos.marked) : t =
|
||||
Bindlib.new_var
|
||||
(fun (x : expr Bindlib.var) : expr -> EVar (x, Pos.get_position s))
|
||||
(Pos.unmark s)
|
||||
|
||||
let compare x y = Bindlib.compare_vars x y
|
||||
let t v = V v
|
||||
let get (V v) = Bindlib.copy_var v (fun x -> EVar x) (Bindlib.name_of v)
|
||||
let compare (V x) (V y) = Bindlib.compare_vars x y
|
||||
end
|
||||
|
||||
module VarMap = Map.Make (Var)
|
||||
module VarSet = Set.Make (Var)
|
||||
module VarMap = Map.Make (Var)
|
||||
|
||||
type vars = expr Bindlib.mvar
|
||||
(* </copy-paste> *)
|
||||
|
||||
let map_expr
|
||||
(ctx : 'a)
|
||||
~(f : 'a -> expr Pos.marked -> expr Pos.marked Bindlib.box)
|
||||
(e : expr Pos.marked) : expr Pos.marked Bindlib.box =
|
||||
match Pos.unmark e with
|
||||
| EVar (v, _pos) -> evar v (Pos.get_position e)
|
||||
let eraise e1 pos = Bindlib.box (ERaise e1, pos)
|
||||
|
||||
let ecatch e1 exn e2 pos =
|
||||
Bindlib.box_apply2 (fun e1 e2 -> ECatch (e1, exn, e2), pos) e1 e2
|
||||
|
||||
let translate_var v = Bindlib.copy_var v (fun x -> EVar x) (Bindlib.name_of v)
|
||||
|
||||
let map_expr ctx ~f e =
|
||||
let m = Marked.get_mark e in
|
||||
match Marked.unmark e with
|
||||
| EVar v -> evar (translate_var v) (Marked.get_mark e)
|
||||
| EApp (e1, args) ->
|
||||
eapp (f ctx e1) (List.map (f ctx) args) (Pos.get_position e)
|
||||
| EAbs ((binder, binder_pos), typs) ->
|
||||
eabs
|
||||
(Bindlib.box_mbinder (f ctx) binder)
|
||||
binder_pos typs (Pos.get_position e)
|
||||
| ETuple (args, s) -> etuple (List.map (f ctx) args) s (Pos.get_position e)
|
||||
eapp (f ctx e1) (List.map (f ctx) args) (Marked.get_mark e)
|
||||
| EAbs (binder, typs) ->
|
||||
let vars, body = Bindlib.unmbind binder in
|
||||
eabs (Bindlib.bind_mvar (Array.map translate_var vars) (f ctx body)) typs m
|
||||
| ETuple (args, s) -> etuple (List.map (f ctx) args) s (Marked.get_mark e)
|
||||
| ETupleAccess (e1, n, s_name, typs) ->
|
||||
etupleaccess ((f ctx) e1) n s_name typs (Pos.get_position e)
|
||||
etupleaccess ((f ctx) e1) n s_name typs (Marked.get_mark e)
|
||||
| EInj (e1, i, e_name, typs) ->
|
||||
einj ((f ctx) e1) i e_name typs (Pos.get_position e)
|
||||
einj ((f ctx) e1) i e_name typs (Marked.get_mark e)
|
||||
| EMatch (arg, arms, e_name) ->
|
||||
ematch ((f ctx) arg) (List.map (f ctx) arms) e_name (Pos.get_position e)
|
||||
| EArray args -> earray (List.map (f ctx) args) (Pos.get_position e)
|
||||
| ELit l -> elit l (Pos.get_position e)
|
||||
| EAssert e1 -> eassert ((f ctx) e1) (Pos.get_position e)
|
||||
| EOp op -> Bindlib.box (EOp op, Pos.get_position e)
|
||||
| ERaise exn -> eraise exn (Pos.get_position e)
|
||||
ematch ((f ctx) arg) (List.map (f ctx) arms) e_name (Marked.get_mark e)
|
||||
| EArray args -> earray (List.map (f ctx) args) (Marked.get_mark e)
|
||||
| ELit l -> elit l (Marked.get_mark e)
|
||||
| EAssert e1 -> eassert ((f ctx) e1) (Marked.get_mark e)
|
||||
| EOp op -> Bindlib.box (EOp op, Marked.get_mark e)
|
||||
| ERaise exn -> eraise exn (Marked.get_mark e)
|
||||
| EIfThenElse (e1, e2, e3) ->
|
||||
eifthenelse ((f ctx) e1) ((f ctx) e2) ((f ctx) e3) (Pos.get_position e)
|
||||
| ECatch (e1, exn, e2) ->
|
||||
ecatch (f ctx e1) exn (f ctx e2) (Pos.get_position e)
|
||||
eifthenelse ((f ctx) e1) ((f ctx) e2) ((f ctx) e3) (Marked.get_mark e)
|
||||
| ECatch (e1, exn, e2) -> ecatch (f ctx e1) exn (f ctx e2) (Marked.get_mark e)
|
||||
|
||||
let rec map_expr_top_down ~f e =
|
||||
map_expr () ~f:(fun () -> map_expr_top_down ~f) (f e)
|
||||
|
||||
let map_expr_marks ~f e =
|
||||
map_expr_top_down ~f:(fun e -> Marked.(mark (f (get_mark e)) (unmark e))) e
|
||||
|
||||
let untype_expr e =
|
||||
map_expr_marks ~f:(fun m -> Untyped { pos = D.mark_pos m }) e
|
||||
|
||||
let untype_program prg =
|
||||
{
|
||||
prg with
|
||||
D.scopes =
|
||||
Bindlib.unbox
|
||||
(D.map_exprs_in_scopes
|
||||
~f:(fun e -> untype_expr e)
|
||||
~varf:translate_var prg.D.scopes);
|
||||
}
|
||||
|
||||
(** See [Bindlib.box_term] documentation for why we are doing that. *)
|
||||
let box_expr (e : expr Pos.marked) : expr Pos.marked Bindlib.box =
|
||||
let box_expr (e : 'm marked_expr) : 'm marked_expr Bindlib.box =
|
||||
let rec id_t () e = map_expr () ~f:id_t e in
|
||||
id_t () e
|
||||
|
||||
let make_var ((x, pos) : Var.t Pos.marked) : expr Pos.marked Bindlib.box =
|
||||
Bindlib.box_apply (fun x -> x, pos) (Bindlib.box_var x)
|
||||
let make_var (x, mark) =
|
||||
Bindlib.box_apply (fun x -> x, mark) (Bindlib.box_var x)
|
||||
|
||||
let make_abs
|
||||
(xs : vars)
|
||||
(e : expr Pos.marked Bindlib.box)
|
||||
(pos_binder : Pos.t)
|
||||
(taus : D.typ Pos.marked list)
|
||||
(pos : Pos.t) : expr Pos.marked Bindlib.box =
|
||||
Bindlib.box_apply
|
||||
(fun b -> EAbs ((b, pos_binder), taus), pos)
|
||||
(Bindlib.bind_mvar xs e)
|
||||
let make_abs xs e taus mark =
|
||||
Bindlib.box_apply (fun b -> EAbs (b, taus), mark) (Bindlib.bind_mvar xs e)
|
||||
|
||||
let make_app
|
||||
(e : expr Pos.marked Bindlib.box)
|
||||
(u : expr Pos.marked Bindlib.box list)
|
||||
(pos : Pos.t) : expr Pos.marked Bindlib.box =
|
||||
Bindlib.box_apply2 (fun e u -> EApp (e, u), pos) e (Bindlib.box_list u)
|
||||
let make_app e u mark =
|
||||
Bindlib.box_apply2 (fun e u -> EApp (e, u), mark) e (Bindlib.box_list u)
|
||||
|
||||
let make_let_in
|
||||
(x : Var.t)
|
||||
(tau : D.typ Pos.marked)
|
||||
(e1 : expr Pos.marked Bindlib.box)
|
||||
(e2 : expr Pos.marked Bindlib.box)
|
||||
(pos : Pos.t) : expr Pos.marked Bindlib.box =
|
||||
make_app (make_abs (Array.of_list [x]) e2 pos [tau] pos) [e1] pos
|
||||
let make_let_in x tau e1 e2 pos =
|
||||
let m_e1 = Marked.get_mark (Bindlib.unbox e1) in
|
||||
let m_e2 = Marked.get_mark (Bindlib.unbox e2) in
|
||||
let m_abs =
|
||||
D.map_mark2
|
||||
(fun _ _ -> pos)
|
||||
(fun m1 m2 -> TArrow (m1.ty, m2.ty), m1.pos)
|
||||
m_e1 m_e2
|
||||
in
|
||||
make_app (make_abs [| x |] e2 [tau] m_abs) [e1] m_e2
|
||||
|
||||
let make_multiple_let_in
|
||||
(xs : Var.t array)
|
||||
(taus : D.typ Pos.marked list)
|
||||
(e1 : expr Pos.marked Bindlib.box list)
|
||||
(e2 : expr Pos.marked Bindlib.box)
|
||||
(pos : Pos.t) : expr Pos.marked Bindlib.box =
|
||||
make_app (make_abs xs e2 pos taus pos) e1 pos
|
||||
let make_multiple_let_in xs taus e1s e2 pos =
|
||||
(* let m_e1s = List.map (fun e -> Marked.get_mark (Bindlib.unbox e)) e1s in *)
|
||||
let m_e1s =
|
||||
D.fold_marks List.hd
|
||||
(fun tys ->
|
||||
D.TTuple (List.map (fun t -> t.D.ty) tys, None), (List.hd tys).D.pos)
|
||||
(List.map (fun e -> Marked.get_mark (Bindlib.unbox e)) e1s)
|
||||
in
|
||||
let m_e2 = Marked.get_mark (Bindlib.unbox e2) in
|
||||
let m_abs =
|
||||
D.map_mark2
|
||||
(fun _ _ -> pos)
|
||||
(fun m1 m2 -> Marked.mark pos (D.TArrow (m1.ty, m2.ty)))
|
||||
m_e1s m_e2
|
||||
in
|
||||
make_app (make_abs xs e2 taus m_abs) e1s m_e2
|
||||
|
||||
let ( let+ ) x f = Bindlib.box_apply f x
|
||||
let ( and+ ) x y = Bindlib.box_pair x y
|
||||
@ -229,57 +214,53 @@ let none_constr : D.EnumConstructor.t =
|
||||
let some_constr : D.EnumConstructor.t =
|
||||
D.EnumConstructor.fresh ("ESome", Pos.no_pos)
|
||||
|
||||
let option_enum_config : (D.EnumConstructor.t * D.typ Pos.marked) list =
|
||||
let option_enum_config : (D.EnumConstructor.t * D.typ Marked.pos) list =
|
||||
[none_constr, (D.TLit D.TUnit, Pos.no_pos); some_constr, (D.TAny, Pos.no_pos)]
|
||||
|
||||
let make_none (pos : Pos.t) : expr Pos.marked Bindlib.box =
|
||||
let mark : 'a -> 'a Pos.marked = Pos.mark pos in
|
||||
Bindlib.box @@ mark
|
||||
@@ EInj
|
||||
(mark @@ ELit LUnit, 0, option_enum, [D.TLit D.TUnit, pos; D.TAny, pos])
|
||||
(* FIXME: proper typing in all the constructors below *)
|
||||
|
||||
let make_some (e : expr Pos.marked Bindlib.box) : expr Pos.marked Bindlib.box =
|
||||
let pos = Pos.get_position @@ Bindlib.unbox e in
|
||||
let mark : 'a -> 'a Pos.marked = Pos.mark pos in
|
||||
begin[@ocamlformat "disable"]
|
||||
let+ e = e in
|
||||
mark @@ EInj (e, 1, option_enum, [ (D.TLit D.TUnit, pos); (D.TAny, pos) ])
|
||||
end
|
||||
let make_none m =
|
||||
let mark = Marked.mark m in
|
||||
let tunit = D.TLit D.TUnit, D.mark_pos m in
|
||||
Bindlib.box
|
||||
@@ mark
|
||||
@@ EInj
|
||||
( Marked.mark
|
||||
(D.map_mark (fun pos -> pos) (fun _ -> tunit) m)
|
||||
(ELit LUnit),
|
||||
0,
|
||||
option_enum,
|
||||
[D.TLit D.TUnit, Pos.no_pos; D.TAny, Pos.no_pos] )
|
||||
|
||||
let make_some e =
|
||||
let m = Marked.get_mark @@ Bindlib.unbox e in
|
||||
let mark = Marked.mark m in
|
||||
let+ e in
|
||||
mark
|
||||
@@ EInj
|
||||
(e, 1, option_enum, [D.TLit D.TUnit, D.mark_pos m; D.TAny, D.mark_pos m])
|
||||
|
||||
(** [make_matchopt_with_abs_arms arg e_none e_some] build an expression
|
||||
[match arg with |None -> e_none | Some -> e_some] and requires e_some and
|
||||
e_none to be in the form [EAbs ...].*)
|
||||
let make_matchopt_with_abs_arms
|
||||
(arg : expr Pos.marked Bindlib.box)
|
||||
(e_none : expr Pos.marked Bindlib.box)
|
||||
(e_some : expr Pos.marked Bindlib.box) : expr Pos.marked Bindlib.box =
|
||||
let pos = Pos.get_position @@ Bindlib.unbox arg in
|
||||
let mark : 'a -> 'a Pos.marked = Pos.mark pos in
|
||||
begin[@ocamlformat "disable"]
|
||||
let+ arg = arg
|
||||
and+ e_none = e_none
|
||||
and+ e_some = e_some in
|
||||
mark @@ EMatch (arg, [ e_none; e_some ], option_enum)
|
||||
end
|
||||
let make_matchopt_with_abs_arms arg e_none e_some =
|
||||
let m = Marked.get_mark @@ Bindlib.unbox arg in
|
||||
let mark = Marked.mark m in
|
||||
let+ arg and+ e_none and+ e_some in
|
||||
mark @@ EMatch (arg, [e_none; e_some], option_enum)
|
||||
|
||||
(** [make_matchopt pos v tau arg e_none e_some] builds an expression
|
||||
[match arg with | None () -> e_none | Some v -> e_some]. It binds v to
|
||||
e_some, permitting it to be used inside the expression. There is no
|
||||
requirements on the form of both e_some and e_none. *)
|
||||
let make_matchopt
|
||||
(pos : Pos.t)
|
||||
(v : Var.t)
|
||||
(tau : D.typ Pos.marked)
|
||||
(arg : expr Pos.marked Bindlib.box)
|
||||
(e_none : expr Pos.marked Bindlib.box)
|
||||
(e_some : expr Pos.marked Bindlib.box) : expr Pos.marked Bindlib.box =
|
||||
let x = Var.make ("_", pos) in
|
||||
let make_matchopt m v tau arg e_none e_some =
|
||||
let x = new_var "_" in
|
||||
|
||||
make_matchopt_with_abs_arms arg
|
||||
(make_abs (Array.of_list [x]) e_none pos [D.TLit D.TUnit, pos] pos)
|
||||
(make_abs (Array.of_list [v]) e_some pos [tau] pos)
|
||||
(make_abs (Array.of_list [x]) e_none [D.TLit D.TUnit, D.mark_pos m] m)
|
||||
(make_abs (Array.of_list [v]) e_some [tau] m)
|
||||
|
||||
let handle_default = Var.make ("handle_default", Pos.no_pos)
|
||||
let handle_default_opt = Var.make ("handle_default_opt", Pos.no_pos)
|
||||
let handle_default = Var.t (new_var "handle_default")
|
||||
let handle_default_opt = Var.t (new_var "handle_default_opt")
|
||||
|
||||
type binder = (expr, expr Pos.marked) Bindlib.binder
|
||||
type 'm binder = ('m expr, 'm marked_expr) Bindlib.binder
|
||||
|
@ -15,6 +15,7 @@
|
||||
the License. *)
|
||||
|
||||
open Utils
|
||||
module Runtime = Runtime_ocaml.Runtime
|
||||
|
||||
(** Abstract syntax tree for the lambda calculus *)
|
||||
|
||||
@ -33,190 +34,217 @@ type lit =
|
||||
| LDuration of Runtime.duration
|
||||
|
||||
type except = ConflictError | EmptyError | NoValueProvided | Crash
|
||||
type 'm mark = 'm Dcalc.Ast.mark
|
||||
|
||||
type expr =
|
||||
| EVar of expr Bindlib.var Pos.marked
|
||||
| ETuple of expr Pos.marked list * Dcalc.Ast.StructName.t option
|
||||
type 'm marked_expr = ('m expr, 'm) Dcalc.Ast.marked
|
||||
|
||||
and 'm expr =
|
||||
| EVar of 'm expr Bindlib.var
|
||||
| ETuple of 'm marked_expr list * Dcalc.Ast.StructName.t option
|
||||
(** The [MarkedString.info] is the former struct field name*)
|
||||
| ETupleAccess of
|
||||
expr Pos.marked
|
||||
'm marked_expr
|
||||
* int
|
||||
* Dcalc.Ast.StructName.t option
|
||||
* Dcalc.Ast.typ Pos.marked list
|
||||
* Dcalc.Ast.typ Marked.pos list
|
||||
(** The [MarkedString.info] is the former struct field name *)
|
||||
| EInj of
|
||||
expr Pos.marked
|
||||
'm marked_expr
|
||||
* int
|
||||
* Dcalc.Ast.EnumName.t
|
||||
* Dcalc.Ast.typ Pos.marked list
|
||||
* Dcalc.Ast.typ Marked.pos list
|
||||
(** The [MarkedString.info] is the former enum case name *)
|
||||
| EMatch of expr Pos.marked * expr Pos.marked list * Dcalc.Ast.EnumName.t
|
||||
| EMatch of 'm marked_expr * 'm marked_expr list * Dcalc.Ast.EnumName.t
|
||||
(** The [MarkedString.info] is the former enum case name *)
|
||||
| EArray of expr Pos.marked list
|
||||
| EArray of 'm marked_expr list
|
||||
| ELit of lit
|
||||
| EAbs of
|
||||
(expr, expr Pos.marked) Bindlib.mbinder Pos.marked
|
||||
* Dcalc.Ast.typ Pos.marked list
|
||||
| EApp of expr Pos.marked * expr Pos.marked list
|
||||
| EAssert of expr Pos.marked
|
||||
('m expr, 'm marked_expr) Bindlib.mbinder * Dcalc.Ast.typ Marked.pos list
|
||||
| EApp of 'm marked_expr * 'm marked_expr list
|
||||
| EAssert of 'm marked_expr
|
||||
| EOp of Dcalc.Ast.operator
|
||||
| EIfThenElse of expr Pos.marked * expr Pos.marked * expr Pos.marked
|
||||
| EIfThenElse of 'm marked_expr * 'm marked_expr * 'm marked_expr
|
||||
| ERaise of except
|
||||
| ECatch of expr Pos.marked * except * expr Pos.marked
|
||||
| ECatch of 'm marked_expr * except * 'm marked_expr
|
||||
|
||||
type program = { decl_ctx : Dcalc.Ast.decl_ctx; scopes : expr Dcalc.Ast.scopes }
|
||||
type 'm program = ('m expr, 'm) Dcalc.Ast.program_generic
|
||||
|
||||
(** {1 Variable helpers} *)
|
||||
|
||||
module Var : sig
|
||||
type t = expr Bindlib.var
|
||||
type 'm var = 'm expr Bindlib.var
|
||||
type 'm vars = 'm expr Bindlib.mvar
|
||||
|
||||
val make : string Pos.marked -> t
|
||||
module Var : sig
|
||||
type t
|
||||
|
||||
val t : 'm expr Bindlib.var -> t
|
||||
val get : t -> 'm expr Bindlib.var
|
||||
val compare : t -> t -> int
|
||||
end
|
||||
|
||||
module VarMap : Map.S with type key = Var.t
|
||||
module VarSet : Set.S with type elt = Var.t
|
||||
|
||||
type vars = expr Bindlib.mvar
|
||||
type binder = (expr, expr Pos.marked) Bindlib.binder
|
||||
val new_var : string -> 'm var
|
||||
|
||||
(** {1 Boxed constructors}*)
|
||||
type 'm binder = ('m expr, 'm marked_expr) Bindlib.binder
|
||||
|
||||
val evar : expr Bindlib.var -> Pos.t -> expr Pos.marked Bindlib.box
|
||||
(** {2 Program traversal} *)
|
||||
|
||||
val map_expr :
|
||||
'a ->
|
||||
f:('a -> 'm1 marked_expr -> 'm2 marked_expr Bindlib.box) ->
|
||||
('m1 expr, 'm2 mark) Marked.t ->
|
||||
'm2 marked_expr Bindlib.box
|
||||
(** See [Dcalc.Ast.map_expr] *)
|
||||
|
||||
val map_expr_top_down :
|
||||
f:('m1 marked_expr -> ('m1 expr, 'm2 mark) Marked.t) ->
|
||||
'm1 marked_expr ->
|
||||
'm2 marked_expr Bindlib.box
|
||||
(** See [Dcalc.Ast.map_expr_top_down] *)
|
||||
|
||||
val map_expr_marks :
|
||||
f:('m1 mark -> 'm2 mark) -> 'm1 marked_expr -> 'm2 marked_expr Bindlib.box
|
||||
(** See [Dcalc.Ast.map_expr_marks] *)
|
||||
|
||||
val untype_expr : 'm marked_expr -> Dcalc.Ast.untyped marked_expr Bindlib.box
|
||||
val untype_program : 'm program -> Dcalc.Ast.untyped program
|
||||
|
||||
(** {1 Boxed constructors} *)
|
||||
|
||||
val evar : 'm expr Bindlib.var -> 'm mark -> 'm marked_expr Bindlib.box
|
||||
|
||||
val etuple :
|
||||
expr Pos.marked Bindlib.box list ->
|
||||
'm marked_expr Bindlib.box list ->
|
||||
Dcalc.Ast.StructName.t option ->
|
||||
Pos.t ->
|
||||
expr Pos.marked Bindlib.box
|
||||
'm mark ->
|
||||
'm marked_expr Bindlib.box
|
||||
|
||||
val etupleaccess :
|
||||
expr Pos.marked Bindlib.box ->
|
||||
'm marked_expr Bindlib.box ->
|
||||
int ->
|
||||
Dcalc.Ast.StructName.t option ->
|
||||
Dcalc.Ast.typ Pos.marked list ->
|
||||
Pos.t ->
|
||||
expr Pos.marked Bindlib.box
|
||||
Dcalc.Ast.typ Marked.pos list ->
|
||||
'm mark ->
|
||||
'm marked_expr Bindlib.box
|
||||
|
||||
val einj :
|
||||
expr Pos.marked Bindlib.box ->
|
||||
'm marked_expr Bindlib.box ->
|
||||
int ->
|
||||
Dcalc.Ast.EnumName.t ->
|
||||
Dcalc.Ast.typ Pos.marked list ->
|
||||
Pos.t ->
|
||||
expr Pos.marked Bindlib.box
|
||||
Dcalc.Ast.typ Marked.pos list ->
|
||||
'm mark ->
|
||||
'm marked_expr Bindlib.box
|
||||
|
||||
val ematch :
|
||||
expr Pos.marked Bindlib.box ->
|
||||
expr Pos.marked Bindlib.box list ->
|
||||
'm marked_expr Bindlib.box ->
|
||||
'm marked_expr Bindlib.box list ->
|
||||
Dcalc.Ast.EnumName.t ->
|
||||
Pos.t ->
|
||||
expr Pos.marked Bindlib.box
|
||||
'm mark ->
|
||||
'm marked_expr Bindlib.box
|
||||
|
||||
val earray :
|
||||
expr Pos.marked Bindlib.box list -> Pos.t -> expr Pos.marked Bindlib.box
|
||||
'm marked_expr Bindlib.box list -> 'm mark -> 'm marked_expr Bindlib.box
|
||||
|
||||
val elit : lit -> Pos.t -> expr Pos.marked Bindlib.box
|
||||
val elit : lit -> 'm mark -> 'm marked_expr Bindlib.box
|
||||
|
||||
val eabs :
|
||||
(expr, expr Pos.marked) Bindlib.mbinder Bindlib.box ->
|
||||
Pos.t ->
|
||||
Dcalc.Ast.typ Pos.marked list ->
|
||||
Pos.t ->
|
||||
expr Pos.marked Bindlib.box
|
||||
('m expr, 'm marked_expr) Bindlib.mbinder Bindlib.box ->
|
||||
Dcalc.Ast.typ Marked.pos list ->
|
||||
'm mark ->
|
||||
'm marked_expr Bindlib.box
|
||||
|
||||
val eapp :
|
||||
expr Pos.marked Bindlib.box ->
|
||||
expr Pos.marked Bindlib.box list ->
|
||||
Pos.t ->
|
||||
expr Pos.marked Bindlib.box
|
||||
'm marked_expr Bindlib.box ->
|
||||
'm marked_expr Bindlib.box list ->
|
||||
'm mark ->
|
||||
'm marked_expr Bindlib.box
|
||||
|
||||
val eassert :
|
||||
expr Pos.marked Bindlib.box -> Pos.t -> expr Pos.marked Bindlib.box
|
||||
'm marked_expr Bindlib.box -> 'm mark -> 'm marked_expr Bindlib.box
|
||||
|
||||
val eop : Dcalc.Ast.operator -> Pos.t -> expr Pos.marked Bindlib.box
|
||||
val eop : Dcalc.Ast.operator -> 'm mark -> 'm marked_expr Bindlib.box
|
||||
|
||||
val eifthenelse :
|
||||
expr Pos.marked Bindlib.box ->
|
||||
expr Pos.marked Bindlib.box ->
|
||||
expr Pos.marked Bindlib.box ->
|
||||
Pos.t ->
|
||||
expr Pos.marked Bindlib.box
|
||||
'm marked_expr Bindlib.box ->
|
||||
'm marked_expr Bindlib.box ->
|
||||
'm marked_expr Bindlib.box ->
|
||||
'm mark ->
|
||||
'm marked_expr Bindlib.box
|
||||
|
||||
val ecatch :
|
||||
expr Pos.marked Bindlib.box ->
|
||||
'm marked_expr Bindlib.box ->
|
||||
except ->
|
||||
expr Pos.marked Bindlib.box ->
|
||||
Pos.t ->
|
||||
expr Pos.marked Bindlib.box
|
||||
'm marked_expr Bindlib.box ->
|
||||
'm mark ->
|
||||
'm marked_expr Bindlib.box
|
||||
|
||||
val eraise : except -> Pos.t -> expr Pos.marked Bindlib.box
|
||||
val eraise : except -> 'm mark -> 'm marked_expr Bindlib.box
|
||||
|
||||
(** {1 Language terms construction}*)
|
||||
|
||||
val make_var : Var.t Pos.marked -> expr Pos.marked Bindlib.box
|
||||
val make_var : ('m var, 'm) Dcalc.Ast.marked -> 'm marked_expr Bindlib.box
|
||||
|
||||
val make_abs :
|
||||
vars ->
|
||||
expr Pos.marked Bindlib.box ->
|
||||
Pos.t ->
|
||||
Dcalc.Ast.typ Pos.marked list ->
|
||||
Pos.t ->
|
||||
expr Pos.marked Bindlib.box
|
||||
'm vars ->
|
||||
'm marked_expr Bindlib.box ->
|
||||
Dcalc.Ast.typ Marked.pos list ->
|
||||
'm mark ->
|
||||
'm marked_expr Bindlib.box
|
||||
|
||||
val make_app :
|
||||
expr Pos.marked Bindlib.box ->
|
||||
expr Pos.marked Bindlib.box list ->
|
||||
Pos.t ->
|
||||
expr Pos.marked Bindlib.box
|
||||
'm marked_expr Bindlib.box ->
|
||||
'm marked_expr Bindlib.box list ->
|
||||
'm mark ->
|
||||
'm marked_expr Bindlib.box
|
||||
|
||||
val make_let_in :
|
||||
Var.t ->
|
||||
Dcalc.Ast.typ Pos.marked ->
|
||||
expr Pos.marked Bindlib.box ->
|
||||
expr Pos.marked Bindlib.box ->
|
||||
'm var ->
|
||||
Dcalc.Ast.typ Marked.pos ->
|
||||
'm marked_expr Bindlib.box ->
|
||||
'm marked_expr Bindlib.box ->
|
||||
Pos.t ->
|
||||
expr Pos.marked Bindlib.box
|
||||
'm marked_expr Bindlib.box
|
||||
|
||||
val make_multiple_let_in :
|
||||
Var.t array ->
|
||||
Dcalc.Ast.typ Pos.marked list ->
|
||||
expr Pos.marked Bindlib.box list ->
|
||||
expr Pos.marked Bindlib.box ->
|
||||
'm vars ->
|
||||
Dcalc.Ast.typ Marked.pos list ->
|
||||
'm marked_expr Bindlib.box list ->
|
||||
'm marked_expr Bindlib.box ->
|
||||
Pos.t ->
|
||||
expr Pos.marked Bindlib.box
|
||||
'm marked_expr Bindlib.box
|
||||
|
||||
val option_enum : Dcalc.Ast.EnumName.t
|
||||
val none_constr : Dcalc.Ast.EnumConstructor.t
|
||||
val some_constr : Dcalc.Ast.EnumConstructor.t
|
||||
|
||||
val option_enum_config :
|
||||
(Dcalc.Ast.EnumConstructor.t * Dcalc.Ast.typ Pos.marked) list
|
||||
(Dcalc.Ast.EnumConstructor.t * Dcalc.Ast.typ Marked.pos) list
|
||||
|
||||
val make_none : Pos.t -> expr Pos.marked Bindlib.box
|
||||
val make_some : expr Pos.marked Bindlib.box -> expr Pos.marked Bindlib.box
|
||||
val make_none : 'm mark -> 'm marked_expr Bindlib.box
|
||||
val make_some : 'm marked_expr Bindlib.box -> 'm marked_expr Bindlib.box
|
||||
|
||||
val make_matchopt_with_abs_arms :
|
||||
expr Pos.marked Bindlib.box ->
|
||||
expr Pos.marked Bindlib.box ->
|
||||
expr Pos.marked Bindlib.box ->
|
||||
expr Pos.marked Bindlib.box
|
||||
'm marked_expr Bindlib.box ->
|
||||
'm marked_expr Bindlib.box ->
|
||||
'm marked_expr Bindlib.box ->
|
||||
'm marked_expr Bindlib.box
|
||||
|
||||
val make_matchopt :
|
||||
Pos.t ->
|
||||
Var.t ->
|
||||
Dcalc.Ast.typ Pos.marked ->
|
||||
expr Pos.marked Bindlib.box ->
|
||||
expr Pos.marked Bindlib.box ->
|
||||
expr Pos.marked Bindlib.box ->
|
||||
expr Pos.marked Bindlib.box
|
||||
'm mark ->
|
||||
'm var ->
|
||||
Dcalc.Ast.typ Marked.pos ->
|
||||
'm marked_expr Bindlib.box ->
|
||||
'm marked_expr Bindlib.box ->
|
||||
'm marked_expr Bindlib.box ->
|
||||
'm marked_expr Bindlib.box
|
||||
(** [e' = make_matchopt'' pos v e e_none e_some] Builds the term corresponding
|
||||
to [match e with | None -> fun () -> e_none |Some -> fun v -> e_some]. *)
|
||||
|
||||
val box_expr : expr Pos.marked -> expr Pos.marked Bindlib.box
|
||||
val box_expr : 'm marked_expr -> 'm marked_expr Bindlib.box
|
||||
|
||||
(** {1 Special symbols}*)
|
||||
(** {1 Special symbols} *)
|
||||
|
||||
val handle_default : Var.t
|
||||
val handle_default_opt : Var.t
|
||||
|
@ -1,81 +0,0 @@
|
||||
(* This file is part of the Catala compiler, a specification language for tax
|
||||
and social benefits computation rules. Copyright (C) 2021 Inria, contributor:
|
||||
Denis Merigoux <denis.merigoux@inria.fr>
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
use this file except in compliance with the License. You may obtain a copy of
|
||||
the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
License for the specific language governing permissions and limitations under
|
||||
the License. *)
|
||||
|
||||
let to_ascii (s : string) : string =
|
||||
let out = ref "" in
|
||||
CamomileLibraryDefault.Camomile.UTF8.iter
|
||||
(fun c ->
|
||||
let code = CamomileLibraryDefault.Camomile.UChar.uint_code c in
|
||||
out :=
|
||||
!out
|
||||
^
|
||||
match code with
|
||||
| 0xc7 -> "C"
|
||||
| 0xe7 -> "c"
|
||||
| c when c >= 0xc0 && c <= 0xc6 -> "A"
|
||||
| c when c >= 0xe0 && c <= 0xe6 -> "a"
|
||||
| c when c >= 0xc8 && c <= 0xcb -> "E"
|
||||
| c when c >= 0xe8 && c <= 0xeb -> "e"
|
||||
| c when c >= 0xcc && c <= 0xcf -> "I"
|
||||
| c when c >= 0xec && c <= 0xef -> "i"
|
||||
| c when c >= 0xd2 && c <= 0xd6 -> "O"
|
||||
| c when c >= 0xf2 && c <= 0xf6 -> "o"
|
||||
| c when c >= 0xd9 && c <= 0xdc -> "U"
|
||||
| c when c >= 0xf9 && c <= 0xfc -> "u"
|
||||
| _ ->
|
||||
if code > 128 then "_"
|
||||
else String.make 1 (CamomileLibraryDefault.Camomile.UChar.char_of c))
|
||||
s;
|
||||
!out
|
||||
|
||||
let to_lowercase (s : string) : string =
|
||||
let is_first = ref true in
|
||||
let out = ref "" in
|
||||
CamomileLibraryDefault.Camomile.UTF8.iter
|
||||
(fun c ->
|
||||
let is_uppercase = Dcalc.Print.is_uppercase c in
|
||||
out :=
|
||||
!out
|
||||
^ (if is_uppercase && not !is_first then "_" else "")
|
||||
^ String.lowercase_ascii
|
||||
(String.make 1 (CamomileLibraryDefault.Camomile.UChar.char_of c));
|
||||
is_first := false)
|
||||
s;
|
||||
!out
|
||||
|
||||
let to_uppercase (s : string) : string =
|
||||
let last_was_underscore = ref false in
|
||||
let is_first = ref true in
|
||||
let out = ref "" in
|
||||
CamomileLibraryDefault.Camomile.UTF8.iter
|
||||
(fun c ->
|
||||
let is_underscore =
|
||||
c = CamomileLibraryDefault.Camomile.UChar.of_char '_'
|
||||
in
|
||||
let c_string =
|
||||
String.make 1 (CamomileLibraryDefault.Camomile.UChar.char_of c)
|
||||
in
|
||||
out :=
|
||||
!out
|
||||
^
|
||||
if is_underscore then ""
|
||||
else if !last_was_underscore || !is_first then
|
||||
String.uppercase_ascii c_string
|
||||
else c_string;
|
||||
last_was_underscore := is_underscore;
|
||||
is_first := false)
|
||||
s;
|
||||
!out
|
@ -21,275 +21,283 @@ module D = Dcalc.Ast
|
||||
(** TODO: This version is not yet debugged and ought to be specialized when
|
||||
Lcalc has more structure. *)
|
||||
|
||||
type closure = { name : Var.t; expr : expr Pos.marked Bindlib.box }
|
||||
type ctx = { name_context : string; globally_bound_vars : VarSet.t }
|
||||
|
||||
(** Returns the expression with closed closures and the set of free variables
|
||||
inside this new expression. Implementation guided by
|
||||
http://gallium.inria.fr/~fpottier/mpri/cours04.pdf#page=9. *)
|
||||
let rec closure_conversion_expr (ctx : ctx) (e : expr Pos.marked) :
|
||||
expr Pos.marked Bindlib.box * VarSet.t =
|
||||
match Pos.unmark e with
|
||||
| EVar v ->
|
||||
( Bindlib.box_apply
|
||||
(fun new_v -> new_v, Pos.get_position v)
|
||||
(Bindlib.box_var (Pos.unmark v)),
|
||||
VarSet.diff (VarSet.singleton (Pos.unmark v)) ctx.globally_bound_vars )
|
||||
| ETuple (args, s) ->
|
||||
let new_args, free_vars =
|
||||
List.fold_left
|
||||
(fun (new_args, free_vars) arg ->
|
||||
let new_arg, new_free_vars = closure_conversion_expr ctx arg in
|
||||
new_arg :: new_args, VarSet.union new_free_vars free_vars)
|
||||
([], VarSet.empty) args
|
||||
in
|
||||
( Bindlib.box_apply
|
||||
(fun new_args -> ETuple (List.rev new_args, s), Pos.get_position e)
|
||||
(Bindlib.box_list new_args),
|
||||
free_vars )
|
||||
| ETupleAccess (e1, n, s, typs) ->
|
||||
let new_e1, free_vars = closure_conversion_expr ctx e1 in
|
||||
( Bindlib.box_apply
|
||||
(fun new_e1 -> ETupleAccess (new_e1, n, s, typs), Pos.get_position e)
|
||||
new_e1,
|
||||
free_vars )
|
||||
| EInj (e1, n, e_name, typs) ->
|
||||
let new_e1, free_vars = closure_conversion_expr ctx e1 in
|
||||
( Bindlib.box_apply
|
||||
(fun new_e1 -> EInj (new_e1, n, e_name, typs), Pos.get_position e)
|
||||
new_e1,
|
||||
free_vars )
|
||||
| EMatch (e1, arms, e_name) ->
|
||||
let new_e1, free_vars = closure_conversion_expr ctx e1 in
|
||||
(* We do not close the clotures inside the arms of the match expression,
|
||||
since they get a special treatment at compilation to Scalc. *)
|
||||
let new_arms, free_vars =
|
||||
List.fold_right
|
||||
(fun arm (new_arms, free_vars) ->
|
||||
match Pos.unmark arm with
|
||||
| EAbs ((binder, binder_pos), typs) ->
|
||||
let vars, body = Bindlib.unmbind binder in
|
||||
let new_body, new_free_vars = closure_conversion_expr ctx body in
|
||||
let new_binder = Bindlib.bind_mvar vars new_body in
|
||||
( Bindlib.box_apply
|
||||
(fun new_binder ->
|
||||
EAbs ((new_binder, binder_pos), typs), Pos.get_position arm)
|
||||
new_binder
|
||||
:: new_arms,
|
||||
VarSet.union free_vars new_free_vars )
|
||||
| _ -> failwith "should not happen")
|
||||
arms ([], free_vars)
|
||||
in
|
||||
( Bindlib.box_apply2
|
||||
(fun new_e1 new_arms ->
|
||||
EMatch (new_e1, new_arms, e_name), Pos.get_position e)
|
||||
new_e1
|
||||
(Bindlib.box_list new_arms),
|
||||
free_vars )
|
||||
| EArray args ->
|
||||
let new_args, free_vars =
|
||||
List.fold_right
|
||||
(fun arg (new_args, free_vars) ->
|
||||
let new_arg, new_free_vars = closure_conversion_expr ctx arg in
|
||||
new_arg :: new_args, VarSet.union free_vars new_free_vars)
|
||||
args ([], VarSet.empty)
|
||||
in
|
||||
( Bindlib.box_apply
|
||||
(fun new_args -> EArray new_args, Pos.get_position e)
|
||||
(Bindlib.box_list new_args),
|
||||
free_vars )
|
||||
| ELit l -> Bindlib.box (ELit l, Pos.get_position e), VarSet.empty
|
||||
| EApp ((EAbs ((binder, binder_pos), typs_abs), e1_pos), args) ->
|
||||
(* let-binding, we should not close these *)
|
||||
let vars, body = Bindlib.unmbind binder in
|
||||
let new_body, free_vars = closure_conversion_expr ctx body in
|
||||
let new_binder = Bindlib.bind_mvar vars new_body in
|
||||
let new_args, free_vars =
|
||||
List.fold_right
|
||||
(fun arg (new_args, free_vars) ->
|
||||
let new_arg, new_free_vars = closure_conversion_expr ctx arg in
|
||||
new_arg :: new_args, VarSet.union free_vars new_free_vars)
|
||||
args ([], free_vars)
|
||||
in
|
||||
( Bindlib.box_apply2
|
||||
(fun new_binder new_args ->
|
||||
( EApp ((EAbs ((new_binder, binder_pos), typs_abs), e1_pos), new_args),
|
||||
Pos.get_position e ))
|
||||
new_binder
|
||||
(Bindlib.box_list new_args),
|
||||
free_vars )
|
||||
| EAbs ((binder, binder_pos), typs) ->
|
||||
(* λ x.t *)
|
||||
(* Converting the closure. *)
|
||||
let vars, body = Bindlib.unmbind binder in
|
||||
(* t *)
|
||||
let new_body, body_vars = closure_conversion_expr ctx body in
|
||||
(* [[t]] *)
|
||||
let extra_vars =
|
||||
VarSet.diff body_vars (VarSet.of_list (Array.to_list vars))
|
||||
in
|
||||
let extra_vars_list = VarSet.elements extra_vars in
|
||||
(* x1, ..., xn *)
|
||||
let code_var = Var.make (ctx.name_context, binder_pos) in
|
||||
(* code *)
|
||||
let inner_c_var = Var.make ("env", binder_pos) in
|
||||
let new_closure_body =
|
||||
make_multiple_let_in
|
||||
(Array.of_list extra_vars_list)
|
||||
(List.init (List.length extra_vars_list) (fun _ ->
|
||||
Dcalc.Ast.TAny, binder_pos))
|
||||
(List.mapi
|
||||
(fun i _ ->
|
||||
Bindlib.box_apply
|
||||
(fun inner_c_var ->
|
||||
( ETupleAccess
|
||||
( (inner_c_var, binder_pos),
|
||||
i + 1,
|
||||
None,
|
||||
List.init
|
||||
(List.length extra_vars_list + 1)
|
||||
(fun _ -> Dcalc.Ast.TAny, binder_pos) ),
|
||||
binder_pos ))
|
||||
(Bindlib.box_var inner_c_var))
|
||||
extra_vars_list)
|
||||
new_body binder_pos
|
||||
in
|
||||
let new_closure =
|
||||
make_abs
|
||||
(Array.concat [Array.make 1 inner_c_var; vars])
|
||||
new_closure_body binder_pos
|
||||
((Dcalc.Ast.TAny, binder_pos) :: typs)
|
||||
(Pos.get_position e)
|
||||
in
|
||||
( make_let_in code_var
|
||||
(Dcalc.Ast.TAny, Pos.get_position e)
|
||||
new_closure
|
||||
(Bindlib.box_apply2
|
||||
(fun code_var extra_vars ->
|
||||
( ETuple
|
||||
( (code_var, binder_pos)
|
||||
:: List.map
|
||||
(fun extra_var -> extra_var, binder_pos)
|
||||
extra_vars,
|
||||
None ),
|
||||
Pos.get_position e ))
|
||||
(Bindlib.box_var code_var)
|
||||
(Bindlib.box_list
|
||||
(List.map
|
||||
(fun extra_var -> Bindlib.box_var extra_var)
|
||||
extra_vars_list)))
|
||||
(Pos.get_position e),
|
||||
extra_vars )
|
||||
| EApp ((EOp op, pos_op), args) ->
|
||||
(* This corresponds to an operator call, which we don't want to transform*)
|
||||
let new_args, free_vars =
|
||||
List.fold_right
|
||||
(fun arg (new_args, free_vars) ->
|
||||
let new_arg, new_free_vars = closure_conversion_expr ctx arg in
|
||||
new_arg :: new_args, VarSet.union free_vars new_free_vars)
|
||||
args ([], VarSet.empty)
|
||||
in
|
||||
( Bindlib.box_apply
|
||||
(fun new_e2 -> EApp ((EOp op, pos_op), new_e2), Pos.get_position e)
|
||||
(Bindlib.box_list new_args),
|
||||
free_vars )
|
||||
| EApp ((EVar (v, _), v_pos), args) when VarSet.mem v ctx.globally_bound_vars
|
||||
->
|
||||
(* This corresponds to a scope call, which we don't want to transform*)
|
||||
let new_args, free_vars =
|
||||
List.fold_right
|
||||
(fun arg (new_args, free_vars) ->
|
||||
let new_arg, new_free_vars = closure_conversion_expr ctx arg in
|
||||
new_arg :: new_args, VarSet.union free_vars new_free_vars)
|
||||
args ([], VarSet.empty)
|
||||
in
|
||||
( Bindlib.box_apply2
|
||||
(fun new_v new_e2 -> EApp ((new_v, v_pos), new_e2), Pos.get_position e)
|
||||
(Bindlib.box_var v)
|
||||
(Bindlib.box_list new_args),
|
||||
free_vars )
|
||||
| EApp (e1, args) ->
|
||||
let new_e1, free_vars = closure_conversion_expr ctx e1 in
|
||||
let env_var = Var.make ("env", Pos.get_position e1) in
|
||||
let code_var = Var.make ("code", Pos.get_position e1) in
|
||||
let new_args, free_vars =
|
||||
List.fold_right
|
||||
(fun arg (new_args, free_vars) ->
|
||||
let new_arg, new_free_vars = closure_conversion_expr ctx arg in
|
||||
new_arg :: new_args, VarSet.union free_vars new_free_vars)
|
||||
args ([], free_vars)
|
||||
in
|
||||
let call_expr =
|
||||
make_let_in code_var
|
||||
(Dcalc.Ast.TAny, Pos.get_position e)
|
||||
(Bindlib.box_apply
|
||||
(fun env_var ->
|
||||
( ETupleAccess
|
||||
((env_var, Pos.get_position e1), 0, None, [ (*TODO: fill?*) ]),
|
||||
Pos.get_position e ))
|
||||
(Bindlib.box_var env_var))
|
||||
(Bindlib.box_apply3
|
||||
(fun code_var env_var new_args ->
|
||||
( EApp
|
||||
( (code_var, Pos.get_position e1),
|
||||
(env_var, Pos.get_position e1) :: new_args ),
|
||||
Pos.get_position e ))
|
||||
(Bindlib.box_var code_var) (Bindlib.box_var env_var)
|
||||
(Bindlib.box_list new_args))
|
||||
(Pos.get_position e)
|
||||
in
|
||||
( make_let_in env_var
|
||||
(Dcalc.Ast.TAny, Pos.get_position e)
|
||||
new_e1 call_expr (Pos.get_position e),
|
||||
free_vars )
|
||||
| EAssert e1 ->
|
||||
let new_e1, free_vars = closure_conversion_expr ctx e1 in
|
||||
( Bindlib.box_apply (fun new_e1 -> EAssert new_e1, Pos.get_position e) new_e1,
|
||||
free_vars )
|
||||
| EOp op -> Bindlib.box (EOp op, Pos.get_position e), VarSet.empty
|
||||
| EIfThenElse (e1, e2, e3) ->
|
||||
let new_e1, free_vars1 = closure_conversion_expr ctx e1 in
|
||||
let new_e2, free_vars2 = closure_conversion_expr ctx e2 in
|
||||
let new_e3, free_vars3 = closure_conversion_expr ctx e3 in
|
||||
( Bindlib.box_apply3
|
||||
(fun new_e1 new_e2 new_e3 ->
|
||||
EIfThenElse (new_e1, new_e2, new_e3), Pos.get_position e)
|
||||
new_e1 new_e2 new_e3,
|
||||
VarSet.union (VarSet.union free_vars1 free_vars2) free_vars3 )
|
||||
| ERaise except ->
|
||||
Bindlib.box (ERaise except, Pos.get_position e), VarSet.empty
|
||||
| ECatch (e1, except, e2) ->
|
||||
let new_e1, free_vars1 = closure_conversion_expr ctx e1 in
|
||||
let new_e2, free_vars2 = closure_conversion_expr ctx e2 in
|
||||
( Bindlib.box_apply2
|
||||
(fun new_e1 new_e2 ->
|
||||
ECatch (new_e1, except, new_e2), Pos.get_position e)
|
||||
new_e1 new_e2,
|
||||
VarSet.union free_vars1 free_vars2 )
|
||||
let closure_conversion_expr (type m) (ctx : ctx) (e : m marked_expr) :
|
||||
m marked_expr Bindlib.box =
|
||||
let module MVarSet = Set.Make (struct
|
||||
type t = m var
|
||||
|
||||
let closure_conversion (p : program) : program Bindlib.box =
|
||||
let compare = Bindlib.compare_vars
|
||||
end) in
|
||||
let rec aux e =
|
||||
match Marked.unmark e with
|
||||
| EVar v ->
|
||||
( Bindlib.box_apply
|
||||
(fun new_v -> new_v, Marked.get_mark e)
|
||||
(Bindlib.box_var v),
|
||||
if VarSet.mem (Var.t v) ctx.globally_bound_vars then MVarSet.empty
|
||||
else MVarSet.singleton v )
|
||||
| ETuple (args, s) ->
|
||||
let new_args, free_vars =
|
||||
List.fold_left
|
||||
(fun (new_args, free_vars) arg ->
|
||||
let new_arg, new_free_vars = aux arg in
|
||||
new_arg :: new_args, MVarSet.union new_free_vars free_vars)
|
||||
([], MVarSet.empty) args
|
||||
in
|
||||
( Bindlib.box_apply
|
||||
(fun new_args -> ETuple (List.rev new_args, s), Marked.get_mark e)
|
||||
(Bindlib.box_list new_args),
|
||||
free_vars )
|
||||
| ETupleAccess (e1, n, s, typs) ->
|
||||
let new_e1, free_vars = aux e1 in
|
||||
( Bindlib.box_apply
|
||||
(fun new_e1 -> ETupleAccess (new_e1, n, s, typs), Marked.get_mark e)
|
||||
new_e1,
|
||||
free_vars )
|
||||
| EInj (e1, n, e_name, typs) ->
|
||||
let new_e1, free_vars = aux e1 in
|
||||
( Bindlib.box_apply
|
||||
(fun new_e1 -> EInj (new_e1, n, e_name, typs), Marked.get_mark e)
|
||||
new_e1,
|
||||
free_vars )
|
||||
| EMatch (e1, arms, e_name) ->
|
||||
let new_e1, free_vars = aux e1 in
|
||||
(* We do not close the clotures inside the arms of the match expression,
|
||||
since they get a special treatment at compilation to Scalc. *)
|
||||
let new_arms, free_vars =
|
||||
List.fold_right
|
||||
(fun arm (new_arms, free_vars) ->
|
||||
match Marked.unmark arm with
|
||||
| EAbs (binder, typs) ->
|
||||
let vars, body = Bindlib.unmbind binder in
|
||||
let new_body, new_free_vars = aux body in
|
||||
let new_binder = Bindlib.bind_mvar vars new_body in
|
||||
( Bindlib.box_apply
|
||||
(fun new_binder ->
|
||||
EAbs (new_binder, typs), Marked.get_mark arm)
|
||||
new_binder
|
||||
:: new_arms,
|
||||
MVarSet.union free_vars new_free_vars )
|
||||
| _ -> failwith "should not happen")
|
||||
arms ([], free_vars)
|
||||
in
|
||||
( Bindlib.box_apply2
|
||||
(fun new_e1 new_arms ->
|
||||
EMatch (new_e1, new_arms, e_name), Marked.get_mark e)
|
||||
new_e1
|
||||
(Bindlib.box_list new_arms),
|
||||
free_vars )
|
||||
| EArray args ->
|
||||
let new_args, free_vars =
|
||||
List.fold_right
|
||||
(fun arg (new_args, free_vars) ->
|
||||
let new_arg, new_free_vars = aux arg in
|
||||
new_arg :: new_args, MVarSet.union free_vars new_free_vars)
|
||||
args ([], MVarSet.empty)
|
||||
in
|
||||
( Bindlib.box_apply
|
||||
(fun new_args -> EArray new_args, Marked.get_mark e)
|
||||
(Bindlib.box_list new_args),
|
||||
free_vars )
|
||||
| ELit l -> Bindlib.box (ELit l, Marked.get_mark e), MVarSet.empty
|
||||
| EApp ((EAbs (binder, typs_abs), e1_pos), args) ->
|
||||
(* let-binding, we should not close these *)
|
||||
let vars, body = Bindlib.unmbind binder in
|
||||
let new_body, free_vars = aux body in
|
||||
let new_binder = Bindlib.bind_mvar vars new_body in
|
||||
let new_args, free_vars =
|
||||
List.fold_right
|
||||
(fun arg (new_args, free_vars) ->
|
||||
let new_arg, new_free_vars = aux arg in
|
||||
new_arg :: new_args, MVarSet.union free_vars new_free_vars)
|
||||
args ([], free_vars)
|
||||
in
|
||||
( Bindlib.box_apply2
|
||||
(fun new_binder new_args ->
|
||||
( EApp ((EAbs (new_binder, typs_abs), e1_pos), new_args),
|
||||
Marked.get_mark e ))
|
||||
new_binder
|
||||
(Bindlib.box_list new_args),
|
||||
free_vars )
|
||||
| EAbs (binder, typs) ->
|
||||
(* λ x.t *)
|
||||
let binder_mark = Marked.get_mark e in
|
||||
let binder_pos = D.mark_pos binder_mark in
|
||||
(* Converting the closure. *)
|
||||
let vars, body = Bindlib.unmbind binder in
|
||||
(* t *)
|
||||
let new_body, body_vars = aux body in
|
||||
(* [[t]] *)
|
||||
let extra_vars =
|
||||
MVarSet.diff body_vars (MVarSet.of_list (Array.to_list vars))
|
||||
in
|
||||
let extra_vars_list = MVarSet.elements extra_vars in
|
||||
(* x1, ..., xn *)
|
||||
let code_var = new_var ctx.name_context in
|
||||
(* code *)
|
||||
let inner_c_var = new_var "env" in
|
||||
let any_ty = Dcalc.Ast.TAny, binder_pos in
|
||||
let new_closure_body =
|
||||
make_multiple_let_in
|
||||
(Array.of_list extra_vars_list)
|
||||
(List.map (fun _ -> any_ty) extra_vars_list)
|
||||
(List.mapi
|
||||
(fun i _ ->
|
||||
Bindlib.box_apply
|
||||
(fun inner_c_var ->
|
||||
( ETupleAccess
|
||||
( (inner_c_var, binder_mark),
|
||||
i + 1,
|
||||
None,
|
||||
List.map (fun _ -> any_ty) extra_vars_list ),
|
||||
binder_mark ))
|
||||
(Bindlib.box_var inner_c_var))
|
||||
extra_vars_list)
|
||||
new_body (D.mark_pos binder_mark)
|
||||
in
|
||||
let new_closure =
|
||||
make_abs
|
||||
(Array.concat [Array.make 1 inner_c_var; vars])
|
||||
new_closure_body
|
||||
((Dcalc.Ast.TAny, binder_pos) :: typs)
|
||||
(Marked.get_mark e)
|
||||
in
|
||||
( make_let_in code_var
|
||||
(Dcalc.Ast.TAny, D.pos e)
|
||||
new_closure
|
||||
(Bindlib.box_apply2
|
||||
(fun code_var extra_vars ->
|
||||
( ETuple
|
||||
( (code_var, binder_mark)
|
||||
:: List.map
|
||||
(fun extra_var -> extra_var, binder_mark)
|
||||
extra_vars,
|
||||
None ),
|
||||
Marked.get_mark e ))
|
||||
(Bindlib.box_var code_var)
|
||||
(Bindlib.box_list
|
||||
(List.map
|
||||
(fun extra_var -> Bindlib.box_var extra_var)
|
||||
extra_vars_list)))
|
||||
(D.pos e),
|
||||
extra_vars )
|
||||
| EApp ((EOp op, pos_op), args) ->
|
||||
(* This corresponds to an operator call, which we don't want to
|
||||
transform*)
|
||||
let new_args, free_vars =
|
||||
List.fold_right
|
||||
(fun arg (new_args, free_vars) ->
|
||||
let new_arg, new_free_vars = aux arg in
|
||||
new_arg :: new_args, MVarSet.union free_vars new_free_vars)
|
||||
args ([], MVarSet.empty)
|
||||
in
|
||||
( Bindlib.box_apply
|
||||
(fun new_e2 -> EApp ((EOp op, pos_op), new_e2), Marked.get_mark e)
|
||||
(Bindlib.box_list new_args),
|
||||
free_vars )
|
||||
| EApp ((EVar v, v_pos), args)
|
||||
when VarSet.mem (Var.t v) ctx.globally_bound_vars ->
|
||||
(* This corresponds to a scope call, which we don't want to transform*)
|
||||
let new_args, free_vars =
|
||||
List.fold_right
|
||||
(fun arg (new_args, free_vars) ->
|
||||
let new_arg, new_free_vars = aux arg in
|
||||
new_arg :: new_args, MVarSet.union free_vars new_free_vars)
|
||||
args ([], MVarSet.empty)
|
||||
in
|
||||
( Bindlib.box_apply2
|
||||
(fun new_v new_e2 -> EApp ((new_v, v_pos), new_e2), Marked.get_mark e)
|
||||
(Bindlib.box_var v)
|
||||
(Bindlib.box_list new_args),
|
||||
free_vars )
|
||||
| EApp (e1, args) ->
|
||||
let new_e1, free_vars = aux e1 in
|
||||
let env_var = new_var "env" in
|
||||
let code_var = new_var "code" in
|
||||
let new_args, free_vars =
|
||||
List.fold_right
|
||||
(fun arg (new_args, free_vars) ->
|
||||
let new_arg, new_free_vars = aux arg in
|
||||
new_arg :: new_args, MVarSet.union free_vars new_free_vars)
|
||||
args ([], free_vars)
|
||||
in
|
||||
let call_expr =
|
||||
make_let_in code_var
|
||||
(Dcalc.Ast.TAny, D.pos e)
|
||||
(Bindlib.box_apply
|
||||
(fun env_var ->
|
||||
( ETupleAccess
|
||||
((env_var, Marked.get_mark e1), 0, None, [ (*TODO: fill?*) ]),
|
||||
Marked.get_mark e ))
|
||||
(Bindlib.box_var env_var))
|
||||
(Bindlib.box_apply3
|
||||
(fun code_var env_var new_args ->
|
||||
( EApp
|
||||
( (code_var, Marked.get_mark e1),
|
||||
(env_var, Marked.get_mark e1) :: new_args ),
|
||||
Marked.get_mark e ))
|
||||
(Bindlib.box_var code_var) (Bindlib.box_var env_var)
|
||||
(Bindlib.box_list new_args))
|
||||
(D.pos e)
|
||||
in
|
||||
( make_let_in env_var (Dcalc.Ast.TAny, D.pos e) new_e1 call_expr (D.pos e),
|
||||
free_vars )
|
||||
| EAssert e1 ->
|
||||
let new_e1, free_vars = aux e1 in
|
||||
( Bindlib.box_apply
|
||||
(fun new_e1 -> EAssert new_e1, Marked.get_mark e)
|
||||
new_e1,
|
||||
free_vars )
|
||||
| EOp op -> Bindlib.box (EOp op, Marked.get_mark e), MVarSet.empty
|
||||
| EIfThenElse (e1, e2, e3) ->
|
||||
let new_e1, free_vars1 = aux e1 in
|
||||
let new_e2, free_vars2 = aux e2 in
|
||||
let new_e3, free_vars3 = aux e3 in
|
||||
( Bindlib.box_apply3
|
||||
(fun new_e1 new_e2 new_e3 ->
|
||||
EIfThenElse (new_e1, new_e2, new_e3), Marked.get_mark e)
|
||||
new_e1 new_e2 new_e3,
|
||||
MVarSet.union (MVarSet.union free_vars1 free_vars2) free_vars3 )
|
||||
| ERaise except ->
|
||||
Bindlib.box (ERaise except, Marked.get_mark e), MVarSet.empty
|
||||
| ECatch (e1, except, e2) ->
|
||||
let new_e1, free_vars1 = aux e1 in
|
||||
let new_e2, free_vars2 = aux e2 in
|
||||
( Bindlib.box_apply2
|
||||
(fun new_e1 new_e2 ->
|
||||
ECatch (new_e1, except, new_e2), Marked.get_mark e)
|
||||
new_e1 new_e2,
|
||||
MVarSet.union free_vars1 free_vars2 )
|
||||
in
|
||||
let e', _vars = aux e in
|
||||
e'
|
||||
|
||||
let closure_conversion (p : 'm program) : 'm program Bindlib.box =
|
||||
let new_scopes, _ =
|
||||
D.fold_left_scope_defs
|
||||
~f:
|
||||
(fun ((acc_new_scopes, global_vars) :
|
||||
(expr D.scopes Bindlib.box -> expr D.scopes Bindlib.box)
|
||||
* VarSet.t) (scope : expr D.scope_def) (scope_var : Var.t) ->
|
||||
~f:(fun (acc_new_scopes, global_vars) scope scope_var ->
|
||||
(* [acc_new_scopes] represents what has been translated in the past, it
|
||||
needs a continuation to attach the rest of the translated scopes. *)
|
||||
let scope_input_var, scope_body_expr =
|
||||
Bindlib.unbind scope.scope_body.scope_body_expr
|
||||
in
|
||||
let global_vars = VarSet.add scope_var global_vars in
|
||||
let global_vars = VarSet.add (Var.t scope_var) global_vars in
|
||||
let ctx =
|
||||
{
|
||||
name_context =
|
||||
Pos.unmark (Dcalc.Ast.ScopeName.get_info scope.scope_name);
|
||||
Marked.unmark (Dcalc.Ast.ScopeName.get_info scope.scope_name);
|
||||
globally_bound_vars = global_vars;
|
||||
}
|
||||
in
|
||||
let new_scope_lets =
|
||||
D.map_exprs_in_scope_lets
|
||||
~f:(fun e -> fst (closure_conversion_expr ctx e))
|
||||
~f:(closure_conversion_expr ctx)
|
||||
~varf:(fun v -> v)
|
||||
scope_body_expr
|
||||
in
|
||||
let new_scope_body_expr =
|
||||
|
@ -1,5 +1,5 @@
|
||||
(* This file is part of the Catala compiler, a specification language for tax
|
||||
and social benefits computation rules. Copyright (C) 2021 Inria, contributor:
|
||||
and social benefits computation rules. Copyright (C) 2022 Inria, contributor:
|
||||
Denis Merigoux <denis.merigoux@inria.fr>
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
@ -14,14 +14,6 @@
|
||||
License for the specific language governing permissions and limitations under
|
||||
the License. *)
|
||||
|
||||
(** Helper functions common to all Catala compiler backends *)
|
||||
|
||||
val to_ascii : string -> string
|
||||
(** Removes all non-ASCII diacritics from a string by converting them to their
|
||||
base letter in the Latin alphabet *)
|
||||
|
||||
val to_lowercase : string -> string
|
||||
(** Converts CamlCase into snake_case *)
|
||||
|
||||
val to_uppercase : string -> string
|
||||
(** Convertes snake_case into CamlCase *)
|
||||
val closure_conversion : 'm Ast.program -> 'm Ast.program Bindlib.box
|
||||
(** Warning/todo: no effort was yet made to ensure correct propagation of type
|
||||
annotations in the typed case *)
|
@ -18,11 +18,11 @@ open Utils
|
||||
module D = Dcalc.Ast
|
||||
module A = Ast
|
||||
|
||||
type ctx = A.Var.t D.VarMap.t
|
||||
type 'm ctx = 'm A.var D.VarMap.t
|
||||
(** This environment contains a mapping between the variables in Dcalc and their
|
||||
correspondance in Lcalc. *)
|
||||
|
||||
let translate_lit (l : D.lit) : A.expr =
|
||||
let translate_lit (l : D.lit) : 'm A.expr =
|
||||
match l with
|
||||
| D.LBool l -> A.ELit (A.LBool l)
|
||||
| D.LInt i -> A.ELit (A.LInt i)
|
||||
@ -33,105 +33,104 @@ let translate_lit (l : D.lit) : A.expr =
|
||||
| D.LDuration d -> A.ELit (A.LDuration d)
|
||||
| D.LEmptyError -> A.ERaise A.EmptyError
|
||||
|
||||
let thunk_expr (e : A.expr Pos.marked Bindlib.box) (pos : Pos.t) :
|
||||
A.expr Pos.marked Bindlib.box =
|
||||
let dummy_var = A.Var.make ("_", pos) in
|
||||
A.make_abs [| dummy_var |] e pos [D.TAny, pos] pos
|
||||
let thunk_expr (e : 'm A.marked_expr Bindlib.box) (mark : 'm A.mark) :
|
||||
'm A.marked_expr Bindlib.box =
|
||||
let dummy_var = A.new_var "_" in
|
||||
A.make_abs [| dummy_var |] e [D.TAny, D.mark_pos mark] mark
|
||||
|
||||
let rec translate_default
|
||||
(ctx : ctx)
|
||||
(exceptions : D.expr Pos.marked list)
|
||||
(just : D.expr Pos.marked)
|
||||
(cons : D.expr Pos.marked)
|
||||
(pos_default : Pos.t) : A.expr Pos.marked Bindlib.box =
|
||||
(ctx : 'm ctx)
|
||||
(exceptions : 'm D.marked_expr list)
|
||||
(just : 'm D.marked_expr)
|
||||
(cons : 'm D.marked_expr)
|
||||
(mark_default : 'm D.mark) : 'm A.marked_expr Bindlib.box =
|
||||
let exceptions =
|
||||
List.map
|
||||
(fun except -> thunk_expr (translate_expr ctx except) pos_default)
|
||||
(fun except -> thunk_expr (translate_expr ctx except) mark_default)
|
||||
exceptions
|
||||
in
|
||||
let exceptions =
|
||||
A.make_app
|
||||
(A.make_var (A.handle_default, pos_default))
|
||||
(A.make_var (A.Var.get A.handle_default, mark_default))
|
||||
[
|
||||
A.earray exceptions pos_default;
|
||||
thunk_expr (translate_expr ctx just) pos_default;
|
||||
thunk_expr (translate_expr ctx cons) pos_default;
|
||||
A.earray exceptions mark_default;
|
||||
thunk_expr (translate_expr ctx just) mark_default;
|
||||
thunk_expr (translate_expr ctx cons) mark_default;
|
||||
]
|
||||
pos_default
|
||||
mark_default
|
||||
in
|
||||
exceptions
|
||||
|
||||
and translate_expr (ctx : ctx) (e : D.expr Pos.marked) :
|
||||
A.expr Pos.marked Bindlib.box =
|
||||
match Pos.unmark e with
|
||||
| D.EVar v -> A.make_var (D.VarMap.find (Pos.unmark v) ctx, Pos.get_position e)
|
||||
and translate_expr (ctx : 'm ctx) (e : 'm D.marked_expr) :
|
||||
'm A.marked_expr Bindlib.box =
|
||||
match Marked.unmark e with
|
||||
| D.EVar v -> A.make_var (D.VarMap.find (D.Var.t v) ctx, Marked.get_mark e)
|
||||
| D.ETuple (args, s) ->
|
||||
A.etuple (List.map (translate_expr ctx) args) s (Pos.get_position e)
|
||||
A.etuple (List.map (translate_expr ctx) args) s (Marked.get_mark e)
|
||||
| D.ETupleAccess (e1, i, s, ts) ->
|
||||
A.etupleaccess (translate_expr ctx e1) i s ts (Pos.get_position e)
|
||||
A.etupleaccess (translate_expr ctx e1) i s ts (Marked.get_mark e)
|
||||
| D.EInj (e1, i, en, ts) ->
|
||||
A.einj (translate_expr ctx e1) i en ts (Pos.get_position e)
|
||||
A.einj (translate_expr ctx e1) i en ts (Marked.get_mark e)
|
||||
| D.EMatch (e1, cases, en) ->
|
||||
A.ematch (translate_expr ctx e1)
|
||||
(List.map (translate_expr ctx) cases)
|
||||
en (Pos.get_position e)
|
||||
en (Marked.get_mark e)
|
||||
| D.EArray es ->
|
||||
A.earray (List.map (translate_expr ctx) es) (Pos.get_position e)
|
||||
| D.ELit l -> Bindlib.box (Pos.same_pos_as (translate_lit l) e)
|
||||
| D.EOp op -> A.eop op (Pos.get_position e)
|
||||
A.earray (List.map (translate_expr ctx) es) (Marked.get_mark e)
|
||||
| D.ELit l -> Bindlib.box (Marked.same_mark_as (translate_lit l) e)
|
||||
| D.EOp op -> A.eop op (Marked.get_mark e)
|
||||
| D.EIfThenElse (e1, e2, e3) ->
|
||||
A.eifthenelse (translate_expr ctx e1) (translate_expr ctx e2)
|
||||
(translate_expr ctx e3) (Pos.get_position e)
|
||||
| D.EAssert e1 -> A.eassert (translate_expr ctx e1) (Pos.get_position e)
|
||||
(translate_expr ctx e3) (Marked.get_mark e)
|
||||
| D.EAssert e1 -> A.eassert (translate_expr ctx e1) (Marked.get_mark e)
|
||||
| D.ErrorOnEmpty arg ->
|
||||
A.ecatch (translate_expr ctx arg) A.EmptyError
|
||||
(Bindlib.box (Pos.same_pos_as (A.ERaise A.NoValueProvided) e))
|
||||
(Pos.get_position e)
|
||||
(Bindlib.box (Marked.same_mark_as (A.ERaise A.NoValueProvided) e))
|
||||
(Marked.get_mark e)
|
||||
| D.EApp (e1, args) ->
|
||||
A.eapp (translate_expr ctx e1)
|
||||
(List.map (translate_expr ctx) args)
|
||||
(Pos.get_position e)
|
||||
| D.EAbs ((binder, pos_binder), ts) ->
|
||||
(Marked.get_mark e)
|
||||
| D.EAbs (binder, ts) ->
|
||||
let vars, body = Bindlib.unmbind binder in
|
||||
let ctx, lc_vars =
|
||||
Array.fold_right
|
||||
(fun var (ctx, lc_vars) ->
|
||||
let lc_var = A.Var.make (Bindlib.name_of var, pos_binder) in
|
||||
D.VarMap.add var lc_var ctx, lc_var :: lc_vars)
|
||||
let lc_var = A.new_var (Bindlib.name_of var) in
|
||||
D.VarMap.add (D.Var.t var) lc_var ctx, lc_var :: lc_vars)
|
||||
vars (ctx, [])
|
||||
in
|
||||
let lc_vars = Array.of_list lc_vars in
|
||||
let new_body = translate_expr ctx body in
|
||||
let new_binder = Bindlib.bind_mvar lc_vars new_body in
|
||||
Bindlib.box_apply
|
||||
(fun new_binder ->
|
||||
Pos.same_pos_as (A.EAbs ((new_binder, pos_binder), ts)) e)
|
||||
(fun new_binder -> Marked.same_mark_as (A.EAbs (new_binder, ts)) e)
|
||||
new_binder
|
||||
| D.EDefault ([exn], just, cons) when !Cli.optimize_flag ->
|
||||
A.ecatch (translate_expr ctx exn) A.EmptyError
|
||||
(A.eifthenelse (translate_expr ctx just) (translate_expr ctx cons)
|
||||
(Bindlib.box (Pos.same_pos_as (A.ERaise A.EmptyError) e))
|
||||
(Pos.get_position e))
|
||||
(Pos.get_position e)
|
||||
(Bindlib.box (Marked.same_mark_as (A.ERaise A.EmptyError) e))
|
||||
(Marked.get_mark e))
|
||||
(Marked.get_mark e)
|
||||
| D.EDefault (exceptions, just, cons) ->
|
||||
translate_default ctx exceptions just cons (Pos.get_position e)
|
||||
translate_default ctx exceptions just cons (Marked.get_mark e)
|
||||
|
||||
let rec translate_scope_lets
|
||||
(decl_ctx : D.decl_ctx)
|
||||
(ctx : A.Var.t D.VarMap.t)
|
||||
(scope_lets : D.expr D.scope_body_expr) :
|
||||
A.expr D.scope_body_expr Bindlib.box =
|
||||
(ctx : 'm ctx)
|
||||
(scope_lets : ('m D.expr, 'm) D.scope_body_expr) :
|
||||
('m A.expr, 'm) D.scope_body_expr Bindlib.box =
|
||||
match scope_lets with
|
||||
| Result e -> Bindlib.box_apply (fun e -> D.Result e) (translate_expr ctx e)
|
||||
| ScopeLet scope_let ->
|
||||
let old_scope_let_var, scope_let_next =
|
||||
Bindlib.unbind scope_let.scope_let_next
|
||||
in
|
||||
let new_scope_let_var =
|
||||
A.Var.make (Bindlib.name_of old_scope_let_var, scope_let.scope_let_pos)
|
||||
in
|
||||
let new_scope_let_var = A.new_var (Bindlib.name_of old_scope_let_var) in
|
||||
let new_scope_let_expr = translate_expr ctx scope_let.scope_let_expr in
|
||||
let new_ctx = D.VarMap.add old_scope_let_var new_scope_let_var ctx in
|
||||
let new_ctx =
|
||||
D.VarMap.add (D.Var.t old_scope_let_var) new_scope_let_var ctx
|
||||
in
|
||||
let new_scope_next = translate_scope_lets decl_ctx new_ctx scope_let_next in
|
||||
let new_scope_next = Bindlib.bind_var new_scope_let_var new_scope_next in
|
||||
Bindlib.box_apply2
|
||||
@ -148,31 +147,29 @@ let rec translate_scope_lets
|
||||
|
||||
let rec translate_scopes
|
||||
(decl_ctx : D.decl_ctx)
|
||||
(ctx : A.Var.t D.VarMap.t)
|
||||
(scopes : D.expr D.scopes) : A.expr D.scopes Bindlib.box =
|
||||
(ctx : 'm ctx)
|
||||
(scopes : ('m D.expr, 'm) D.scopes) : ('m A.expr, 'm) D.scopes Bindlib.box =
|
||||
match scopes with
|
||||
| Nil -> Bindlib.box D.Nil
|
||||
| ScopeDef scope_def ->
|
||||
let old_scope_var, scope_next = Bindlib.unbind scope_def.scope_next in
|
||||
let new_scope_var =
|
||||
A.Var.make (D.ScopeName.get_info scope_def.scope_name)
|
||||
A.new_var (Marked.unmark (D.ScopeName.get_info scope_def.scope_name))
|
||||
in
|
||||
let old_scope_input_var, scope_body_expr =
|
||||
Bindlib.unbind scope_def.scope_body.scope_body_expr
|
||||
in
|
||||
let new_scope_input_var =
|
||||
A.Var.make
|
||||
( Bindlib.name_of old_scope_input_var,
|
||||
Pos.get_position (D.ScopeName.get_info scope_def.scope_name) )
|
||||
let new_scope_input_var = A.new_var (Bindlib.name_of old_scope_input_var) in
|
||||
let new_ctx =
|
||||
D.VarMap.add (D.Var.t old_scope_input_var) new_scope_input_var ctx
|
||||
in
|
||||
let new_ctx = D.VarMap.add old_scope_input_var new_scope_input_var ctx in
|
||||
let new_scope_body_expr =
|
||||
translate_scope_lets decl_ctx new_ctx scope_body_expr
|
||||
in
|
||||
let new_scope_body_expr =
|
||||
Bindlib.bind_var new_scope_input_var new_scope_body_expr
|
||||
in
|
||||
let new_scope : A.expr D.scope_body Bindlib.box =
|
||||
let new_scope : ('m A.expr, 'm) D.scope_body Bindlib.box =
|
||||
Bindlib.box_apply
|
||||
(fun new_scope_body_expr ->
|
||||
{
|
||||
@ -184,7 +181,7 @@ let rec translate_scopes
|
||||
})
|
||||
new_scope_body_expr
|
||||
in
|
||||
let new_ctx = D.VarMap.add old_scope_var new_scope_var new_ctx in
|
||||
let new_ctx = D.VarMap.add (D.Var.t old_scope_var) new_scope_var new_ctx in
|
||||
let scope_next =
|
||||
Bindlib.bind_var new_scope_var
|
||||
(translate_scopes decl_ctx new_ctx scope_next)
|
||||
@ -199,7 +196,7 @@ let rec translate_scopes
|
||||
})
|
||||
new_scope scope_next
|
||||
|
||||
let translate_program (prgm : D.program) : A.program =
|
||||
let translate_program (prgm : 'm D.program) : 'm A.program =
|
||||
{
|
||||
scopes =
|
||||
Bindlib.unbox (translate_scopes prgm.decl_ctx D.VarMap.empty prgm.scopes);
|
||||
|
@ -15,6 +15,6 @@
|
||||
the License. *)
|
||||
|
||||
(** Translation from the default calculus to the lambda calculus. This
|
||||
translation uses exceptions handle empty default terms. *)
|
||||
translation uses exceptions to handle empty default terms. *)
|
||||
|
||||
val translate_program : Dcalc.Ast.program -> Ast.program
|
||||
val translate_program : 'm Dcalc.Ast.program -> 'm Ast.program
|
||||
|
@ -40,12 +40,12 @@ module A = Ast
|
||||
hoisted and later handled by the [translate_expr] function. Every other
|
||||
cases is found in the translate_and_hoist function. *)
|
||||
|
||||
type hoists = D.expr Pos.marked A.VarMap.t
|
||||
type 'm hoists = 'm D.marked_expr A.VarMap.t
|
||||
(** Hoists definition. It represent bindings between [A.Var.t] and [D.expr]. *)
|
||||
|
||||
type info = {
|
||||
expr : A.expr Pos.marked Bindlib.box;
|
||||
var : A.expr Bindlib.var;
|
||||
type 'm info = {
|
||||
expr : 'm A.marked_expr Bindlib.box;
|
||||
var : 'm A.expr Bindlib.var;
|
||||
is_pure : bool;
|
||||
}
|
||||
(** Information about each encontered Dcalc variable is stored inside a context
|
||||
@ -54,19 +54,20 @@ type info = {
|
||||
indicating whenever the variable can be an EmptyError and hence should be
|
||||
matched (false) or if it never can be EmptyError (true). *)
|
||||
|
||||
let pp_info (fmt : Format.formatter) (info : info) =
|
||||
let pp_info (fmt : Format.formatter) (info : 'm info) =
|
||||
Format.fprintf fmt "{var: %a; is_pure: %b}" Print.format_var info.var
|
||||
info.is_pure
|
||||
|
||||
type ctx = {
|
||||
type 'm ctx = {
|
||||
decl_ctx : D.decl_ctx;
|
||||
vars : info D.VarMap.t;
|
||||
vars : 'm info D.VarMap.t;
|
||||
(** information context about variables in the current scope *)
|
||||
}
|
||||
|
||||
let _pp_ctx (fmt : Format.formatter) (ctx : ctx) =
|
||||
let pp_binding (fmt : Format.formatter) ((v, info) : D.Var.t * info) =
|
||||
Format.fprintf fmt "%a: %a" Dcalc.Print.format_var v pp_info info
|
||||
let _pp_ctx (fmt : Format.formatter) (ctx : 'm ctx) =
|
||||
let pp_binding (fmt : Format.formatter) ((v, info) : D.Var.t * 'm info) =
|
||||
Format.fprintf fmt "%a: %a" Dcalc.Print.format_var (D.Var.get v) pp_info
|
||||
info
|
||||
in
|
||||
|
||||
let pp_bindings =
|
||||
@ -79,10 +80,10 @@ let _pp_ctx (fmt : Format.formatter) (ctx : ctx) =
|
||||
|
||||
(** [find ~info n ctx] is a warpper to ocaml's Map.find that handle errors in a
|
||||
slightly better way. *)
|
||||
let find ?(info : string = "none") (n : D.Var.t) (ctx : ctx) : info =
|
||||
let find ?(info : string = "none") (n : 'm D.var) (ctx : 'm ctx) : 'm info =
|
||||
(* let _ = Format.asprintf "Searching for variable %a inside context %a"
|
||||
Dcalc.Print.format_var n pp_ctx ctx |> Cli.debug_print in *)
|
||||
try D.VarMap.find n ctx.vars
|
||||
try D.VarMap.find (D.Var.t n) ctx.vars
|
||||
with Not_found ->
|
||||
Errors.raise_spanned_error Pos.no_pos
|
||||
"Internal Error: Variable %a was not found in the current environment. \
|
||||
@ -93,16 +94,17 @@ let find ?(info : string = "none") (n : D.Var.t) (ctx : ctx) : info =
|
||||
var, creating a unique corresponding variable in Lcalc, with the
|
||||
corresponding expression, and the boolean is_pure. It is usefull for
|
||||
debuging purposes as it printing each of the Dcalc/Lcalc variable pairs. *)
|
||||
let add_var (pos : Pos.t) (var : D.Var.t) (is_pure : bool) (ctx : ctx) : ctx =
|
||||
let new_var = A.Var.make (Bindlib.name_of var, pos) in
|
||||
let expr = A.make_var (new_var, pos) in
|
||||
let add_var (mark : 'm D.mark) (var : 'm D.var) (is_pure : bool) (ctx : 'm ctx)
|
||||
: 'm ctx =
|
||||
let new_var = A.new_var (Bindlib.name_of var) in
|
||||
let expr = A.make_var (new_var, mark) in
|
||||
|
||||
(* Cli.debug_print @@ Format.asprintf "D.%a |-> A.%a" Dcalc.Print.format_var
|
||||
var Print.format_var new_var; *)
|
||||
{
|
||||
ctx with
|
||||
vars =
|
||||
D.VarMap.update var
|
||||
D.VarMap.update (D.Var.t var)
|
||||
(fun _ -> Some { expr; var = new_var; is_pure })
|
||||
ctx.vars;
|
||||
}
|
||||
@ -112,10 +114,11 @@ let add_var (pos : Pos.t) (var : D.Var.t) (is_pure : bool) (ctx : ctx) : ctx =
|
||||
Since positions where there is thunked expressions is exactly where we will
|
||||
put option expressions. Hence, the transformation simply reduce [unit -> 'a]
|
||||
into ['a option] recursivly. There is no polymorphism inside catala. *)
|
||||
let rec translate_typ (tau : D.typ Pos.marked) : D.typ Pos.marked =
|
||||
(Fun.flip Pos.same_pos_as) tau
|
||||
let rec translate_typ (tau : D.typ Marked.pos) : D.typ Marked.pos =
|
||||
(Fun.flip Marked.same_mark_as)
|
||||
tau
|
||||
begin
|
||||
match Pos.unmark tau with
|
||||
match Marked.unmark tau with
|
||||
| D.TLit l -> D.TLit l
|
||||
| D.TTuple (ts, s) -> D.TTuple (List.map translate_typ ts, s)
|
||||
| D.TEnum (ts, en) -> D.TEnum (List.map translate_typ ts, en)
|
||||
@ -160,10 +163,10 @@ let disjoint_union_maps (pos : Pos.t) (cs : 'a A.VarMap.t list) : 'a A.VarMap.t
|
||||
the equivalence between the execution of e and the execution of e' are
|
||||
equivalent in an environement where each variable v, where (v, e_v) is in
|
||||
hoists, has the non-empty value in e_v. *)
|
||||
let rec translate_and_hoist (ctx : ctx) (e : D.expr Pos.marked) :
|
||||
A.expr Pos.marked Bindlib.box * hoists =
|
||||
let pos = Pos.get_position e in
|
||||
match Pos.unmark e with
|
||||
let rec translate_and_hoist (ctx : 'm ctx) (e : 'm D.marked_expr) :
|
||||
'm A.marked_expr Bindlib.box * 'm hoists =
|
||||
let pos = Marked.get_mark e in
|
||||
match Marked.unmark e with
|
||||
(* empty-producing/using terms. We hoist those. (D.EVar in some cases,
|
||||
EApp(D.EVar _, [ELit LUnit]), EDefault _, ELit LEmptyDefault) I'm unsure
|
||||
about assert. *)
|
||||
@ -172,49 +175,47 @@ let rec translate_and_hoist (ctx : ctx) (e : D.expr Pos.marked) :
|
||||
current context) is thunked, hence matched in the next case. This
|
||||
assumption can change in the future, and this case is here for this
|
||||
reason. *)
|
||||
let v, pos_v = v in
|
||||
if not (find ~info:"search for a variable" v ctx).is_pure then
|
||||
let v' = A.Var.make (Bindlib.name_of v, pos_v) in
|
||||
let v' = A.new_var (Bindlib.name_of v) in
|
||||
(* Cli.debug_print @@ Format.asprintf "Found an unpure variable %a,
|
||||
created a variable %a to replace it" Dcalc.Print.format_var v
|
||||
Print.format_var v'; *)
|
||||
A.make_var (v', pos), A.VarMap.singleton v' e
|
||||
A.make_var (v', pos), A.VarMap.singleton (A.Var.t v') e
|
||||
else (find ~info:"should never happend" v ctx).expr, A.VarMap.empty
|
||||
| D.EApp ((D.EVar (v, pos_v), p), [(D.ELit D.LUnit, _)]) ->
|
||||
| D.EApp ((D.EVar v, p), [(D.ELit D.LUnit, _)]) ->
|
||||
if not (find ~info:"search for a variable" v ctx).is_pure then
|
||||
let v' = A.Var.make (Bindlib.name_of v, pos_v) in
|
||||
let v' = A.new_var (Bindlib.name_of v) in
|
||||
(* Cli.debug_print @@ Format.asprintf "Found an unpure variable %a,
|
||||
created a variable %a to replace it" Dcalc.Print.format_var v
|
||||
Print.format_var v'; *)
|
||||
A.make_var (v', pos), A.VarMap.singleton v' (D.EVar (v, pos_v), p)
|
||||
A.make_var (v', pos), A.VarMap.singleton (A.Var.t v') (D.EVar v, p)
|
||||
else
|
||||
Errors.raise_spanned_error pos
|
||||
Errors.raise_spanned_error (D.pos e)
|
||||
"Internal error: an pure variable was found in an unpure environment."
|
||||
| D.EDefault (_exceptions, _just, _cons) ->
|
||||
let v' = A.Var.make ("default_term", pos) in
|
||||
A.make_var (v', pos), A.VarMap.singleton v' e
|
||||
let v' = A.new_var "default_term" in
|
||||
A.make_var (v', pos), A.VarMap.singleton (A.Var.t v') e
|
||||
| D.ELit D.LEmptyError ->
|
||||
let v' = A.Var.make ("empty_litteral", pos) in
|
||||
A.make_var (v', pos), A.VarMap.singleton v' e
|
||||
let v' = A.new_var "empty_litteral" in
|
||||
A.make_var (v', pos), A.VarMap.singleton (A.Var.t v') e
|
||||
(* This one is a very special case. It transform an unpure expression
|
||||
environement to a pure expression. *)
|
||||
| ErrorOnEmpty arg ->
|
||||
(* [ match arg with | None -> raise NoValueProvided | Some v -> {{ v }} ] *)
|
||||
let silent_var = A.Var.make ("_", pos) in
|
||||
let x = A.Var.make ("non_empty_argument", pos) in
|
||||
let silent_var = A.new_var "_" in
|
||||
let x = A.new_var "non_empty_argument" in
|
||||
|
||||
let arg' = translate_expr ctx arg in
|
||||
|
||||
( A.make_matchopt_with_abs_arms arg'
|
||||
(A.make_abs [| silent_var |]
|
||||
(Bindlib.box (A.ERaise A.NoValueProvided, pos))
|
||||
pos
|
||||
[D.TAny, pos]
|
||||
[D.TAny, D.pos e]
|
||||
pos)
|
||||
(A.make_abs [| x |] (A.make_var (x, pos)) pos [D.TAny, pos] pos),
|
||||
(A.make_abs [| x |] (A.make_var (x, pos)) [D.TAny, D.pos e] pos),
|
||||
A.VarMap.empty )
|
||||
(* pure terms *)
|
||||
| D.ELit l -> A.elit (translate_lit l pos) pos, A.VarMap.empty
|
||||
| D.ELit l -> A.elit (translate_lit l (D.pos e)) pos, A.VarMap.empty
|
||||
| D.EIfThenElse (e1, e2, e3) ->
|
||||
let e1', h1 = translate_and_hoist ctx e1 in
|
||||
let e2', h2 = translate_and_hoist ctx e2 in
|
||||
@ -224,13 +225,13 @@ let rec translate_and_hoist (ctx : ctx) (e : D.expr Pos.marked) :
|
||||
|
||||
(*(* equivalent code : *) let e' = let+ e1' = e1' and+ e2' = e2' and+ e3' =
|
||||
e3' in (A.EIfThenElse (e1', e2', e3'), pos) in *)
|
||||
e', disjoint_union_maps pos [h1; h2; h3]
|
||||
e', disjoint_union_maps (D.pos e) [h1; h2; h3]
|
||||
| D.EAssert e1 ->
|
||||
(* same behavior as in the ICFP paper: if e1 is empty, then no error is
|
||||
raised. *)
|
||||
let e1', h1 = translate_and_hoist ctx e1 in
|
||||
A.eassert e1' pos, h1
|
||||
| D.EAbs ((binder, pos_binder), ts) ->
|
||||
| D.EAbs (binder, ts) ->
|
||||
let vars, body = Bindlib.unmbind binder in
|
||||
let ctx, lc_vars =
|
||||
ArrayLabels.fold_right vars ~init:(ctx, []) ~f:(fun var (ctx, lc_vars) ->
|
||||
@ -252,8 +253,7 @@ let rec translate_and_hoist (ctx : ctx) (e : D.expr Pos.marked) :
|
||||
let new_binder = Bindlib.bind_mvar lc_vars new_body in
|
||||
|
||||
( Bindlib.box_apply
|
||||
(fun new_binder ->
|
||||
A.EAbs ((new_binder, pos_binder), List.map translate_typ ts), pos)
|
||||
(fun new_binder -> A.EAbs (new_binder, List.map translate_typ ts), pos)
|
||||
new_binder,
|
||||
hoists )
|
||||
| EApp (e1, args) ->
|
||||
@ -262,7 +262,7 @@ let rec translate_and_hoist (ctx : ctx) (e : D.expr Pos.marked) :
|
||||
args |> List.map (translate_and_hoist ctx) |> List.split
|
||||
in
|
||||
|
||||
let hoists = disjoint_union_maps pos (h1 :: h_args) in
|
||||
let hoists = disjoint_union_maps (D.pos e) (h1 :: h_args) in
|
||||
let e' = A.eapp e1' args' pos in
|
||||
e', hoists
|
||||
| ETuple (args, s) ->
|
||||
@ -270,7 +270,7 @@ let rec translate_and_hoist (ctx : ctx) (e : D.expr Pos.marked) :
|
||||
args |> List.map (translate_and_hoist ctx) |> List.split
|
||||
in
|
||||
|
||||
let hoists = disjoint_union_maps pos h_args in
|
||||
let hoists = disjoint_union_maps (D.pos e) h_args in
|
||||
A.etuple args' s pos, hoists
|
||||
| ETupleAccess (e1, i, s, ts) ->
|
||||
let e1', hoists = translate_and_hoist ctx e1 in
|
||||
@ -286,75 +286,72 @@ let rec translate_and_hoist (ctx : ctx) (e : D.expr Pos.marked) :
|
||||
cases |> List.map (translate_and_hoist ctx) |> List.split
|
||||
in
|
||||
|
||||
let hoists = disjoint_union_maps pos (h1 :: h_cases) in
|
||||
let hoists = disjoint_union_maps (D.pos e) (h1 :: h_cases) in
|
||||
let e' = A.ematch e1' cases' en pos in
|
||||
e', hoists
|
||||
| EArray es ->
|
||||
let es', hoists = es |> List.map (translate_and_hoist ctx) |> List.split in
|
||||
|
||||
A.earray es' pos, disjoint_union_maps pos hoists
|
||||
A.earray es' pos, disjoint_union_maps (D.pos e) hoists
|
||||
| EOp op -> Bindlib.box (A.EOp op, pos), A.VarMap.empty
|
||||
|
||||
and translate_expr ?(append_esome = true) (ctx : ctx) (e : D.expr Pos.marked) :
|
||||
A.expr Pos.marked Bindlib.box =
|
||||
and translate_expr ?(append_esome = true) (ctx : 'm ctx) (e : 'm D.marked_expr)
|
||||
: 'm A.marked_expr Bindlib.box =
|
||||
let e', hoists = translate_and_hoist ctx e in
|
||||
let hoists = A.VarMap.bindings hoists in
|
||||
|
||||
let _pos = Pos.get_position e in
|
||||
let _pos = Marked.get_mark e in
|
||||
|
||||
(* build the hoists *)
|
||||
(* Cli.debug_print @@ Format.asprintf "hoist for the expression: [%a]"
|
||||
(Format.pp_print_list Print.format_var) (List.map fst hoists); *)
|
||||
ListLabels.fold_left hoists
|
||||
~init:(if append_esome then A.make_some e' else e')
|
||||
~f:(fun acc (v, (hoist, pos_hoist)) ->
|
||||
~f:(fun acc (v, (hoist, mark_hoist)) ->
|
||||
(* Cli.debug_print @@ Format.asprintf "hoist using A.%a" Print.format_var
|
||||
v; *)
|
||||
let c' : A.expr Pos.marked Bindlib.box =
|
||||
let c' : 'm A.marked_expr Bindlib.box =
|
||||
match hoist with
|
||||
(* Here we have to handle only the cases appearing in hoists, as defined
|
||||
the [translate_and_hoist] function. *)
|
||||
| D.EVar v ->
|
||||
(find ~info:"should never happend" (Pos.unmark v) ctx).expr
|
||||
| D.EVar v -> (find ~info:"should never happend" v ctx).expr
|
||||
| D.EDefault (excep, just, cons) ->
|
||||
let excep' = List.map (translate_expr ctx) excep in
|
||||
let just' = translate_expr ctx just in
|
||||
let cons' = translate_expr ctx cons in
|
||||
(* calls handle_option. *)
|
||||
A.make_app
|
||||
(A.make_var (A.handle_default_opt, pos_hoist))
|
||||
(A.make_var (A.Var.get A.handle_default_opt, mark_hoist))
|
||||
[
|
||||
Bindlib.box_apply
|
||||
(fun excep' -> A.EArray excep', pos_hoist)
|
||||
(fun excep' -> A.EArray excep', mark_hoist)
|
||||
(Bindlib.box_list excep');
|
||||
just';
|
||||
cons';
|
||||
]
|
||||
pos_hoist
|
||||
| D.ELit D.LEmptyError -> A.make_none pos_hoist
|
||||
mark_hoist
|
||||
| D.ELit D.LEmptyError -> A.make_none mark_hoist
|
||||
| D.EAssert arg ->
|
||||
let arg' = translate_expr ctx arg in
|
||||
|
||||
(* [ match arg with | None -> raise NoValueProvided | Some v -> assert
|
||||
{{ v }} ] *)
|
||||
let silent_var = A.Var.make ("_", pos_hoist) in
|
||||
let x = A.Var.make ("assertion_argument", pos_hoist) in
|
||||
let silent_var = A.new_var "_" in
|
||||
let x = A.new_var "assertion_argument" in
|
||||
|
||||
A.make_matchopt_with_abs_arms arg'
|
||||
(A.make_abs [| silent_var |]
|
||||
(Bindlib.box (A.ERaise A.NoValueProvided, pos_hoist))
|
||||
pos_hoist
|
||||
[D.TAny, pos_hoist]
|
||||
pos_hoist)
|
||||
(Bindlib.box (A.ERaise A.NoValueProvided, mark_hoist))
|
||||
[D.TAny, D.mark_pos mark_hoist]
|
||||
mark_hoist)
|
||||
(A.make_abs [| x |]
|
||||
(Bindlib.box_apply
|
||||
(fun arg -> A.EAssert arg, pos_hoist)
|
||||
(A.make_var (x, pos_hoist)))
|
||||
pos_hoist
|
||||
[D.TAny, pos_hoist]
|
||||
pos_hoist)
|
||||
(fun arg -> A.EAssert arg, mark_hoist)
|
||||
(A.make_var (x, mark_hoist)))
|
||||
[D.TAny, D.mark_pos mark_hoist]
|
||||
mark_hoist)
|
||||
| _ ->
|
||||
Errors.raise_spanned_error pos_hoist
|
||||
Errors.raise_spanned_error (D.mark_pos mark_hoist)
|
||||
"Internal Error: An term was found in a position where it should \
|
||||
not be"
|
||||
in
|
||||
@ -363,11 +360,14 @@ and translate_expr ?(append_esome = true) (ctx : ctx) (e : D.expr Pos.marked) :
|
||||
] *)
|
||||
(* Cli.debug_print @@ Format.asprintf "build matchopt using %a"
|
||||
Print.format_var v; *)
|
||||
A.make_matchopt pos_hoist v (D.TAny, pos_hoist) c' (A.make_none pos_hoist)
|
||||
acc)
|
||||
A.make_matchopt mark_hoist (A.Var.get v)
|
||||
(D.TAny, D.mark_pos mark_hoist)
|
||||
c' (A.make_none mark_hoist) acc)
|
||||
|
||||
let rec translate_scope_let (ctx : ctx) (lets : D.expr D.scope_body_expr) :
|
||||
A.expr D.scope_body_expr Bindlib.box =
|
||||
let rec translate_scope_let
|
||||
(ctx : 'm ctx)
|
||||
(lets : ('m D.expr, 'm) D.scope_body_expr) :
|
||||
('m A.expr, 'm) D.scope_body_expr Bindlib.box =
|
||||
match lets with
|
||||
| Result e ->
|
||||
Bindlib.box_apply
|
||||
@ -377,7 +377,7 @@ let rec translate_scope_let (ctx : ctx) (lets : D.expr D.scope_body_expr) :
|
||||
{
|
||||
scope_let_kind = SubScopeVarDefinition;
|
||||
scope_let_typ = typ;
|
||||
scope_let_expr = D.EAbs ((binder, _), _), _;
|
||||
scope_let_expr = D.EAbs (binder, _), emark;
|
||||
scope_let_next = next;
|
||||
scope_let_pos = pos;
|
||||
} ->
|
||||
@ -389,7 +389,8 @@ let rec translate_scope_let (ctx : ctx) (lets : D.expr D.scope_body_expr) :
|
||||
let var, next = Bindlib.unbind next in
|
||||
(* Cli.debug_print @@ Format.asprintf "unbinding %a" Dcalc.Print.format_var
|
||||
var; *)
|
||||
let ctx' = add_var pos var var_is_pure ctx in
|
||||
let vmark = D.map_mark (fun _ -> pos) (fun _ -> typ) emark in
|
||||
let ctx' = add_var vmark var var_is_pure ctx in
|
||||
let new_var = (find ~info:"variable that was just created" var ctx').var in
|
||||
let new_next = translate_scope_let ctx' next in
|
||||
Bindlib.box_apply2
|
||||
@ -408,7 +409,7 @@ let rec translate_scope_let (ctx : ctx) (lets : D.expr D.scope_body_expr) :
|
||||
{
|
||||
scope_let_kind = SubScopeVarDefinition;
|
||||
scope_let_typ = typ;
|
||||
scope_let_expr = (D.ErrorOnEmpty _, _) as expr;
|
||||
scope_let_expr = (D.ErrorOnEmpty _, emark) as expr;
|
||||
scope_let_next = next;
|
||||
scope_let_pos = pos;
|
||||
} ->
|
||||
@ -417,7 +418,8 @@ let rec translate_scope_let (ctx : ctx) (lets : D.expr D.scope_body_expr) :
|
||||
let var, next = Bindlib.unbind next in
|
||||
(* Cli.debug_print @@ Format.asprintf "unbinding %a" Dcalc.Print.format_var
|
||||
var; *)
|
||||
let ctx' = add_var pos var var_is_pure ctx in
|
||||
let vmark = D.map_mark (fun _ -> pos) (fun _ -> typ) emark in
|
||||
let ctx' = add_var vmark var var_is_pure ctx in
|
||||
let new_var = (find ~info:"variable that was just created" var ctx').var in
|
||||
Bindlib.box_apply2
|
||||
(fun new_expr new_next ->
|
||||
@ -459,7 +461,7 @@ let rec translate_scope_let (ctx : ctx) (lets : D.expr D.scope_body_expr) :
|
||||
can do so by looking at the typ of the destructuring: if it's
|
||||
thunked, then the variable is context. If it's not thunked, it's a
|
||||
regular input. *)
|
||||
match Pos.unmark typ with
|
||||
match Marked.unmark typ with
|
||||
| D.TArrow ((D.TLit D.TUnit, _), _) -> false
|
||||
| _ -> true)
|
||||
| ScopeVarDefinition | SubScopeVarDefinition | CallingSubScope
|
||||
@ -469,7 +471,10 @@ let rec translate_scope_let (ctx : ctx) (lets : D.expr D.scope_body_expr) :
|
||||
let var, next = Bindlib.unbind next in
|
||||
(* Cli.debug_print @@ Format.asprintf "unbinding %a" Dcalc.Print.format_var
|
||||
var; *)
|
||||
let ctx' = add_var pos var var_is_pure ctx in
|
||||
let vmark =
|
||||
D.map_mark (fun _ -> pos) (fun _ -> typ) (Marked.get_mark expr)
|
||||
in
|
||||
let ctx' = add_var vmark var var_is_pure ctx in
|
||||
let new_var = (find ~info:"variable that was just created" var ctx').var in
|
||||
Bindlib.box_apply2
|
||||
(fun new_expr new_next ->
|
||||
@ -486,8 +491,9 @@ let rec translate_scope_let (ctx : ctx) (lets : D.expr D.scope_body_expr) :
|
||||
|
||||
let translate_scope_body
|
||||
(scope_pos : Pos.t)
|
||||
(ctx : ctx)
|
||||
(body : D.expr D.scope_body) : A.expr D.scope_body Bindlib.box =
|
||||
(ctx : 'm ctx)
|
||||
(body : ('m D.expr, 'm) D.scope_body) :
|
||||
('m A.expr, 'm) D.scope_body Bindlib.box =
|
||||
match body with
|
||||
| {
|
||||
scope_body_expr = result;
|
||||
@ -495,7 +501,14 @@ let translate_scope_body
|
||||
scope_body_output_struct = output_struct;
|
||||
} ->
|
||||
let v, lets = Bindlib.unbind result in
|
||||
let ctx' = add_var scope_pos v true ctx in
|
||||
let vmark =
|
||||
let m =
|
||||
match lets with
|
||||
| Result e | ScopeLet { scope_let_expr = e; _ } -> Marked.get_mark e
|
||||
in
|
||||
D.map_mark (fun _ -> scope_pos) (fun ty -> ty) m
|
||||
in
|
||||
let ctx' = add_var vmark v true ctx in
|
||||
let v' = (find ~info:"variable that was just created" v ctx').var in
|
||||
Bindlib.box_apply
|
||||
(fun new_expr ->
|
||||
@ -506,18 +519,23 @@ let translate_scope_body
|
||||
})
|
||||
(Bindlib.bind_var v' (translate_scope_let ctx' lets))
|
||||
|
||||
let rec translate_scopes (ctx : ctx) (scopes : D.expr D.scopes) :
|
||||
A.expr D.scopes Bindlib.box =
|
||||
let rec translate_scopes (ctx : 'm ctx) (scopes : ('m D.expr, 'm) D.scopes) :
|
||||
('m A.expr, 'm) D.scopes Bindlib.box =
|
||||
match scopes with
|
||||
| Nil -> Bindlib.box D.Nil
|
||||
| ScopeDef { scope_name; scope_body; scope_next } ->
|
||||
let scope_var, next = Bindlib.unbind scope_next in
|
||||
let new_ctx = add_var Pos.no_pos scope_var true ctx in
|
||||
let vmark =
|
||||
match Bindlib.unbind scope_body.scope_body_expr with
|
||||
| _, (Result e | ScopeLet { scope_let_expr = e; _ }) -> Marked.get_mark e
|
||||
in
|
||||
|
||||
let new_ctx = add_var vmark scope_var true ctx in
|
||||
let new_scope_name =
|
||||
(find ~info:"variable that was just created" scope_var new_ctx).var
|
||||
in
|
||||
|
||||
let scope_pos = Pos.get_position (D.ScopeName.get_info scope_name) in
|
||||
let scope_pos = Marked.get_mark (D.ScopeName.get_info scope_name) in
|
||||
|
||||
let new_body = translate_scope_body scope_pos ctx scope_body in
|
||||
let tail = translate_scopes new_ctx next in
|
||||
@ -528,7 +546,7 @@ let rec translate_scopes (ctx : ctx) (scopes : D.expr D.scopes) :
|
||||
new_body
|
||||
(Bindlib.bind_var new_scope_name tail)
|
||||
|
||||
let translate_program (prgm : D.program) : A.program =
|
||||
let translate_program (prgm : 'm D.program) : 'm A.program =
|
||||
let inputs_structs =
|
||||
D.fold_left_scope_defs prgm.scopes ~init:[] ~f:(fun acc scope_def _ ->
|
||||
scope_def.D.scope_body.scope_body_input_struct :: acc)
|
||||
|
@ -19,4 +19,4 @@
|
||||
transformation is one piece to permit to compile toward legacy languages
|
||||
that does not contains exceptions. *)
|
||||
|
||||
val translate_program : Dcalc.Ast.program -> Ast.program
|
||||
val translate_program : 'm Dcalc.Ast.program -> 'm Ast.program
|
||||
|
@ -1,7 +1,7 @@
|
||||
(library
|
||||
(name lcalc)
|
||||
(public_name catala.lcalc)
|
||||
(libraries bindlib dcalc scopelang runtime)
|
||||
(libraries bindlib ubase dcalc scopelang catala.runtime_ocaml)
|
||||
(preprocess
|
||||
(pps visitors.ppx)))
|
||||
|
||||
|
@ -15,19 +15,20 @@
|
||||
the License. *)
|
||||
open Utils
|
||||
open Ast
|
||||
module D = Dcalc.Ast
|
||||
|
||||
let ( let+ ) x f = Bindlib.box_apply f x
|
||||
let ( and+ ) x y = Bindlib.box_pair x y
|
||||
|
||||
let visitor_map
|
||||
(t : 'a -> expr Pos.marked -> expr Pos.marked Bindlib.box)
|
||||
(t : 'a -> 'm marked_expr -> 'm marked_expr Bindlib.box)
|
||||
(ctx : 'a)
|
||||
(e : expr Pos.marked) : expr Pos.marked Bindlib.box =
|
||||
(e : 'm marked_expr) : 'm marked_expr Bindlib.box =
|
||||
(* calls [t ctx] on every direct childs of [e], then rebuild an abstract
|
||||
syntax tree modified. Used in other transformations. *)
|
||||
let default_mark e' = Pos.same_pos_as e' e in
|
||||
match Pos.unmark e with
|
||||
| EVar (v, _pos) ->
|
||||
let default_mark e' = Marked.same_mark_as e' e in
|
||||
match Marked.unmark e with
|
||||
| EVar v ->
|
||||
let+ v = Bindlib.box_var v in
|
||||
default_mark @@ v
|
||||
| ETuple (args, n) ->
|
||||
@ -46,11 +47,11 @@ let visitor_map
|
||||
| EArray args ->
|
||||
let+ args = args |> List.map (t ctx) |> Bindlib.box_list in
|
||||
default_mark @@ EArray args
|
||||
| EAbs ((binder, pos_binder), ts) ->
|
||||
| EAbs (binder, ts) ->
|
||||
let vars, body = Bindlib.unmbind binder in
|
||||
let body = t ctx body in
|
||||
let+ binder = Bindlib.bind_mvar vars body in
|
||||
default_mark @@ EAbs ((binder, pos_binder), ts)
|
||||
default_mark @@ EAbs (binder, ts)
|
||||
| EApp (e1, args) ->
|
||||
let+ e1 = t ctx e1
|
||||
and+ args = args |> List.map (t ctx) |> Bindlib.box_list in
|
||||
@ -66,10 +67,9 @@ let visitor_map
|
||||
default_mark @@ ECatch (e1, exn, e2)
|
||||
| ERaise _ | ELit _ | EOp _ -> Bindlib.box e
|
||||
|
||||
let rec iota_expr (_ : unit) (e : expr Pos.marked) : expr Pos.marked Bindlib.box
|
||||
=
|
||||
let default_mark e' = Pos.mark (Pos.get_position e) e' in
|
||||
match Pos.unmark e with
|
||||
let rec iota_expr (_ : unit) (e : 'm marked_expr) : 'm marked_expr Bindlib.box =
|
||||
let default_mark e' = Marked.mark (Marked.get_mark e) e' in
|
||||
match Marked.unmark e with
|
||||
| EMatch ((EInj (e1, i, n', _ts), _), cases, n)
|
||||
when Dcalc.Ast.EnumName.compare n n' = 0 ->
|
||||
let+ e1 = visitor_map iota_expr () e1
|
||||
@ -86,42 +86,45 @@ let rec iota_expr (_ : unit) (e : expr Pos.marked) : expr Pos.marked Bindlib.box
|
||||
visitor_map iota_expr () e'
|
||||
| _ -> visitor_map iota_expr () e
|
||||
|
||||
let rec beta_expr (_ : unit) (e : expr Pos.marked) : expr Pos.marked Bindlib.box
|
||||
=
|
||||
let default_mark e' = Pos.same_pos_as e' e in
|
||||
match Pos.unmark e with
|
||||
let rec beta_expr (_ : unit) (e : 'm marked_expr) : 'm marked_expr Bindlib.box =
|
||||
let default_mark e' = Marked.same_mark_as e' e in
|
||||
match Marked.unmark e with
|
||||
| EApp (e1, args) -> (
|
||||
let+ e1 = beta_expr () e1
|
||||
and+ args = List.map (beta_expr ()) args |> Bindlib.box_list in
|
||||
match Pos.unmark e1 with
|
||||
| EAbs ((binder, _pos_binder), _ts) ->
|
||||
match Marked.unmark e1 with
|
||||
| EAbs (binder, _ts) ->
|
||||
let (_ : (_, _) Bindlib.mbinder) = binder in
|
||||
Bindlib.msubst binder (List.map fst args |> Array.of_list)
|
||||
| _ -> default_mark @@ EApp (e1, args))
|
||||
| _ -> visitor_map beta_expr () e
|
||||
|
||||
let iota_optimizations (p : program) : program =
|
||||
let new_scopes = Dcalc.Ast.map_exprs_in_scopes ~f:(iota_expr ()) p.scopes in
|
||||
{ p with scopes = Bindlib.unbox new_scopes }
|
||||
let iota_optimizations (p : 'm program) : 'm program =
|
||||
let new_scopes =
|
||||
Dcalc.Ast.map_exprs_in_scopes ~f:(iota_expr ()) ~varf:(fun v -> v) p.scopes
|
||||
in
|
||||
{ p with D.scopes = Bindlib.unbox new_scopes }
|
||||
|
||||
(* TODO: beta optimizations apply inlining of the program. We left the inclusion
|
||||
of beta-optimization as future work since its produce code that is harder to
|
||||
read, and can produce exponential blowup of the size of the generated
|
||||
program. *)
|
||||
let _beta_optimizations (p : program) : program =
|
||||
let new_scopes = Dcalc.Ast.map_exprs_in_scopes ~f:(beta_expr ()) p.scopes in
|
||||
let _beta_optimizations (p : 'm program) : 'm program =
|
||||
let new_scopes =
|
||||
Dcalc.Ast.map_exprs_in_scopes ~f:(beta_expr ()) ~varf:(fun v -> v) p.scopes
|
||||
in
|
||||
{ p with scopes = Bindlib.unbox new_scopes }
|
||||
|
||||
let rec peephole_expr (_ : unit) (e : expr Pos.marked) :
|
||||
expr Pos.marked Bindlib.box =
|
||||
let default_mark e' = Pos.mark (Pos.get_position e) e' in
|
||||
let rec peephole_expr (_ : unit) (e : 'm marked_expr) :
|
||||
'm marked_expr Bindlib.box =
|
||||
let default_mark e' = Marked.mark (Marked.get_mark e) e' in
|
||||
|
||||
match Pos.unmark e with
|
||||
match Marked.unmark e with
|
||||
| EIfThenElse (e1, e2, e3) -> (
|
||||
let+ e1 = peephole_expr () e1
|
||||
and+ e2 = peephole_expr () e2
|
||||
and+ e3 = peephole_expr () e3 in
|
||||
match Pos.unmark e1 with
|
||||
match Marked.unmark e1 with
|
||||
| ELit (LBool true)
|
||||
| EApp ((EOp (Unop (Log _)), _), [(ELit (LBool true), _)]) ->
|
||||
e2
|
||||
@ -131,7 +134,7 @@ let rec peephole_expr (_ : unit) (e : expr Pos.marked) :
|
||||
| _ -> default_mark @@ EIfThenElse (e1, e2, e3))
|
||||
| ECatch (e1, except, e2) -> (
|
||||
let+ e1 = peephole_expr () e1 and+ e2 = peephole_expr () e2 in
|
||||
match Pos.unmark e1, Pos.unmark e2 with
|
||||
match Marked.unmark e1, Marked.unmark e2 with
|
||||
| ERaise except', ERaise except'' when except' = except && except = except''
|
||||
->
|
||||
default_mark @@ ERaise except
|
||||
@ -140,11 +143,13 @@ let rec peephole_expr (_ : unit) (e : expr Pos.marked) :
|
||||
| _ -> default_mark @@ ECatch (e1, except, e2))
|
||||
| _ -> visitor_map peephole_expr () e
|
||||
|
||||
let peephole_optimizations (p : program) : program =
|
||||
let peephole_optimizations (p : 'm program) : 'm program =
|
||||
let new_scopes =
|
||||
Dcalc.Ast.map_exprs_in_scopes ~f:(peephole_expr ()) p.scopes
|
||||
Dcalc.Ast.map_exprs_in_scopes ~f:(peephole_expr ())
|
||||
~varf:(fun v -> v)
|
||||
p.scopes
|
||||
in
|
||||
{ p with scopes = Bindlib.unbox new_scopes }
|
||||
|
||||
let optimize_program (p : program) : program =
|
||||
p |> iota_optimizations |> peephole_optimizations
|
||||
let optimize_program (p : 'm program) : Dcalc.Ast.untyped program =
|
||||
p |> iota_optimizations |> peephole_optimizations |> untype_program
|
||||
|
@ -16,4 +16,6 @@
|
||||
|
||||
open Ast
|
||||
|
||||
val optimize_program : program -> program
|
||||
val optimize_program : 'm program -> Dcalc.Ast.untyped program
|
||||
(** Warning/todo: no effort was yet made to ensure correct propagation of type
|
||||
annotations in the typed case *)
|
||||
|
@ -17,22 +17,10 @@
|
||||
open Utils
|
||||
open Ast
|
||||
|
||||
let is_uppercase (x : CamomileLibraryDefault.Camomile.UChar.t) : bool =
|
||||
try
|
||||
match CamomileLibraryDefault.Camomile.UCharInfo.general_category x with
|
||||
| `Ll -> false
|
||||
| `Lu -> true
|
||||
| _ -> false
|
||||
with _ -> true
|
||||
|
||||
let begins_with_uppercase (s : string) : bool =
|
||||
let first_letter = CamomileLibraryDefault.Camomile.UTF8.get s 0 in
|
||||
is_uppercase first_letter
|
||||
|
||||
(** {b Note:} (EmileRolley) seems to be factorizable with
|
||||
Dcalc.Print.format_lit. *)
|
||||
let format_lit (fmt : Format.formatter) (l : lit Pos.marked) : unit =
|
||||
match Pos.unmark l with
|
||||
let format_lit (fmt : Format.formatter) (l : lit Marked.pos) : unit =
|
||||
match Marked.unmark l with
|
||||
| LBool b -> Dcalc.Print.format_lit_style fmt (string_of_bool b)
|
||||
| LInt i -> Dcalc.Print.format_lit_style fmt (Runtime.integer_to_string i)
|
||||
| LUnit -> Dcalc.Print.format_lit_style fmt "()"
|
||||
@ -68,26 +56,26 @@ let format_keyword (fmt : Format.formatter) (s : string) : unit =
|
||||
let format_punctuation (fmt : Format.formatter) (s : string) : unit =
|
||||
Format.fprintf fmt "%a" (Utils.Cli.format_with_style [ANSITerminal.cyan]) s
|
||||
|
||||
let needs_parens (e : expr Pos.marked) : bool =
|
||||
match Pos.unmark e with EAbs _ | ETuple (_, Some _) -> true | _ -> false
|
||||
let needs_parens (e : 'm marked_expr) : bool =
|
||||
match Marked.unmark e with EAbs _ | ETuple (_, Some _) -> true | _ -> false
|
||||
|
||||
let format_var (fmt : Format.formatter) (v : Var.t) : unit =
|
||||
let format_var (fmt : Format.formatter) (v : 'm Ast.var) : unit =
|
||||
Format.fprintf fmt "%s_%d" (Bindlib.name_of v) (Bindlib.uid_of v)
|
||||
|
||||
let rec format_expr
|
||||
?(debug : bool = false)
|
||||
(ctx : Dcalc.Ast.decl_ctx)
|
||||
(fmt : Format.formatter)
|
||||
(e : expr Pos.marked) : unit =
|
||||
(e : 'm marked_expr) : unit =
|
||||
let format_expr = format_expr ctx ~debug in
|
||||
let format_with_parens (fmt : Format.formatter) (e : expr Pos.marked) =
|
||||
let format_with_parens (fmt : Format.formatter) (e : 'm marked_expr) =
|
||||
if needs_parens e then
|
||||
Format.fprintf fmt "%a%a%a" format_punctuation "(" format_expr e
|
||||
format_punctuation ")"
|
||||
else Format.fprintf fmt "%a" format_expr e
|
||||
in
|
||||
match Pos.unmark e with
|
||||
| EVar v -> Format.fprintf fmt "%a" format_var (Pos.unmark v)
|
||||
match Marked.unmark e with
|
||||
| EVar v -> Format.fprintf fmt "%a" format_var v
|
||||
| ETuple (es, None) ->
|
||||
Format.fprintf fmt "@[<hov 2>%a%a%a@]" format_punctuation "("
|
||||
(Format.pp_print_list
|
||||
@ -136,23 +124,23 @@ let rec format_expr
|
||||
format_expr e))
|
||||
(List.combine es
|
||||
(List.map fst (Dcalc.Ast.EnumMap.find e_name ctx.ctx_enums)))
|
||||
| ELit l -> Format.fprintf fmt "%a" format_lit (Pos.same_pos_as l e)
|
||||
| EApp ((EAbs ((binder, _), taus), _), args) ->
|
||||
| ELit l ->
|
||||
Format.fprintf fmt "%a" format_lit (Marked.mark (Dcalc.Ast.pos e) l)
|
||||
| EApp ((EAbs (binder, taus), _), args) ->
|
||||
let xs, body = Bindlib.unmbind binder in
|
||||
let xs_tau = List.map2 (fun x tau -> x, tau) (Array.to_list xs) taus in
|
||||
let xs_tau_arg = List.map2 (fun (x, tau) arg -> x, tau, arg) xs_tau args in
|
||||
Format.fprintf fmt "%a%a"
|
||||
(Format.pp_print_list
|
||||
~pp_sep:(fun fmt () -> Format.fprintf fmt "")
|
||||
(fun fmt (x, tau, arg) ->
|
||||
(fun fmt ((x, tau), arg) ->
|
||||
Format.fprintf fmt "@[<hov 2>%a@ %a@ %a@ %a@ %a@ %a@ %a@]@\n"
|
||||
format_keyword "let" format_var x format_punctuation ":"
|
||||
(Dcalc.Print.format_typ ctx)
|
||||
tau format_punctuation "=" format_expr arg format_keyword "in"))
|
||||
xs_tau_arg format_expr body
|
||||
| EAbs ((binder, _), taus) ->
|
||||
(Marked.unmark tau) format_punctuation "=" format_expr arg
|
||||
format_keyword "in"))
|
||||
(List.combine (List.combine (Array.to_list xs) taus) args)
|
||||
format_expr body
|
||||
| EAbs (binder, taus) ->
|
||||
let xs, body = Bindlib.unmbind binder in
|
||||
let xs_tau = List.map2 (fun x tau -> x, tau) (Array.to_list xs) taus in
|
||||
Format.fprintf fmt "@[<hov 2>%a %a %a@ %a@]" format_punctuation "λ"
|
||||
(Format.pp_print_list
|
||||
~pp_sep:(fun fmt () -> Format.fprintf fmt "@ ")
|
||||
@ -160,21 +148,22 @@ let rec format_expr
|
||||
Format.fprintf fmt "%a%a%a %a%a" format_punctuation "(" format_var x
|
||||
format_punctuation ":"
|
||||
(Dcalc.Print.format_typ ctx)
|
||||
tau format_punctuation ")"))
|
||||
xs_tau format_punctuation "→" format_expr body
|
||||
(Marked.unmark tau) format_punctuation ")"))
|
||||
(List.combine (Array.to_list xs) taus)
|
||||
format_punctuation "→" format_expr body
|
||||
| EApp
|
||||
((EOp (Binop ((Dcalc.Ast.Map | Dcalc.Ast.Filter) as op)), _), [arg1; arg2])
|
||||
->
|
||||
Format.fprintf fmt "@[<hov 2>%a@ %a@ %a@]" Dcalc.Print.format_binop
|
||||
(op, Pos.no_pos) format_with_parens arg1 format_with_parens arg2
|
||||
Format.fprintf fmt "@[<hov 2>%a@ %a@ %a@]" Dcalc.Print.format_binop op
|
||||
format_with_parens arg1 format_with_parens arg2
|
||||
| EApp ((EOp (Binop op), _), [arg1; arg2]) ->
|
||||
Format.fprintf fmt "@[<hov 2>%a@ %a@ %a@]" format_with_parens arg1
|
||||
Dcalc.Print.format_binop (op, Pos.no_pos) format_with_parens arg2
|
||||
Dcalc.Print.format_binop op format_with_parens arg2
|
||||
| EApp ((EOp (Unop (Log _)), _), [arg1]) when not debug ->
|
||||
Format.fprintf fmt "%a" format_with_parens arg1
|
||||
| EApp ((EOp (Unop op), _), [arg1]) ->
|
||||
Format.fprintf fmt "@[<hov 2>%a@ %a@]" Dcalc.Print.format_unop
|
||||
(op, Pos.no_pos) format_with_parens arg1
|
||||
Format.fprintf fmt "@[<hov 2>%a@ %a@]" Dcalc.Print.format_unop op
|
||||
format_with_parens arg1
|
||||
| EApp (f, args) ->
|
||||
Format.fprintf fmt "@[<hov 2>%a@ %a@]" format_expr f
|
||||
(Format.pp_print_list
|
||||
@ -185,12 +174,9 @@ let rec format_expr
|
||||
Format.fprintf fmt "@[<hov 2>%a@ %a@ %a@ %a@ %a@ %a@]" format_keyword "if"
|
||||
format_expr e1 format_keyword "then" format_expr e2 format_keyword "else"
|
||||
format_expr e3
|
||||
| EOp (Ternop op) ->
|
||||
Format.fprintf fmt "%a" Dcalc.Print.format_ternop (op, Pos.no_pos)
|
||||
| EOp (Binop op) ->
|
||||
Format.fprintf fmt "%a" Dcalc.Print.format_binop (op, Pos.no_pos)
|
||||
| EOp (Unop op) ->
|
||||
Format.fprintf fmt "%a" Dcalc.Print.format_unop (op, Pos.no_pos)
|
||||
| EOp (Ternop op) -> Format.fprintf fmt "%a" Dcalc.Print.format_ternop op
|
||||
| EOp (Binop op) -> Format.fprintf fmt "%a" Dcalc.Print.format_binop op
|
||||
| EOp (Unop op) -> Format.fprintf fmt "%a" Dcalc.Print.format_unop op
|
||||
| ECatch (e1, exn, e2) ->
|
||||
Format.fprintf fmt "@[<hov 2>%a@ %a@ %a@ %a ->@ %a@]" format_keyword "try"
|
||||
format_with_parens e1 format_keyword "with" format_exception exn
|
||||
@ -202,14 +188,13 @@ let rec format_expr
|
||||
Format.fprintf fmt "@[<hov 2>%a@ %a%a%a@]" format_keyword "assert"
|
||||
format_punctuation "(" format_expr e' format_punctuation ")"
|
||||
|
||||
let format_scope
|
||||
?(debug : bool = false)
|
||||
(ctx : Dcalc.Ast.decl_ctx)
|
||||
(fmt : Format.formatter)
|
||||
((n, s) : Dcalc.Ast.ScopeName.t * Ast.expr Dcalc.Ast.scope_body) : unit =
|
||||
let format_scope ?(debug = false) ctx fmt (n, s) =
|
||||
Format.fprintf fmt "@[<hov 2>%a %a =@ %a@]" format_keyword "let"
|
||||
Dcalc.Ast.ScopeName.format_t n (format_expr ctx ~debug)
|
||||
(Bindlib.unbox
|
||||
(Dcalc.Ast.build_whole_scope_expr ~make_abs:Ast.make_abs
|
||||
~make_let_in:Ast.make_let_in ~box_expr:Ast.box_expr ctx s
|
||||
(Pos.get_position (Dcalc.Ast.ScopeName.get_info n))))
|
||||
(Dcalc.Ast.map_mark
|
||||
(fun _ -> Marked.get_mark (Dcalc.Ast.ScopeName.get_info n))
|
||||
(fun ty -> ty)
|
||||
(Dcalc.Ast.get_scope_body_mark s))))
|
||||
|
@ -16,27 +16,22 @@
|
||||
|
||||
open Utils
|
||||
|
||||
(** {1 Helpers} *)
|
||||
|
||||
val is_uppercase : CamomileLibraryDefault.Camomile.UChar.t -> bool
|
||||
val begins_with_uppercase : string -> bool
|
||||
|
||||
(** {1 Formatters} *)
|
||||
|
||||
val format_lit : Format.formatter -> Ast.lit Pos.marked -> unit
|
||||
val format_var : Format.formatter -> Ast.Var.t -> unit
|
||||
val format_lit : Format.formatter -> Ast.lit Marked.pos -> unit
|
||||
val format_var : Format.formatter -> 'm Ast.var -> unit
|
||||
val format_exception : Format.formatter -> Ast.except -> unit
|
||||
|
||||
val format_expr :
|
||||
?debug:bool ->
|
||||
Dcalc.Ast.decl_ctx ->
|
||||
Format.formatter ->
|
||||
Ast.expr Pos.marked ->
|
||||
'm Ast.marked_expr ->
|
||||
unit
|
||||
|
||||
val format_scope :
|
||||
?debug:bool ->
|
||||
Dcalc.Ast.decl_ctx ->
|
||||
Format.formatter ->
|
||||
Dcalc.Ast.ScopeName.t * Ast.expr Dcalc.Ast.scope_body ->
|
||||
Dcalc.Ast.ScopeName.t * ('m Ast.expr, 'm) Dcalc.Ast.scope_body ->
|
||||
unit
|
||||
|
@ -16,11 +16,11 @@
|
||||
|
||||
open Utils
|
||||
open Ast
|
||||
open Backends
|
||||
open String_common
|
||||
module D = Dcalc.Ast
|
||||
|
||||
let find_struct (s : D.StructName.t) (ctx : D.decl_ctx) :
|
||||
(D.StructFieldName.t * D.typ Pos.marked) list =
|
||||
(D.StructFieldName.t * D.typ Marked.pos) list =
|
||||
try D.StructMap.find s ctx.D.ctx_structs
|
||||
with Not_found ->
|
||||
let s_name, pos = D.StructName.get_info s in
|
||||
@ -29,7 +29,7 @@ let find_struct (s : D.StructName.t) (ctx : D.decl_ctx) :
|
||||
s_name
|
||||
|
||||
let find_enum (en : D.EnumName.t) (ctx : D.decl_ctx) :
|
||||
(D.EnumConstructor.t * D.typ Pos.marked) list =
|
||||
(D.EnumConstructor.t * D.typ Marked.pos) list =
|
||||
try D.EnumMap.find en ctx.D.ctx_enums
|
||||
with Not_found ->
|
||||
let en_name, pos = D.EnumName.get_info en in
|
||||
@ -37,27 +37,26 @@ let find_enum (en : D.EnumName.t) (ctx : D.decl_ctx) :
|
||||
"Internal Error: Enumeration %s was not found in the current environment."
|
||||
en_name
|
||||
|
||||
let format_lit (fmt : Format.formatter) (l : lit Pos.marked) : unit =
|
||||
match Pos.unmark l with
|
||||
| LBool b ->
|
||||
Dcalc.Print.format_lit fmt (Pos.same_pos_as (Dcalc.Ast.LBool b) l)
|
||||
let format_lit (fmt : Format.formatter) (l : lit Marked.pos) : unit =
|
||||
match Marked.unmark l with
|
||||
| LBool b -> Dcalc.Print.format_lit fmt (Dcalc.Ast.LBool b)
|
||||
| LInt i ->
|
||||
Format.fprintf fmt "integer_of_string@ \"%s\"" (Runtime.integer_to_string i)
|
||||
| LUnit -> Dcalc.Print.format_lit fmt (Pos.same_pos_as Dcalc.Ast.LUnit l)
|
||||
| LUnit -> Dcalc.Print.format_lit fmt Dcalc.Ast.LUnit
|
||||
| LRat i ->
|
||||
Format.fprintf fmt "decimal_of_string \"%a\"" Dcalc.Print.format_lit
|
||||
(Pos.same_pos_as (Dcalc.Ast.LRat i) l)
|
||||
(Dcalc.Ast.LRat i)
|
||||
| LMoney e ->
|
||||
Format.fprintf fmt "money_of_cents_string@ \"%s\""
|
||||
(Runtime.integer_to_string (Runtime.money_to_cents e))
|
||||
| LDate d ->
|
||||
Format.fprintf fmt "date_of_numbers %d %d %d"
|
||||
Format.fprintf fmt "date_of_numbers (%d) (%d) (%d)"
|
||||
(Runtime.integer_to_int (Runtime.year_of_date d))
|
||||
(Runtime.integer_to_int (Runtime.month_number_of_date d))
|
||||
(Runtime.integer_to_int (Runtime.day_of_month_of_date d))
|
||||
| LDuration d ->
|
||||
let years, months, days = Runtime.duration_to_years_months_days d in
|
||||
Format.fprintf fmt "duration_of_numbers %d %d %d" years months days
|
||||
Format.fprintf fmt "duration_of_numbers (%d) (%d) (%d)" years months days
|
||||
|
||||
let format_op_kind (fmt : Format.formatter) (k : Dcalc.Ast.op_kind) =
|
||||
Format.fprintf fmt "%s"
|
||||
@ -68,9 +67,9 @@ let format_op_kind (fmt : Format.formatter) (k : Dcalc.Ast.op_kind) =
|
||||
| KDate -> "@"
|
||||
| KDuration -> "^")
|
||||
|
||||
let format_binop (fmt : Format.formatter) (op : Dcalc.Ast.binop Pos.marked) :
|
||||
let format_binop (fmt : Format.formatter) (op : Dcalc.Ast.binop Marked.pos) :
|
||||
unit =
|
||||
match Pos.unmark op with
|
||||
match Marked.unmark op with
|
||||
| Add k -> Format.fprintf fmt "+%a" format_op_kind k
|
||||
| Sub k -> Format.fprintf fmt "-%a" format_op_kind k
|
||||
| Mult k -> Format.fprintf fmt "*%a" format_op_kind k
|
||||
@ -87,9 +86,9 @@ let format_binop (fmt : Format.formatter) (op : Dcalc.Ast.binop Pos.marked) :
|
||||
| Map -> Format.fprintf fmt "Array.map"
|
||||
| Filter -> Format.fprintf fmt "array_filter"
|
||||
|
||||
let format_ternop (fmt : Format.formatter) (op : Dcalc.Ast.ternop Pos.marked) :
|
||||
let format_ternop (fmt : Format.formatter) (op : Dcalc.Ast.ternop Marked.pos) :
|
||||
unit =
|
||||
match Pos.unmark op with Fold -> Format.fprintf fmt "Array.fold_left"
|
||||
match Marked.unmark op with Fold -> Format.fprintf fmt "Array.fold_left"
|
||||
|
||||
let format_uid_list (fmt : Format.formatter) (uids : Uid.MarkedString.info list)
|
||||
: unit =
|
||||
@ -101,74 +100,80 @@ let format_uid_list (fmt : Format.formatter) (uids : Uid.MarkedString.info list)
|
||||
uids
|
||||
|
||||
let format_string_list (fmt : Format.formatter) (uids : string list) : unit =
|
||||
let sanitize_quotes = Re.compile (Re.char '"') in
|
||||
Format.fprintf fmt "@[<hov 2>[%a]@]"
|
||||
(Format.pp_print_list
|
||||
~pp_sep:(fun fmt () -> Format.fprintf fmt ";@ ")
|
||||
(fun fmt info -> Format.fprintf fmt "\"%s\"" info))
|
||||
(fun fmt info ->
|
||||
Format.fprintf fmt "\"%s\""
|
||||
(Re.replace sanitize_quotes ~f:(fun _ -> "\\\"") info)))
|
||||
uids
|
||||
|
||||
let format_unop (fmt : Format.formatter) (op : Dcalc.Ast.unop Pos.marked) : unit
|
||||
let format_unop (fmt : Format.formatter) (op : Dcalc.Ast.unop Marked.pos) : unit
|
||||
=
|
||||
match Pos.unmark op with
|
||||
match Marked.unmark op with
|
||||
| Minus k -> Format.fprintf fmt "~-%a" format_op_kind k
|
||||
| Not -> Format.fprintf fmt "%s" "not"
|
||||
| Log (_entry, _infos) ->
|
||||
Errors.raise_spanned_error (Pos.get_position op)
|
||||
Errors.raise_spanned_error (Marked.get_mark op)
|
||||
"Internal error: a log operator has not been caught by the expression \
|
||||
match"
|
||||
| Length -> Format.fprintf fmt "%s" "array_length"
|
||||
| IntToRat -> Format.fprintf fmt "%s" "decimal_of_integer"
|
||||
| MoneyToRat -> Format.fprintf fmt "%s" "decimal_of_money"
|
||||
| RatToMoney -> Format.fprintf fmt "%s" "money_of_decimal"
|
||||
| GetDay -> Format.fprintf fmt "%s" "day_of_month_of_date"
|
||||
| GetMonth -> Format.fprintf fmt "%s" "month_number_of_date"
|
||||
| GetYear -> Format.fprintf fmt "%s" "year_of_date"
|
||||
| FirstDayOfMonth -> Format.fprintf fmt "%s" "first_day_of_month"
|
||||
| LastDayOfMonth -> Format.fprintf fmt "%s" "last_day_of_month"
|
||||
| RoundMoney -> Format.fprintf fmt "%s" "money_round"
|
||||
| RoundDecimal -> Format.fprintf fmt "%s" "decimal_round"
|
||||
|
||||
let avoid_keywords (s : string) : string =
|
||||
if
|
||||
match s with
|
||||
(* list taken from
|
||||
http://caml.inria.fr/pub/docs/manual-ocaml/lex.html#sss:keywords *)
|
||||
| "and" | "as" | "assert" | "asr" | "begin" | "class" | "constraint" | "do"
|
||||
| "done" | "downto" | "else" | "end" | "exception" | "external" | "false"
|
||||
| "for" | "fun" | "function" | "functor" | "if" | "in" | "include"
|
||||
| "inherit" | "initializer" | "land" | "lazy" | "let" | "lor" | "lsl"
|
||||
| "lsr" | "lxor" | "match" | "method" | "mod" | "module" | "mutable" | "new"
|
||||
| "nonrec" | "object" | "of" | "open" | "or" | "private" | "rec" | "sig"
|
||||
| "struct" | "then" | "to" | "true" | "try" | "type" | "val" | "virtual"
|
||||
| "when" | "while" | "with" ->
|
||||
true
|
||||
| _ -> false
|
||||
then s ^ "_"
|
||||
else s
|
||||
match s with
|
||||
(* list taken from
|
||||
http://caml.inria.fr/pub/docs/manual-ocaml/lex.html#sss:keywords *)
|
||||
| "and" | "as" | "assert" | "asr" | "begin" | "class" | "constraint" | "do"
|
||||
| "done" | "downto" | "else" | "end" | "exception" | "external" | "false"
|
||||
| "for" | "fun" | "function" | "functor" | "if" | "in" | "include" | "inherit"
|
||||
| "initializer" | "land" | "lazy" | "let" | "lor" | "lsl" | "lsr" | "lxor"
|
||||
| "match" | "method" | "mod" | "module" | "mutable" | "new" | "nonrec"
|
||||
| "object" | "of" | "open" | "or" | "private" | "rec" | "sig" | "struct"
|
||||
| "then" | "to" | "true" | "try" | "type" | "val" | "virtual" | "when"
|
||||
| "while" | "with" ->
|
||||
s ^ "_user"
|
||||
| _ -> s
|
||||
|
||||
let format_struct_name (fmt : Format.formatter) (v : Dcalc.Ast.StructName.t) :
|
||||
unit =
|
||||
Format.asprintf "%a" Dcalc.Ast.StructName.format_t v
|
||||
|> to_ascii
|
||||
|> to_lowercase
|
||||
|> avoid_keywords
|
||||
|> Format.fprintf fmt "%s"
|
||||
[@@ocamlformat "disable"]
|
||||
|
||||
let format_to_struct_type (fmt : Format.formatter) (v : Dcalc.Ast.StructName.t) :
|
||||
unit =
|
||||
Format.asprintf "%a" Dcalc.Ast.StructName.format_t v
|
||||
|> to_ascii
|
||||
|> to_lowercase
|
||||
|> to_snake_case
|
||||
|> avoid_keywords
|
||||
|> Format.fprintf fmt "%s"
|
||||
|
||||
let format_to_module_name
|
||||
(fmt : Format.formatter)
|
||||
(name : [< `Ename of D.EnumName.t | `Sname of D.StructName.t ]) =
|
||||
(match name with
|
||||
| `Ename v -> Format.asprintf "%a" D.EnumName.format_t v
|
||||
| `Sname v -> Format.asprintf "%a" D.StructName.format_t v)
|
||||
|> to_ascii
|
||||
|> to_snake_case
|
||||
|> avoid_keywords
|
||||
|> String.split_on_char '_'
|
||||
|> List.map String.capitalize_ascii
|
||||
|> String.concat ""
|
||||
|> Format.fprintf fmt "%s"
|
||||
[@@ocamlformat "disable"]
|
||||
|
||||
let format_struct_field_name
|
||||
(fmt : Format.formatter)
|
||||
((sname_opt, v) :
|
||||
Dcalc.Ast.StructName.t option * Dcalc.Ast.StructFieldName.t) : unit =
|
||||
(match sname_opt with
|
||||
| Some sname -> Format.fprintf fmt "%a.%s" format_to_struct_type sname
|
||||
| Some sname ->
|
||||
Format.fprintf fmt "%a.%s" format_to_module_name (`Sname sname)
|
||||
| None -> Format.fprintf fmt "%s")
|
||||
(avoid_keywords
|
||||
(to_ascii (Format.asprintf "%a" Dcalc.Ast.StructFieldName.format_t v)))
|
||||
@ -177,7 +182,7 @@ let format_enum_name (fmt : Format.formatter) (v : Dcalc.Ast.EnumName.t) : unit
|
||||
=
|
||||
Format.fprintf fmt "%s"
|
||||
(avoid_keywords
|
||||
(to_lowercase
|
||||
(to_snake_case
|
||||
(to_ascii (Format.asprintf "%a" Dcalc.Ast.EnumName.format_t v))))
|
||||
|
||||
let format_enum_cons_name
|
||||
@ -187,9 +192,9 @@ let format_enum_cons_name
|
||||
(avoid_keywords
|
||||
(to_ascii (Format.asprintf "%a" Dcalc.Ast.EnumConstructor.format_t v)))
|
||||
|
||||
let rec typ_embedding_name (fmt : Format.formatter) (ty : D.typ Pos.marked) :
|
||||
let rec typ_embedding_name (fmt : Format.formatter) (ty : D.typ Marked.pos) :
|
||||
unit =
|
||||
match Pos.unmark ty with
|
||||
match Marked.unmark ty with
|
||||
| D.TLit D.TUnit -> Format.fprintf fmt "embed_unit"
|
||||
| D.TLit D.TBool -> Format.fprintf fmt "embed_bool"
|
||||
| D.TLit D.TInt -> Format.fprintf fmt "embed_integer"
|
||||
@ -203,19 +208,18 @@ let rec typ_embedding_name (fmt : Format.formatter) (ty : D.typ Pos.marked) :
|
||||
| D.TArray ty -> Format.fprintf fmt "embed_array (%a)" typ_embedding_name ty
|
||||
| _ -> Format.fprintf fmt "unembeddable"
|
||||
|
||||
let typ_needs_parens (e : Dcalc.Ast.typ Pos.marked) : bool =
|
||||
match Pos.unmark e with TArrow _ | TArray _ -> true | _ -> false
|
||||
let typ_needs_parens (e : Dcalc.Ast.typ Marked.pos) : bool =
|
||||
match Marked.unmark e with TArrow _ | TArray _ -> true | _ -> false
|
||||
|
||||
let rec format_typ (fmt : Format.formatter) (typ : Dcalc.Ast.typ Pos.marked) :
|
||||
let rec format_typ (fmt : Format.formatter) (typ : Dcalc.Ast.typ Marked.pos) :
|
||||
unit =
|
||||
let format_typ = format_typ in
|
||||
let format_typ_with_parens
|
||||
(fmt : Format.formatter)
|
||||
(t : Dcalc.Ast.typ Pos.marked) =
|
||||
(t : Dcalc.Ast.typ Marked.pos) =
|
||||
if typ_needs_parens t then Format.fprintf fmt "(%a)" format_typ t
|
||||
else Format.fprintf fmt "%a" format_typ t
|
||||
in
|
||||
match Pos.unmark typ with
|
||||
match Marked.unmark typ with
|
||||
| TLit l -> Format.fprintf fmt "%a" Dcalc.Print.format_tlit l
|
||||
| TTuple (ts, None) ->
|
||||
Format.fprintf fmt "@[<hov 2>(%a)@]"
|
||||
@ -223,23 +227,24 @@ let rec format_typ (fmt : Format.formatter) (typ : Dcalc.Ast.typ Pos.marked) :
|
||||
~pp_sep:(fun fmt () -> Format.fprintf fmt "@ *@ ")
|
||||
format_typ_with_parens)
|
||||
ts
|
||||
| TTuple (_, Some s) -> Format.fprintf fmt "%a.t" format_to_struct_type s
|
||||
| TTuple (_, Some s) ->
|
||||
Format.fprintf fmt "%a.t" format_to_module_name (`Sname s)
|
||||
| TEnum ([t], e) when D.EnumName.compare e Ast.option_enum = 0 ->
|
||||
Format.fprintf fmt "@[<hov 2>(%a)@] %a" format_typ_with_parens t
|
||||
format_enum_name e
|
||||
| TEnum (_, e) when D.EnumName.compare e Ast.option_enum = 0 ->
|
||||
Errors.raise_spanned_error (Pos.get_position typ)
|
||||
Errors.raise_spanned_error (Marked.get_mark typ)
|
||||
"Internal Error: found an typing parameter for an eoption type of the \
|
||||
wrong lenght."
|
||||
| TEnum (_ts, e) -> Format.fprintf fmt "%a" format_enum_name e
|
||||
wrong length."
|
||||
| TEnum (_ts, e) -> Format.fprintf fmt "%a.t" format_to_module_name (`Ename e)
|
||||
| TArrow (t1, t2) ->
|
||||
Format.fprintf fmt "@[<hov 2>%a ->@ %a@]" format_typ_with_parens t1
|
||||
format_typ_with_parens t2
|
||||
| TArray t1 -> Format.fprintf fmt "@[%a@ array@]" format_typ_with_parens t1
|
||||
| TAny -> Format.fprintf fmt "_"
|
||||
|
||||
let format_var (fmt : Format.formatter) (v : Var.t) : unit =
|
||||
let lowercase_name = to_lowercase (to_ascii (Bindlib.name_of v)) in
|
||||
let format_var (fmt : Format.formatter) (v : 'm var) : unit =
|
||||
let lowercase_name = to_snake_case (to_ascii (Bindlib.name_of v)) in
|
||||
let lowercase_name =
|
||||
Re.Pcre.substitute ~rex:(Re.Pcre.regexp "\\.")
|
||||
~subst:(fun _ -> "_dot_")
|
||||
@ -248,26 +253,35 @@ let format_var (fmt : Format.formatter) (v : Var.t) : unit =
|
||||
let lowercase_name = avoid_keywords (to_ascii lowercase_name) in
|
||||
if
|
||||
List.mem lowercase_name ["handle_default"; "handle_default_opt"]
|
||||
|| Dcalc.Print.begins_with_uppercase (Bindlib.name_of v)
|
||||
|| begins_with_uppercase (Bindlib.name_of v)
|
||||
then Format.fprintf fmt "%s" lowercase_name
|
||||
else if lowercase_name = "_" then Format.fprintf fmt "%s" lowercase_name
|
||||
else Format.fprintf fmt "%s_" lowercase_name
|
||||
else (
|
||||
Cli.debug_print "lowercase_name: %s " lowercase_name;
|
||||
Format.fprintf fmt "%s_" lowercase_name)
|
||||
|
||||
let needs_parens (e : expr Pos.marked) : bool =
|
||||
match Pos.unmark e with
|
||||
let needs_parens (e : 'm marked_expr) : bool =
|
||||
match Marked.unmark e with
|
||||
| EApp ((EAbs (_, _), _), _)
|
||||
| ELit (LBool _ | LUnit)
|
||||
| EVar _ | ETuple _ | EOp _ ->
|
||||
false
|
||||
| _ -> true
|
||||
|
||||
let format_exception (fmt : Format.formatter) (exc : except Pos.marked) : unit =
|
||||
match Pos.unmark exc with
|
||||
| ConflictError -> Format.fprintf fmt "ConflictError"
|
||||
let format_exception (fmt : Format.formatter) (exc : except Marked.pos) : unit =
|
||||
match Marked.unmark exc with
|
||||
| ConflictError ->
|
||||
let pos = Marked.get_mark exc in
|
||||
Format.fprintf fmt
|
||||
"(ConflictError@ @[<hov 2>{filename = \"%s\";@ start_line=%d;@ \
|
||||
start_column=%d;@ end_line=%d; end_column=%d;@ law_headings=%a}@])"
|
||||
(Pos.get_file pos) (Pos.get_start_line pos) (Pos.get_start_column pos)
|
||||
(Pos.get_end_line pos) (Pos.get_end_column pos) format_string_list
|
||||
(Pos.get_law_info pos)
|
||||
| EmptyError -> Format.fprintf fmt "EmptyError"
|
||||
| Crash -> Format.fprintf fmt "Crash"
|
||||
| NoValueProvided ->
|
||||
let pos = Pos.get_position exc in
|
||||
let pos = Marked.get_mark exc in
|
||||
Format.fprintf fmt
|
||||
"(NoValueProvided@ @[<hov 2>{filename = \"%s\";@ start_line=%d;@ \
|
||||
start_column=%d;@ end_line=%d; end_column=%d;@ law_headings=%a}@])"
|
||||
@ -278,14 +292,14 @@ let format_exception (fmt : Format.formatter) (exc : except Pos.marked) : unit =
|
||||
let rec format_expr
|
||||
(ctx : Dcalc.Ast.decl_ctx)
|
||||
(fmt : Format.formatter)
|
||||
(e : expr Pos.marked) : unit =
|
||||
(e : 'm marked_expr) : unit =
|
||||
let format_expr = format_expr ctx in
|
||||
let format_with_parens (fmt : Format.formatter) (e : expr Pos.marked) =
|
||||
let format_with_parens (fmt : Format.formatter) (e : 'm marked_expr) =
|
||||
if needs_parens e then Format.fprintf fmt "(%a)" format_expr e
|
||||
else Format.fprintf fmt "%a" format_expr e
|
||||
in
|
||||
match Pos.unmark e with
|
||||
| EVar v -> Format.fprintf fmt "%a" format_var (Pos.unmark v)
|
||||
match Marked.unmark e with
|
||||
| EVar v -> Format.fprintf fmt "%a" format_var v
|
||||
| ETuple (es, None) ->
|
||||
Format.fprintf fmt "@[<hov 2>(%a)@]"
|
||||
(Format.pp_print_list
|
||||
@ -321,20 +335,23 @@ let rec format_expr
|
||||
Format.fprintf fmt "%a.%a" format_with_parens e1 format_struct_field_name
|
||||
(Some s, fst (List.nth (find_struct s ctx) n)))
|
||||
| EInj (e, n, en, _ts) ->
|
||||
Format.fprintf fmt "@[<hov 2>%a@ %a@]" format_enum_cons_name
|
||||
Format.fprintf fmt "@[<hov 2>%a.%a@ %a@]" format_to_module_name (`Ename en)
|
||||
format_enum_cons_name
|
||||
(fst (List.nth (find_enum en ctx) n))
|
||||
format_with_parens e
|
||||
| EMatch (e, es, e_name) ->
|
||||
Format.fprintf fmt "@[<hov 2>match@ %a@]@ with@\n%a" format_with_parens e
|
||||
Format.fprintf fmt "@[<hv>@[<hov 2>match@ %a@]@ with@\n| %a@]"
|
||||
format_with_parens e
|
||||
(Format.pp_print_list
|
||||
~pp_sep:(fun fmt () -> Format.fprintf fmt "@\n| ")
|
||||
~pp_sep:(fun fmt () -> Format.fprintf fmt "@ | ")
|
||||
(fun fmt (e, c) ->
|
||||
Format.fprintf fmt "%a %a" format_enum_cons_name c
|
||||
Format.fprintf fmt "@[<hov 2>%a.%a %a@]" format_to_module_name
|
||||
(`Ename e_name) format_enum_cons_name c
|
||||
(fun fmt e ->
|
||||
match Pos.unmark e with
|
||||
| EAbs ((binder, _), _) ->
|
||||
match Marked.unmark e with
|
||||
| EAbs (binder, _) ->
|
||||
let xs, body = Bindlib.unmbind binder in
|
||||
Format.fprintf fmt "%a ->@[<hov 2>@ %a@]"
|
||||
Format.fprintf fmt "%a ->@ %a"
|
||||
(Format.pp_print_list
|
||||
~pp_sep:(fun fmt () -> Format.fprintf fmt "@,")
|
||||
(fun fmt x -> Format.fprintf fmt "%a" format_var x))
|
||||
@ -343,8 +360,8 @@ let rec format_expr
|
||||
(* should not happen *))
|
||||
e))
|
||||
(List.combine es (List.map fst (find_enum e_name ctx)))
|
||||
| ELit l -> Format.fprintf fmt "%a" format_lit (Pos.same_pos_as l e)
|
||||
| EApp ((EAbs ((binder, _), taus), _), args) ->
|
||||
| ELit l -> Format.fprintf fmt "%a" format_lit (Marked.mark (D.pos e) l)
|
||||
| EApp ((EAbs (binder, taus), _), args) ->
|
||||
let xs, body = Bindlib.unmbind binder in
|
||||
let xs_tau = List.map2 (fun x tau -> x, tau) (Array.to_list xs) taus in
|
||||
let xs_tau_arg = List.map2 (fun (x, tau) arg -> x, tau, arg) xs_tau args in
|
||||
@ -355,7 +372,7 @@ let rec format_expr
|
||||
Format.fprintf fmt "@[<hov 2>let@ %a@ :@ %a@ =@ %a@]@ in@\n"
|
||||
format_var x format_typ tau format_with_parens arg))
|
||||
xs_tau_arg format_with_parens body
|
||||
| EAbs ((binder, _), taus) ->
|
||||
| EAbs (binder, taus) ->
|
||||
let xs, body = Bindlib.unmbind binder in
|
||||
let xs_tau = List.map2 (fun x tau -> x, tau) (Array.to_list xs) taus in
|
||||
Format.fprintf fmt "@[<hov 2>fun@ %a ->@ %a@]"
|
||||
@ -380,8 +397,9 @@ let rec format_expr
|
||||
when !Cli.trace_flag ->
|
||||
Format.fprintf fmt "(log_variable_definition@ %a@ (%a)@ %a)" format_uid_list
|
||||
info typ_embedding_name (tau, Pos.no_pos) format_with_parens arg1
|
||||
| EApp ((EOp (Unop (D.Log (D.PosRecordIfTrueBool, _))), pos), [arg1])
|
||||
| EApp ((EOp (Unop (D.Log (D.PosRecordIfTrueBool, _))), m), [arg1])
|
||||
when !Cli.trace_flag ->
|
||||
let pos = D.mark_pos m in
|
||||
Format.fprintf fmt
|
||||
"(log_decision_taken@ @[<hov 2>{filename = \"%s\";@ start_line=%d;@ \
|
||||
start_column=%d;@ end_line=%d; end_column=%d;@ law_headings=%a}@]@ %a)"
|
||||
@ -397,6 +415,24 @@ let rec format_expr
|
||||
| EApp ((EOp (Unop op), _), [arg1]) ->
|
||||
Format.fprintf fmt "@[<hov 2>%a@ %a@]" format_unop (op, Pos.no_pos)
|
||||
format_with_parens arg1
|
||||
| EApp ((EVar x, pos), args)
|
||||
when Ast.Var.compare (Ast.Var.t x) Ast.handle_default = 0
|
||||
|| Ast.Var.compare (Ast.Var.t x) Ast.handle_default_opt = 0 ->
|
||||
Format.fprintf fmt
|
||||
"@[<hov 2>%a@ @[<hov 2>{filename = \"%s\";@ start_line=%d;@ \
|
||||
start_column=%d;@ end_line=%d; end_column=%d;@ law_headings=%a}@]@ %a@]"
|
||||
format_var x
|
||||
(Pos.get_file (D.mark_pos pos))
|
||||
(Pos.get_start_line (D.mark_pos pos))
|
||||
(Pos.get_start_column (D.mark_pos pos))
|
||||
(Pos.get_end_line (D.mark_pos pos))
|
||||
(Pos.get_end_column (D.mark_pos pos))
|
||||
format_string_list
|
||||
(Pos.get_law_info (D.mark_pos pos))
|
||||
(Format.pp_print_list
|
||||
~pp_sep:(fun fmt () -> Format.fprintf fmt "@ ")
|
||||
format_with_parens)
|
||||
args
|
||||
| EApp (f, args) ->
|
||||
Format.fprintf fmt "@[<hov 2>%a@ %a@]" format_with_parens f
|
||||
(Format.pp_print_list
|
||||
@ -412,29 +448,38 @@ let rec format_expr
|
||||
| EOp (Unop op) -> Format.fprintf fmt "%a" format_unop (op, Pos.no_pos)
|
||||
| EAssert e' ->
|
||||
Format.fprintf fmt
|
||||
"@[<hov 2>if @ %a@ then@ ()@ else@ raise AssertionFailed@]"
|
||||
"@[<hov 2>if@ %a@ then@ ()@ else@ raise (AssertionFailed @[<hov \
|
||||
2>{filename = \"%s\";@ start_line=%d;@ start_column=%d;@ end_line=%d; \
|
||||
end_column=%d;@ law_headings=%a}@])@]"
|
||||
format_with_parens e'
|
||||
| ERaise exc ->
|
||||
Format.fprintf fmt "raise@ %a" format_exception (exc, Pos.get_position e)
|
||||
(Pos.get_file (D.pos e'))
|
||||
(Pos.get_start_line (D.pos e'))
|
||||
(Pos.get_start_column (D.pos e'))
|
||||
(Pos.get_end_line (D.pos e'))
|
||||
(Pos.get_end_column (D.pos e'))
|
||||
format_string_list
|
||||
(Pos.get_law_info (D.pos e'))
|
||||
| ERaise exc -> Format.fprintf fmt "raise@ %a" format_exception (exc, D.pos e)
|
||||
| ECatch (e1, exc, e2) ->
|
||||
Format.fprintf fmt "@[<hov 2>try@ %a@ with@ %a@ ->@ %a@]" format_with_parens
|
||||
e1 format_exception
|
||||
(exc, Pos.get_position e)
|
||||
Format.fprintf fmt
|
||||
"@,@[<hv>@[<hov 2>try@ %a@]@ with@]@ @[<hov 2>%a@ ->@ %a@]"
|
||||
format_with_parens e1 format_exception
|
||||
(exc, D.pos e)
|
||||
format_with_parens e2
|
||||
|
||||
let format_struct_embedding
|
||||
(fmt : Format.formatter)
|
||||
((struct_name, struct_fields) :
|
||||
D.StructName.t * (D.StructFieldName.t * D.typ Pos.marked) list) =
|
||||
D.StructName.t * (D.StructFieldName.t * D.typ Marked.pos) list) =
|
||||
if List.length struct_fields = 0 then
|
||||
Format.fprintf fmt "let embed_%a (_: %a.t) : runtime_value = Unit@\n@\n"
|
||||
format_struct_name struct_name format_to_struct_type struct_name
|
||||
format_struct_name struct_name format_to_module_name (`Sname struct_name)
|
||||
else
|
||||
Format.fprintf fmt
|
||||
"@[<hov 2>let embed_%a (x: %a.t) : runtime_value =@ Struct([\"%a\"],@ \
|
||||
@[<hov 2>[%a]@])@]@\n\
|
||||
@\n"
|
||||
format_struct_name struct_name format_to_struct_type struct_name
|
||||
format_struct_name struct_name format_to_module_name (`Sname struct_name)
|
||||
D.StructName.format_t struct_name
|
||||
(Format.pp_print_list
|
||||
~pp_sep:(fun fmt () -> Format.fprintf fmt ";@\n")
|
||||
@ -448,17 +493,17 @@ let format_struct_embedding
|
||||
let format_enum_embedding
|
||||
(fmt : Format.formatter)
|
||||
((enum_name, enum_cases) :
|
||||
D.EnumName.t * (D.EnumConstructor.t * D.typ Pos.marked) list) =
|
||||
D.EnumName.t * (D.EnumConstructor.t * D.typ Marked.pos) list) =
|
||||
if List.length enum_cases = 0 then
|
||||
Format.fprintf fmt "let embed_%a (_: %a) : runtime_value = Unit@\n@\n"
|
||||
format_enum_name enum_name format_enum_name enum_name
|
||||
Format.fprintf fmt "let embed_%a (_: %a.t) : runtime_value = Unit@\n@\n"
|
||||
format_to_module_name (`Ename enum_name) format_enum_name enum_name
|
||||
else
|
||||
Format.fprintf fmt
|
||||
"@[<hov 2>let embed_%a (x: %a) : runtime_value =@ Enum([\"%a\"],@ @[<hov \
|
||||
2>match x with@ %a@])@]@\n\
|
||||
"@[<hv 2>@[<hov 2>let embed_%a@ @[<hov 2>(x:@ %a.t)@]@ : runtime_value \
|
||||
=@]@ Enum([\"%a\"],@ @[<hov 2>match x with@ %a@])@]@\n\
|
||||
@\n"
|
||||
format_enum_name enum_name format_enum_name enum_name D.EnumName.format_t
|
||||
enum_name
|
||||
format_enum_name enum_name format_to_module_name (`Ename enum_name)
|
||||
D.EnumName.format_t enum_name
|
||||
(Format.pp_print_list
|
||||
~pp_sep:(fun fmt () -> Format.fprintf fmt "@\n")
|
||||
(fun _fmt (enum_cons, enum_cons_type) ->
|
||||
@ -474,37 +519,33 @@ let format_ctx
|
||||
let format_struct_decl fmt (struct_name, struct_fields) =
|
||||
if List.length struct_fields = 0 then
|
||||
Format.fprintf fmt
|
||||
"module %a = struct@\n@[<hov 2>@ type t = unit\nend@] @\n"
|
||||
format_to_struct_type struct_name
|
||||
"@[<v 2>module %a = struct@\n@[<hov 2>type t = unit@]@]@\nend@\n"
|
||||
format_to_module_name (`Sname struct_name)
|
||||
else
|
||||
Format.fprintf fmt
|
||||
"module %a = struct@\n\
|
||||
@[<hov 2>@ type t = {@\n\
|
||||
@[<hov 2> %a@]@\n\
|
||||
}\n\
|
||||
end@]@\n"
|
||||
format_to_struct_type struct_name
|
||||
"@[<v>@[<v 2>module %a = struct@ @[<hv 2>type t = {@,\
|
||||
%a@;\
|
||||
<0-2>}@]@]@ end@]@\n"
|
||||
format_to_module_name (`Sname struct_name)
|
||||
(Format.pp_print_list
|
||||
~pp_sep:(fun fmt () -> Format.fprintf fmt "@\n")
|
||||
~pp_sep:(fun fmt () -> Format.fprintf fmt ";@ ")
|
||||
(fun _fmt (struct_field, struct_field_type) ->
|
||||
Format.fprintf fmt "%a:@ %a;" format_struct_field_name
|
||||
Format.fprintf fmt "@[<hov 2>%a:@ %a@]" format_struct_field_name
|
||||
(None, struct_field) format_typ struct_field_type))
|
||||
struct_fields;
|
||||
if !Cli.trace_flag then
|
||||
format_struct_embedding fmt (struct_name, struct_fields)
|
||||
in
|
||||
let format_enum_decl fmt (enum_name, enum_cons) =
|
||||
if List.length enum_cons = 0 then
|
||||
Format.fprintf fmt "type %a = unit@\n@\n" format_enum_name enum_name
|
||||
else
|
||||
Format.fprintf fmt "type %a =@\n@[<hov 2> %a@]@\n@\n" format_enum_name
|
||||
enum_name
|
||||
(Format.pp_print_list
|
||||
~pp_sep:(fun fmt () -> Format.fprintf fmt "@\n")
|
||||
(fun _fmt (enum_cons, enum_cons_type) ->
|
||||
Format.fprintf fmt "| %a@ of@ %a" format_enum_cons_name enum_cons
|
||||
format_typ enum_cons_type))
|
||||
enum_cons;
|
||||
Format.fprintf fmt
|
||||
"module %a = struct@\n@[<hov 2>@ type t =@\n@[<hov 2> %a@]@\nend@]@\n"
|
||||
format_to_module_name (`Ename enum_name)
|
||||
(Format.pp_print_list
|
||||
~pp_sep:(fun fmt () -> Format.fprintf fmt "@\n")
|
||||
(fun _fmt (enum_cons, enum_cons_type) ->
|
||||
Format.fprintf fmt "@[<hov 2>| %a@ of@ %a@]" format_enum_cons_name
|
||||
enum_cons format_typ enum_cons_type))
|
||||
enum_cons;
|
||||
if !Cli.trace_flag then format_enum_embedding fmt (enum_name, enum_cons)
|
||||
in
|
||||
let is_in_type_ordering s =
|
||||
@ -535,7 +576,7 @@ let format_ctx
|
||||
let rec format_scope_body_expr
|
||||
(ctx : Dcalc.Ast.decl_ctx)
|
||||
(fmt : Format.formatter)
|
||||
(scope_lets : Ast.expr Dcalc.Ast.scope_body_expr) : unit =
|
||||
(scope_lets : ('m Ast.expr, 'm) Dcalc.Ast.scope_body_expr) : unit =
|
||||
match scope_lets with
|
||||
| Dcalc.Ast.Result e -> format_expr ctx fmt e
|
||||
| Dcalc.Ast.ScopeLet scope_let ->
|
||||
@ -551,7 +592,7 @@ let rec format_scope_body_expr
|
||||
let rec format_scopes
|
||||
(ctx : Dcalc.Ast.decl_ctx)
|
||||
(fmt : Format.formatter)
|
||||
(scopes : Ast.expr Dcalc.Ast.scopes) : unit =
|
||||
(scopes : ('m Ast.expr, 'm) Dcalc.Ast.scopes) : unit =
|
||||
match scopes with
|
||||
| Dcalc.Ast.Nil -> ()
|
||||
| Dcalc.Ast.ScopeDef scope_def ->
|
||||
@ -560,23 +601,27 @@ let rec format_scopes
|
||||
in
|
||||
let scope_var, scope_next = Bindlib.unbind scope_def.scope_next in
|
||||
Format.fprintf fmt "@\n@\n@[<hov 2>let %a (%a: %a.t) : %a.t =@\n%a@]%a"
|
||||
format_var scope_var format_var scope_input_var format_to_struct_type
|
||||
scope_def.scope_body.scope_body_input_struct format_to_struct_type
|
||||
scope_def.scope_body.scope_body_output_struct
|
||||
format_var scope_var format_var scope_input_var format_to_module_name
|
||||
(`Sname scope_def.scope_body.scope_body_input_struct)
|
||||
format_to_module_name
|
||||
(`Sname scope_def.scope_body.scope_body_output_struct)
|
||||
(format_scope_body_expr ctx)
|
||||
scope_body_expr (format_scopes ctx) scope_next
|
||||
|
||||
let format_program
|
||||
(fmt : Format.formatter)
|
||||
(p : Ast.program)
|
||||
(p : 'm Ast.program)
|
||||
(type_ordering : Scopelang.Dependency.TVertex.t list) : unit =
|
||||
Cli.style_flag := false;
|
||||
Format.fprintf fmt
|
||||
"(** This file has been generated by the Catala compiler, do not edit! *)@\n\
|
||||
@\n\
|
||||
open Runtime@\n\
|
||||
@\n\
|
||||
[@@@@@@ocaml.warning \"-4-26-27-32-41-42\"]@\n\
|
||||
@\n\
|
||||
%a%a@?"
|
||||
(format_ctx type_ordering) p.decl_ctx (format_scopes p.decl_ctx) p.scopes
|
||||
Cli.call_unstyled (fun _ ->
|
||||
Format.fprintf fmt
|
||||
"(** This file has been generated by the Catala compiler, do not edit! \
|
||||
*)@\n\
|
||||
@\n\
|
||||
open Runtime_ocaml.Runtime@\n\
|
||||
@\n\
|
||||
[@@@@@@ocaml.warning \"-4-26-27-32-41-42\"]@\n\
|
||||
@\n\
|
||||
%a%a@\n\
|
||||
@?"
|
||||
(format_ctx type_ordering) p.decl_ctx (format_scopes p.decl_ctx)
|
||||
p.scopes)
|
||||
|
@ -14,8 +14,49 @@
|
||||
License for the specific language governing permissions and limitations under
|
||||
the License. *)
|
||||
|
||||
open Utils
|
||||
open Ast
|
||||
|
||||
(** Formats a lambda calculus program into a valid OCaml program *)
|
||||
|
||||
val avoid_keywords : string -> string
|
||||
|
||||
val find_struct :
|
||||
Dcalc.Ast.StructName.t ->
|
||||
Dcalc.Ast.decl_ctx ->
|
||||
(Dcalc.Ast.StructFieldName.t * Dcalc.Ast.typ Marked.pos) list
|
||||
|
||||
val find_enum :
|
||||
Dcalc.Ast.EnumName.t ->
|
||||
Dcalc.Ast.decl_ctx ->
|
||||
(Dcalc.Ast.EnumConstructor.t * Dcalc.Ast.typ Marked.pos) list
|
||||
|
||||
val typ_needs_parens : Dcalc.Ast.typ Marked.pos -> bool
|
||||
val needs_parens : 'm marked_expr -> bool
|
||||
val format_enum_name : Format.formatter -> Dcalc.Ast.EnumName.t -> unit
|
||||
|
||||
val format_enum_cons_name :
|
||||
Format.formatter -> Dcalc.Ast.EnumConstructor.t -> unit
|
||||
|
||||
val format_struct_name : Format.formatter -> Dcalc.Ast.StructName.t -> unit
|
||||
|
||||
val format_struct_field_name :
|
||||
Format.formatter ->
|
||||
Dcalc.Ast.StructName.t option * Dcalc.Ast.StructFieldName.t ->
|
||||
unit
|
||||
|
||||
val format_to_module_name :
|
||||
Format.formatter ->
|
||||
[< `Ename of Dcalc.Ast.EnumName.t | `Sname of Dcalc.Ast.StructName.t ] ->
|
||||
unit
|
||||
|
||||
val format_lit : Format.formatter -> lit Marked.pos -> unit
|
||||
val format_uid_list : Format.formatter -> Uid.MarkedString.info list -> unit
|
||||
val format_var : Format.formatter -> 'm var -> unit
|
||||
|
||||
val format_program :
|
||||
Format.formatter -> Ast.program -> Scopelang.Dependency.TVertex.t list -> unit
|
||||
Format.formatter ->
|
||||
'm Ast.program ->
|
||||
Scopelang.Dependency.TVertex.t list ->
|
||||
unit
|
||||
(** Usage [format_program fmt p type_dependencies_ordering] *)
|
||||
|
@ -1,7 +1,7 @@
|
||||
(library
|
||||
(name literate)
|
||||
(public_name catala.literate)
|
||||
(libraries re utils surface))
|
||||
(libraries re utils surface ubase))
|
||||
|
||||
(documentation
|
||||
(package catala)
|
||||
|
@ -114,14 +114,14 @@ let wrap_html
|
||||
|
||||
(** Performs syntax highlighting on a piece of code by using Pygments and the
|
||||
special Catala lexer. *)
|
||||
let pygmentize_code (c : string Pos.marked) (language : C.backend_lang) : string
|
||||
let pygmentize_code (c : string Marked.pos) (language : C.backend_lang) : string
|
||||
=
|
||||
C.debug_print "Pygmenting the code chunk %s"
|
||||
(Pos.to_string (Pos.get_position c));
|
||||
(Pos.to_string (Marked.get_mark c));
|
||||
let temp_file_in = Filename.temp_file "catala_html_pygments" "in" in
|
||||
let temp_file_out = Filename.temp_file "catala_html_pygments" "out" in
|
||||
let oc = open_out temp_file_in in
|
||||
Printf.fprintf oc "%s" (Pos.unmark c);
|
||||
Printf.fprintf oc "%s" (Marked.unmark c);
|
||||
close_out oc;
|
||||
let pygments = "pygmentize" in
|
||||
let pygments_lexer = get_language_extension language in
|
||||
@ -133,9 +133,9 @@ let pygmentize_code (c : string Pos.marked) (language : C.backend_lang) : string
|
||||
"html";
|
||||
"-O";
|
||||
"style=colorful,anchorlinenos=True,lineanchors=\""
|
||||
^ Pos.get_file (Pos.get_position c)
|
||||
^ String_common.to_ascii (Pos.get_file (Marked.get_mark c))
|
||||
^ "\",linenos=table,linenostart="
|
||||
^ string_of_int (Pos.get_start_line (Pos.get_position c) - 1);
|
||||
^ string_of_int (Pos.get_start_line (Marked.get_mark c) - 1);
|
||||
"-o";
|
||||
temp_file_out;
|
||||
temp_file_in;
|
||||
@ -158,9 +158,15 @@ let pygmentize_code (c : string Pos.marked) (language : C.backend_lang) : string
|
||||
|
||||
(** {1 Weaving} *)
|
||||
|
||||
let sanitize_html_href str =
|
||||
str
|
||||
|> String_common.to_ascii
|
||||
|> R.substitute ~rex:(R.regexp "[' '°]") ~subst:(function _ -> "%20")
|
||||
|
||||
let rec law_structure_to_html
|
||||
(language : C.backend_lang)
|
||||
(print_only_law : bool)
|
||||
(parents_headings : string list)
|
||||
(fmt : Format.formatter)
|
||||
(i : A.law_structure) : unit =
|
||||
match i with
|
||||
@ -171,30 +177,83 @@ let rec law_structure_to_html
|
||||
Format.fprintf fmt
|
||||
"<div class='code-wrapper%s'>\n<div class='filename'>%s</div>\n%s\n</div>"
|
||||
(if metadata then " code-metadata" else "")
|
||||
(Pos.get_file (Pos.get_position c))
|
||||
(Pos.get_file (Marked.get_mark c))
|
||||
(pygmentize_code
|
||||
(Pos.same_pos_as ("```catala\n" ^ Pos.unmark c ^ "```") c)
|
||||
(Marked.same_mark_as ("```catala\n" ^ Marked.unmark c ^ "```") c)
|
||||
language)
|
||||
| A.CodeBlock _ -> ()
|
||||
| A.LawHeading (heading, children) ->
|
||||
let h_number = heading.law_heading_precedence + 1 in
|
||||
Format.fprintf fmt "<h%d class='law-heading'><a href='%s'>%s</a></h%d>\n"
|
||||
h_number
|
||||
let is_a_section_to_collapse =
|
||||
(* Only 2 depth sections are collasped in a <details> tag. Indeed, this
|
||||
allow to significantly reduce rendering time (~= 100x for the
|
||||
[aides_logement] example in the catala-website), while remaining
|
||||
practicable. *)
|
||||
h_number = 2
|
||||
in
|
||||
let h_name = Marked.unmark heading.law_heading_name in
|
||||
let complete_headings = parents_headings @ [h_name] in
|
||||
let id = complete_headings |> String.concat "-" |> sanitize_html_href in
|
||||
let fmt_details_open fmt () =
|
||||
if is_a_section_to_collapse then
|
||||
Format.fprintf fmt "<details><summary>%s</summary>" h_name
|
||||
in
|
||||
let fmt_details_close fmt () =
|
||||
if is_a_section_to_collapse then Format.fprintf fmt "</details>"
|
||||
in
|
||||
Format.fprintf fmt
|
||||
"<h%d class='law-heading' id=\"%s\"><a href=\"#%s\">%s</a>%s</h%d>@\n\
|
||||
%a\n\
|
||||
%a\n\
|
||||
%a"
|
||||
h_number id id h_name
|
||||
(match heading.law_heading_id, language with
|
||||
| Some id, Fr ->
|
||||
let ltime = Unix.localtime (Unix.time ()) in
|
||||
P.sprintf "https://legifrance.gouv.fr/codes/id/%s/%d-%02d-%02d" id
|
||||
P.sprintf
|
||||
"<a class=\"link-article\" \
|
||||
href=\"https://legifrance.gouv.fr/codes/id/%s/%d-%02d-%02d\" \
|
||||
target=\"_blank\">Voir le texte sur Légifrance.gouv.fr</a>"
|
||||
id
|
||||
(1900 + ltime.Unix.tm_year)
|
||||
(ltime.Unix.tm_mon + 1) ltime.Unix.tm_mday
|
||||
| _ -> "#")
|
||||
(pre_html (Pos.unmark heading.law_heading_name))
|
||||
h_number;
|
||||
Format.pp_print_list
|
||||
~pp_sep:(fun fmt () -> Format.fprintf fmt "\n")
|
||||
(law_structure_to_html language print_only_law)
|
||||
fmt children
|
||||
| _ -> "")
|
||||
h_number fmt_details_open ()
|
||||
(Format.pp_print_list
|
||||
~pp_sep:(fun fmt () -> Format.fprintf fmt "\n")
|
||||
(law_structure_to_html language print_only_law complete_headings))
|
||||
children fmt_details_close ()
|
||||
| A.LawInclude _ -> ()
|
||||
|
||||
let rec fmt_toc
|
||||
(parents_headings : string list)
|
||||
fmt
|
||||
(items : A.law_structure list) =
|
||||
Format.fprintf fmt "@[<v 2><ol class=\"toc-%d\">@\n%a@\n@]</ol>"
|
||||
(List.length parents_headings)
|
||||
(Format.pp_print_list
|
||||
~pp_sep:(fun fmt () -> Format.fprintf fmt "@\n")
|
||||
(fun fmt item ->
|
||||
match item with
|
||||
| A.LawHeading (heading, childs) ->
|
||||
let h_name = Marked.unmark heading.law_heading_name in
|
||||
let complete_headings = parents_headings @ [h_name] in
|
||||
let id =
|
||||
complete_headings |> String.concat "-" |> sanitize_html_href
|
||||
in
|
||||
Format.fprintf fmt
|
||||
"@[<hov 2><li class=\"toc-item\">@\n\
|
||||
@[<hov 2><div>@\n\
|
||||
<a href=\"#%s\">%s</a>@\n\
|
||||
%a@\n\
|
||||
@]</div>@\n\
|
||||
@]</li>"
|
||||
id h_name
|
||||
(fmt_toc complete_headings)
|
||||
childs
|
||||
| _ -> ()))
|
||||
(items |> List.filter (function A.LawHeading (_, _) -> true | _ -> false))
|
||||
|
||||
(** {1 API} *)
|
||||
|
||||
let ast_to_html
|
||||
@ -202,7 +261,23 @@ let ast_to_html
|
||||
~(print_only_law : bool)
|
||||
(fmt : Format.formatter)
|
||||
(program : A.program) : unit =
|
||||
Format.pp_print_list
|
||||
~pp_sep:(fun fmt () -> Format.fprintf fmt "\n\n")
|
||||
(law_structure_to_html language print_only_law)
|
||||
fmt program.program_items
|
||||
let toc =
|
||||
match language with
|
||||
| C.Fr -> "Sommaire"
|
||||
| C.En -> "Table of contents"
|
||||
| C.Pl -> "Spis treści."
|
||||
in
|
||||
|
||||
Format.fprintf fmt
|
||||
"@[<hov 2><details class=\"toc\">@\n\
|
||||
<summary>%s</summary>@\n\
|
||||
%a@\n\
|
||||
@]</details>\n\
|
||||
%a@\n"
|
||||
toc (fmt_toc []) program.program_items
|
||||
(Format.pp_print_list
|
||||
~pp_sep:(fun fmt () -> Format.fprintf fmt "\n\n")
|
||||
(fun fmt ->
|
||||
Format.fprintf fmt "%a"
|
||||
(law_structure_to_html language print_only_law [])))
|
||||
program.program_items
|
||||
|
@ -182,9 +182,10 @@ let check_exceeding_lines
|
||||
(start_line : int)
|
||||
(filename : string)
|
||||
(content : string) =
|
||||
content |> String.split_on_char '\n'
|
||||
content
|
||||
|> String.split_on_char '\n'
|
||||
|> List.iteri (fun i s ->
|
||||
if CamomileLibrary.UTF8.length s > max_len then (
|
||||
if String.length s > max_len then (
|
||||
Cli.warning_print "The line %s in %s is exceeding %s characters:"
|
||||
(Cli.with_style
|
||||
ANSITerminal.[Bold; yellow]
|
||||
@ -216,7 +217,7 @@ let rec law_structure_to_latex
|
||||
| 6 -> "subsubsubsubsubsubsection"
|
||||
| 7 -> "paragraph"
|
||||
| _ -> "subparagraph")
|
||||
(pre_latexify (Pos.unmark heading.law_heading_name));
|
||||
(pre_latexify (Marked.unmark heading.law_heading_name));
|
||||
Format.pp_print_list
|
||||
~pp_sep:(fun fmt () -> Format.fprintf fmt "\n\n")
|
||||
(law_structure_to_latex language print_only_law)
|
||||
@ -241,10 +242,10 @@ let rec law_structure_to_latex
|
||||
```catala\n\
|
||||
%s```\n\
|
||||
\\end{minted}"
|
||||
(pre_latexify (Filename.basename (Pos.get_file (Pos.get_position c))))
|
||||
(Pos.get_start_line (Pos.get_position c) - 1)
|
||||
(pre_latexify (Filename.basename (Pos.get_file (Marked.get_mark c))))
|
||||
(Pos.get_start_line (Marked.get_mark c) - 1)
|
||||
(get_language_extension language)
|
||||
(Pos.unmark c)
|
||||
(Marked.unmark c)
|
||||
| A.CodeBlock (_, c, true) when not print_only_law ->
|
||||
let metadata_title =
|
||||
match language with
|
||||
@ -252,9 +253,9 @@ let rec law_structure_to_latex
|
||||
| En -> "Metadata"
|
||||
| Pl -> "Metadane"
|
||||
in
|
||||
let start_line = Pos.get_start_line (Pos.get_position c) - 1 in
|
||||
let filename = Filename.basename (Pos.get_file (Pos.get_position c)) in
|
||||
let block_content = Pos.unmark c in
|
||||
let start_line = Pos.get_start_line (Marked.get_mark c) - 1 in
|
||||
let filename = Filename.basename (Pos.get_file (Marked.get_mark c)) in
|
||||
let block_content = Marked.unmark c in
|
||||
check_exceeding_lines start_line filename block_content;
|
||||
Format.fprintf fmt
|
||||
"\\begin{tcolorbox}[colframe=OliveGreen, breakable, \
|
||||
|
@ -78,7 +78,8 @@ let run_pandoc (s : string) (backend : [ `Html | `Latex ]) : string =
|
||||
let pandoc_args =
|
||||
[|
|
||||
"-f";
|
||||
"markdown+multiline_tables";
|
||||
"markdown+multiline_tables+tex_math_dollars";
|
||||
"--mathjax";
|
||||
"-t";
|
||||
(match backend with `Html -> "html" | `Latex -> "latex");
|
||||
"-o";
|
||||
|
@ -14,13 +14,23 @@
|
||||
License for the specific language governing permissions and limitations under
|
||||
the License. *)
|
||||
|
||||
type 'ast plugin_apply_fun_typ =
|
||||
source_file:Utils.Pos.input_file ->
|
||||
output_file:string option ->
|
||||
scope:string option ->
|
||||
'ast ->
|
||||
Scopelang.Dependency.TVertex.t list ->
|
||||
unit
|
||||
|
||||
type 'ast gen = {
|
||||
name : string;
|
||||
extension : string;
|
||||
apply : string option -> 'ast -> Scopelang.Dependency.TVertex.t list -> unit;
|
||||
apply : 'ast plugin_apply_fun_typ;
|
||||
}
|
||||
|
||||
type t = Lcalc of Lcalc.Ast.program gen | Scalc of Scalc.Ast.program gen
|
||||
type t =
|
||||
| Lcalc of Dcalc.Ast.untyped Lcalc.Ast.program gen
|
||||
| Scalc of Scalc.Ast.program gen
|
||||
|
||||
let name = function Lcalc { name; _ } | Scalc { name; _ } -> name
|
||||
let backend_plugins : (string, t) Hashtbl.t = Hashtbl.create 17
|
||||
|
@ -16,13 +16,23 @@
|
||||
|
||||
(** {2 catala-facing API} *)
|
||||
|
||||
type 'ast plugin_apply_fun_typ =
|
||||
source_file:Utils.Pos.input_file ->
|
||||
output_file:string option ->
|
||||
scope:string option ->
|
||||
'ast ->
|
||||
Scopelang.Dependency.TVertex.t list ->
|
||||
unit
|
||||
|
||||
type 'ast gen = {
|
||||
name : string;
|
||||
extension : string;
|
||||
apply : string option -> 'ast -> Scopelang.Dependency.TVertex.t list -> unit;
|
||||
apply : 'ast plugin_apply_fun_typ;
|
||||
}
|
||||
|
||||
type t = Lcalc of Lcalc.Ast.program gen | Scalc of Scalc.Ast.program gen
|
||||
type t =
|
||||
| Lcalc of Dcalc.Ast.untyped Lcalc.Ast.program gen
|
||||
| Scalc of Scalc.Ast.program gen
|
||||
|
||||
val find : string -> t
|
||||
(** Find a registered plugin *)
|
||||
@ -39,19 +49,13 @@ module PluginAPI : sig
|
||||
val register_lcalc :
|
||||
name:string ->
|
||||
extension:string ->
|
||||
(string option ->
|
||||
Lcalc.Ast.program ->
|
||||
Scopelang.Dependency.TVertex.t list ->
|
||||
unit) ->
|
||||
Dcalc.Ast.untyped Lcalc.Ast.program plugin_apply_fun_typ ->
|
||||
unit
|
||||
|
||||
val register_scalc :
|
||||
name:string ->
|
||||
extension:string ->
|
||||
(string option ->
|
||||
Scalc.Ast.program ->
|
||||
Scopelang.Dependency.TVertex.t list ->
|
||||
unit) ->
|
||||
Scalc.Ast.program plugin_apply_fun_typ ->
|
||||
unit
|
||||
end
|
||||
|
||||
|
473
compiler/plugins/api_web.ml
Normal file
473
compiler/plugins/api_web.ml
Normal file
@ -0,0 +1,473 @@
|
||||
(* This file is part of the Catala compiler, a specification language for tax
|
||||
and social benefits computation rules. Copyright (C) 2020 Inria,
|
||||
contributors: Emile Rolley <emile.rolley@tuta.io>, Louis Gesbert
|
||||
<louis.gesbert@inria.fr>.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
use this file except in compliance with the License. You may obtain a copy of
|
||||
the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
License for the specific language governing permissions and limitations under
|
||||
the License. *)
|
||||
|
||||
(** Catala plugin for generating web APIs. It generates OCaml code before the
|
||||
the associated [js_of_ocaml] wrapper. *)
|
||||
|
||||
open Utils
|
||||
open String_common
|
||||
open Lcalc
|
||||
open Lcalc.Ast
|
||||
open Lcalc.To_ocaml
|
||||
module D = Dcalc.Ast
|
||||
|
||||
let name = "api_web"
|
||||
let extension = ".ml"
|
||||
|
||||
(** Contains all format functions used to generating the [js_of_ocaml] wrapper
|
||||
of the corresponding Catala program. *)
|
||||
module To_jsoo = struct
|
||||
let to_camel_case (s : string) : string =
|
||||
String.split_on_char '_' s
|
||||
|> (function
|
||||
| hd :: tl -> hd :: List.map String.capitalize_ascii tl | l -> l)
|
||||
|> String.concat ""
|
||||
|
||||
let format_struct_field_name_camel_case
|
||||
(fmt : Format.formatter)
|
||||
(v : Dcalc.Ast.StructFieldName.t) : unit =
|
||||
let s =
|
||||
Format.asprintf "%a" Dcalc.Ast.StructFieldName.format_t v
|
||||
|> to_ascii
|
||||
|> to_snake_case
|
||||
|> avoid_keywords
|
||||
|> to_camel_case
|
||||
in
|
||||
Format.fprintf fmt "%s" s
|
||||
|
||||
let format_tlit (fmt : Format.formatter) (l : Dcalc.Ast.typ_lit) : unit =
|
||||
Dcalc.Print.format_base_type fmt
|
||||
(match l with
|
||||
| TUnit -> "unit"
|
||||
| TInt -> "int"
|
||||
| TRat | TMoney -> "Js.number Js.t"
|
||||
| TDuration -> "Runtime_jsoo.Runtime.duration Js.t"
|
||||
| TBool -> "bool Js.t"
|
||||
| TDate -> "Js.js_string Js.t")
|
||||
|
||||
let rec format_typ (fmt : Format.formatter) (typ : Dcalc.Ast.typ Marked.pos) :
|
||||
unit =
|
||||
let format_typ_with_parens
|
||||
(fmt : Format.formatter)
|
||||
(t : Dcalc.Ast.typ Marked.pos) =
|
||||
if typ_needs_parens t then Format.fprintf fmt "(%a)" format_typ t
|
||||
else Format.fprintf fmt "%a" format_typ t
|
||||
in
|
||||
match Marked.unmark typ with
|
||||
| TLit l -> Format.fprintf fmt "%a" format_tlit l
|
||||
| TTuple (_, Some s) -> Format.fprintf fmt "%a Js.t" format_struct_name s
|
||||
| TTuple (_, None) ->
|
||||
(* Tuples are encoded as an javascript polymorphic array. *)
|
||||
Format.fprintf fmt "Js.Unsafe.any_js_array Js.t "
|
||||
| TEnum ([t], e) when D.EnumName.compare e option_enum = 0 ->
|
||||
Format.fprintf fmt "@[<hov 2>(%a)@] %a" format_typ_with_parens t
|
||||
format_enum_name e
|
||||
| TEnum (_, e) when D.EnumName.compare e option_enum = 0 ->
|
||||
Errors.raise_spanned_error (Marked.get_mark typ)
|
||||
"Internal Error: found an typing parameter for an eoption type of the \
|
||||
wrong length."
|
||||
| TEnum (_, e) -> Format.fprintf fmt "%a Js.t" format_enum_name e
|
||||
| TArray t1 ->
|
||||
Format.fprintf fmt "@[%a@ Js.js_array Js.t@]" format_typ_with_parens t1
|
||||
| TAny -> Format.fprintf fmt "Js.Unsafe.any Js.t"
|
||||
| TArrow (t1, t2) ->
|
||||
Format.fprintf fmt "(@[<hov 2>%a, @ %a@]) Js.meth_callback"
|
||||
format_typ_with_parens t1 format_typ_with_parens t2
|
||||
|
||||
let rec format_typ_to_jsoo fmt typ =
|
||||
match Marked.unmark typ with
|
||||
| Dcalc.Ast.TLit TBool -> Format.fprintf fmt "Js.bool"
|
||||
| Dcalc.Ast.TLit TInt -> Format.fprintf fmt "integer_to_int"
|
||||
| Dcalc.Ast.TLit TRat ->
|
||||
Format.fprintf fmt "Js.number_of_float %@%@ decimal_to_float"
|
||||
| Dcalc.Ast.TLit TMoney ->
|
||||
Format.fprintf fmt "Js.number_of_float %@%@ money_to_float"
|
||||
| Dcalc.Ast.TLit TDuration -> Format.fprintf fmt "duration_to_jsoo"
|
||||
| Dcalc.Ast.TLit TDate -> Format.fprintf fmt "date_to_jsoo"
|
||||
| Dcalc.Ast.TEnum (_, ename) ->
|
||||
Format.fprintf fmt "%a_to_jsoo" format_enum_name ename
|
||||
| Dcalc.Ast.TTuple (_, Some sname) ->
|
||||
Format.fprintf fmt "%a_to_jsoo" format_struct_name sname
|
||||
| Dcalc.Ast.TArray t ->
|
||||
Format.fprintf fmt "Js.array %@%@ Array.map (fun x -> %a x)"
|
||||
format_typ_to_jsoo t
|
||||
| Dcalc.Ast.TAny | Dcalc.Ast.TTuple (_, None) ->
|
||||
Format.fprintf fmt "Js.Unsafe.inject"
|
||||
| _ -> Format.fprintf fmt ""
|
||||
|
||||
let rec format_typ_of_jsoo fmt typ =
|
||||
match Marked.unmark typ with
|
||||
| Dcalc.Ast.TLit TBool -> Format.fprintf fmt "Js.to_bool"
|
||||
| Dcalc.Ast.TLit TInt -> Format.fprintf fmt "integer_of_int"
|
||||
| Dcalc.Ast.TLit TRat ->
|
||||
Format.fprintf fmt "decimal_of_float %@%@ Js.float_of_number"
|
||||
| Dcalc.Ast.TLit TMoney ->
|
||||
Format.fprintf fmt
|
||||
"money_of_decimal %@%@ decimal_of_float %@%@ Js.float_of_number"
|
||||
| Dcalc.Ast.TLit TDuration -> Format.fprintf fmt "duration_of_jsoo"
|
||||
| Dcalc.Ast.TLit TDate -> Format.fprintf fmt "date_of_jsoo"
|
||||
| Dcalc.Ast.TEnum (_, ename) ->
|
||||
Format.fprintf fmt "%a_of_jsoo" format_enum_name ename
|
||||
| Dcalc.Ast.TTuple (_, Some sname) ->
|
||||
Format.fprintf fmt "%a_of_jsoo" format_struct_name sname
|
||||
| Dcalc.Ast.TArray t ->
|
||||
Format.fprintf fmt "Array.map (fun x -> %a x) %@%@ Js.to_array"
|
||||
format_typ_of_jsoo t
|
||||
| _ -> Format.fprintf fmt ""
|
||||
|
||||
let format_var_camel_case (fmt : Format.formatter) (v : 'm var) : unit =
|
||||
let lowercase_name =
|
||||
Bindlib.name_of v
|
||||
|> to_ascii
|
||||
|> to_snake_case
|
||||
|> Re.Pcre.substitute ~rex:(Re.Pcre.regexp "\\.") ~subst:(fun _ ->
|
||||
"_dot_")
|
||||
|> to_ascii
|
||||
|> avoid_keywords
|
||||
|> to_camel_case
|
||||
in
|
||||
if
|
||||
List.mem lowercase_name ["handle_default"; "handle_default_opt"]
|
||||
|| begins_with_uppercase (Bindlib.name_of v)
|
||||
then Format.fprintf fmt "%s" lowercase_name
|
||||
else if lowercase_name = "_" then Format.fprintf fmt "%s" lowercase_name
|
||||
else Format.fprintf fmt "%s_" lowercase_name
|
||||
|
||||
let format_ctx
|
||||
(type_ordering : Scopelang.Dependency.TVertex.t list)
|
||||
(fmt : Format.formatter)
|
||||
(ctx : D.decl_ctx) : unit =
|
||||
let format_prop_or_meth fmt (struct_field_type : D.typ Marked.pos) =
|
||||
match Marked.unmark struct_field_type with
|
||||
| Dcalc.Ast.TArrow _ -> Format.fprintf fmt "Js.meth"
|
||||
| _ -> Format.fprintf fmt "Js.readonly_prop"
|
||||
in
|
||||
let format_struct_decl fmt (struct_name, struct_fields) =
|
||||
let fmt_struct_name fmt _ = format_struct_name fmt struct_name in
|
||||
let fmt_module_struct_name fmt _ =
|
||||
To_ocaml.format_to_module_name fmt (`Sname struct_name)
|
||||
in
|
||||
let fmt_to_jsoo fmt _ =
|
||||
Format.fprintf fmt "%a"
|
||||
(Format.pp_print_list
|
||||
~pp_sep:(fun fmt () -> Format.fprintf fmt "@\n")
|
||||
(fun fmt (struct_field, struct_field_type) ->
|
||||
match Marked.unmark struct_field_type with
|
||||
| Dcalc.Ast.TArrow (t1, t2) ->
|
||||
Format.fprintf fmt
|
||||
"@[<hov 2>method %a =@ Js.wrap_meth_callback@ @[<hv 2>(@,\
|
||||
fun input ->@ %a (%a.%a (%a input)))@]@]"
|
||||
format_struct_field_name_camel_case struct_field
|
||||
format_typ_to_jsoo t2 fmt_struct_name ()
|
||||
format_struct_field_name (None, struct_field)
|
||||
format_typ_of_jsoo t1
|
||||
| _ ->
|
||||
Format.fprintf fmt "@[<hov 2>val %a =@ %a %a.%a@]"
|
||||
format_struct_field_name_camel_case struct_field
|
||||
format_typ_to_jsoo struct_field_type fmt_struct_name ()
|
||||
format_struct_field_name (None, struct_field)))
|
||||
struct_fields
|
||||
in
|
||||
let fmt_of_jsoo fmt _ =
|
||||
Format.fprintf fmt "%a"
|
||||
(Format.pp_print_list
|
||||
~pp_sep:(fun fmt () -> Format.fprintf fmt ";@\n")
|
||||
(fun fmt (struct_field, struct_field_type) ->
|
||||
match Marked.unmark struct_field_type with
|
||||
| Dcalc.Ast.TArrow _ ->
|
||||
Format.fprintf fmt
|
||||
"%a = failwith \"The function '%a' translation isn't yet \
|
||||
supported...\""
|
||||
format_struct_field_name (None, struct_field)
|
||||
format_struct_field_name (None, struct_field)
|
||||
| _ ->
|
||||
Format.fprintf fmt
|
||||
"@[<hv 2>%a =@ @[<hov 2>%a@ @[<hov>%a@,##.%a@]@]@]"
|
||||
format_struct_field_name (None, struct_field)
|
||||
format_typ_of_jsoo struct_field_type fmt_struct_name ()
|
||||
format_struct_field_name_camel_case struct_field))
|
||||
struct_fields
|
||||
in
|
||||
let fmt_conv_funs fmt _ =
|
||||
Format.fprintf fmt
|
||||
"@[<hov 2>let %a_to_jsoo@ (%a@ : %a.t)@ : %a Js.t =@ @[<hv \
|
||||
2>object%%js@\n\
|
||||
%a@\n\
|
||||
@]@]end@\n\
|
||||
@[<hov 2>let %a_of_jsoo@ @[<hov 2>(%a@ : %a Js.t)@] :@ %a.t =@ \
|
||||
@[<hv 2>{@,\
|
||||
%a@]@\n\
|
||||
}@]"
|
||||
fmt_struct_name () fmt_struct_name () fmt_module_struct_name ()
|
||||
fmt_struct_name () fmt_to_jsoo () fmt_struct_name () fmt_struct_name
|
||||
() fmt_struct_name () fmt_module_struct_name () fmt_of_jsoo ()
|
||||
in
|
||||
|
||||
if List.length struct_fields = 0 then
|
||||
Format.fprintf fmt
|
||||
"class type %a =@ object end@\n\
|
||||
let %a_to_jsoo (_ : %a.t) : %a Js.t = object%%js end@\n\
|
||||
let %a_of_jsoo (_ : %a Js.t) : %a.t = ()" fmt_struct_name ()
|
||||
fmt_struct_name () fmt_module_struct_name () fmt_struct_name ()
|
||||
fmt_struct_name () fmt_struct_name () fmt_module_struct_name ()
|
||||
else
|
||||
Format.fprintf fmt
|
||||
"@[<hv 2>class type %a =@ @[<hov 2>object@ %a@]@,end@\n%a@]@\n"
|
||||
fmt_struct_name ()
|
||||
(Format.pp_print_list
|
||||
~pp_sep:(fun fmt () -> Format.fprintf fmt "@\n")
|
||||
(fun fmt (struct_field, struct_field_type) ->
|
||||
Format.fprintf fmt "@[<hov 2>method %a:@ %a %a@]"
|
||||
format_struct_field_name_camel_case struct_field format_typ
|
||||
struct_field_type format_prop_or_meth struct_field_type))
|
||||
struct_fields fmt_conv_funs ()
|
||||
in
|
||||
let format_enum_decl
|
||||
fmt
|
||||
(enum_name, (enum_cons : (D.EnumConstructor.t * D.typ Marked.pos) list))
|
||||
=
|
||||
let fmt_enum_name fmt _ = format_enum_name fmt enum_name in
|
||||
let fmt_module_enum_name fmt _ =
|
||||
To_ocaml.format_to_module_name fmt (`Ename enum_name)
|
||||
in
|
||||
let fmt_to_jsoo fmt _ =
|
||||
Format.fprintf fmt "%a"
|
||||
(Format.pp_print_list
|
||||
~pp_sep:(fun fmt () -> Format.fprintf fmt "@\n")
|
||||
(fun fmt (cname, typ) ->
|
||||
match Marked.unmark typ with
|
||||
| Dcalc.Ast.TTuple (_, None) ->
|
||||
Cli.error_print
|
||||
"Tuples aren't supported yet in the conversion to JS"
|
||||
| _ ->
|
||||
Format.fprintf fmt
|
||||
"@[<v 2>@[<v 4>| %a arg -> object%%js@\n\
|
||||
val kind = Js.string \"%a\"@\n\
|
||||
val payload = Js.Unsafe.coerce (Js.Unsafe.inject (%a \
|
||||
arg))@]@\n\
|
||||
end@]"
|
||||
format_enum_cons_name cname format_enum_cons_name cname
|
||||
format_typ_to_jsoo typ))
|
||||
enum_cons
|
||||
in
|
||||
let fmt_of_jsoo fmt _ =
|
||||
Format.fprintf fmt
|
||||
"@[<hov 2>match@ %a##.kind@ |> Js.to_string@ with@]@\n\
|
||||
@[<hv>%a@\n\
|
||||
@[<hv 2>| cons ->@ @[<hov 2>failwith@ @[<hov 2>(Printf.sprintf@ \
|
||||
\"Unexpected '%%s' kind for the enumeration '%a.t'\"@ cons)@]@]@]@]"
|
||||
fmt_enum_name ()
|
||||
(Format.pp_print_list
|
||||
~pp_sep:(fun fmt () -> Format.fprintf fmt "@\n")
|
||||
(fun fmt (cname, typ) ->
|
||||
match Marked.unmark typ with
|
||||
| Dcalc.Ast.TTuple (_, None) ->
|
||||
Cli.error_print
|
||||
"Tuples aren't yet supported in the conversion to JS..."
|
||||
| Dcalc.Ast.TLit TUnit ->
|
||||
Format.fprintf fmt "@[<hv 2>| \"%a\" ->@ %a.%a ()@]"
|
||||
format_enum_cons_name cname fmt_module_enum_name ()
|
||||
format_enum_cons_name cname
|
||||
| _ ->
|
||||
Format.fprintf fmt
|
||||
"| \"%a\" ->@\n%a.%a (%a (Js.Unsafe.coerce %a##.payload))"
|
||||
format_enum_cons_name cname fmt_module_enum_name ()
|
||||
format_enum_cons_name cname format_typ_of_jsoo typ
|
||||
fmt_enum_name ()))
|
||||
enum_cons fmt_module_enum_name ()
|
||||
in
|
||||
|
||||
let fmt_conv_funs fmt _ =
|
||||
Format.fprintf fmt
|
||||
"@[<hov 2>let %a_to_jsoo@ : %a.t -> %a Js.t@ = function@\n\
|
||||
%a@]@\n\
|
||||
@\n\
|
||||
@[<hov 2>let %a_of_jsoo@ @[<hov 2>(%a@ : %a Js.t)@]@ : %a.t =@ %a@]@\n"
|
||||
fmt_enum_name () fmt_module_enum_name () fmt_enum_name () fmt_to_jsoo
|
||||
() fmt_enum_name () fmt_enum_name () fmt_enum_name ()
|
||||
fmt_module_enum_name () fmt_of_jsoo ()
|
||||
in
|
||||
Format.fprintf fmt
|
||||
"@[<v 2>class type %a =@ @[<v 2>object@ @[<hov 2>method kind :@ \
|
||||
Js.js_string Js.t Js.readonly_prop@\n\
|
||||
@[<v 2>(** Expects one of:@\n\
|
||||
%a *)@]@]@\n\
|
||||
@\n\
|
||||
@[<hov 2>method payload :@ Js.Unsafe.any Js.t Js.readonly_prop@]@]@\n\
|
||||
end@]@\n\
|
||||
@\n\
|
||||
%a@\n"
|
||||
format_enum_name enum_name
|
||||
(Format.pp_print_list
|
||||
~pp_sep:(fun fmt () -> Format.fprintf fmt "@\n")
|
||||
(fun fmt (enum_cons, _) ->
|
||||
Format.fprintf fmt "- \"%a\"" format_enum_cons_name enum_cons))
|
||||
enum_cons fmt_conv_funs ()
|
||||
in
|
||||
let is_in_type_ordering s =
|
||||
List.exists
|
||||
(fun struct_or_enum ->
|
||||
match struct_or_enum with
|
||||
| Scopelang.Dependency.TVertex.Enum _ -> false
|
||||
| Scopelang.Dependency.TVertex.Struct s' -> s = s')
|
||||
type_ordering
|
||||
in
|
||||
let scope_structs =
|
||||
List.map
|
||||
(fun (s, _) -> Scopelang.Dependency.TVertex.Struct s)
|
||||
(Dcalc.Ast.StructMap.bindings
|
||||
(Dcalc.Ast.StructMap.filter
|
||||
(fun s _ -> not (is_in_type_ordering s))
|
||||
ctx.ctx_structs))
|
||||
in
|
||||
List.iter
|
||||
(fun struct_or_enum ->
|
||||
match struct_or_enum with
|
||||
| Scopelang.Dependency.TVertex.Struct s ->
|
||||
Format.fprintf fmt "%a@\n" format_struct_decl (s, find_struct s ctx)
|
||||
| Scopelang.Dependency.TVertex.Enum e ->
|
||||
Format.fprintf fmt "%a@\n" format_enum_decl (e, find_enum e ctx))
|
||||
(type_ordering @ scope_structs)
|
||||
|
||||
let fmt_input_struct_name fmt (scope_def : ('a expr, 'm) D.scope_def) =
|
||||
format_struct_name fmt scope_def.scope_body.scope_body_input_struct
|
||||
|
||||
let fmt_output_struct_name fmt (scope_def : ('a expr, 'm) D.scope_def) =
|
||||
format_struct_name fmt scope_def.scope_body.scope_body_output_struct
|
||||
|
||||
let rec format_scopes_to_fun
|
||||
(ctx : Dcalc.Ast.decl_ctx)
|
||||
(fmt : Format.formatter)
|
||||
(scopes : ('expr, 'm) Dcalc.Ast.scopes) =
|
||||
match scopes with
|
||||
| Dcalc.Ast.Nil -> ()
|
||||
| Dcalc.Ast.ScopeDef scope_def ->
|
||||
let scope_var, scope_next = Bindlib.unbind scope_def.scope_next in
|
||||
let fmt_fun_call fmt _ =
|
||||
Format.fprintf fmt "@[<hv>%a@ |> %a_of_jsoo@ |> %a@ |> %a_to_jsoo@]"
|
||||
fmt_input_struct_name scope_def fmt_input_struct_name scope_def
|
||||
format_var scope_var fmt_output_struct_name scope_def
|
||||
in
|
||||
Format.fprintf fmt
|
||||
"@\n@\n@[<hov 2>let %a@ (%a : %a Js.t)@ : %a Js.t =@\n%a@]@\n%a"
|
||||
format_var scope_var fmt_input_struct_name scope_def
|
||||
fmt_input_struct_name scope_def fmt_output_struct_name scope_def
|
||||
fmt_fun_call () (format_scopes_to_fun ctx) scope_next
|
||||
|
||||
let rec format_scopes_to_callbacks
|
||||
(ctx : Dcalc.Ast.decl_ctx)
|
||||
(fmt : Format.formatter)
|
||||
(scopes : ('expr, 'm) Dcalc.Ast.scopes) : unit =
|
||||
match scopes with
|
||||
| Dcalc.Ast.Nil -> ()
|
||||
| Dcalc.Ast.ScopeDef scope_def ->
|
||||
let scope_var, scope_next = Bindlib.unbind scope_def.scope_next in
|
||||
let fmt_meth_name fmt _ =
|
||||
Format.fprintf fmt "method %a : (%a Js.t -> %a Js.t) Js.callback"
|
||||
format_var_camel_case scope_var fmt_input_struct_name scope_def
|
||||
fmt_output_struct_name scope_def
|
||||
in
|
||||
Format.fprintf fmt "@,@[<hov 2>%a =@ Js.wrap_callback@ %a@]@,%a"
|
||||
fmt_meth_name () format_var scope_var
|
||||
(format_scopes_to_callbacks ctx)
|
||||
scope_next
|
||||
|
||||
let format_program
|
||||
(fmt : Format.formatter)
|
||||
(module_name : string option)
|
||||
(prgm : 'm Lcalc.Ast.program)
|
||||
(type_ordering : Scopelang.Dependency.TVertex.t list) =
|
||||
let fmt_lib_name fmt _ =
|
||||
Format.fprintf fmt "%sLib"
|
||||
(Option.fold ~none:""
|
||||
~some:(fun name ->
|
||||
List.nth (String.split_on_char ' ' name) 1
|
||||
|> String.split_on_char '_'
|
||||
|> List.map String.capitalize_ascii
|
||||
|> String.concat "")
|
||||
module_name)
|
||||
in
|
||||
|
||||
Cli.call_unstyled (fun _ ->
|
||||
Format.fprintf fmt
|
||||
"(** This file has been generated by the Catala compiler, do not \
|
||||
edit! *)@\n\
|
||||
@\n\
|
||||
open Runtime_ocaml.Runtime@\n\
|
||||
open Runtime_jsoo.Runtime@\n\
|
||||
open Js_of_ocaml@\n\
|
||||
%s@\n\
|
||||
@\n\
|
||||
[@@@@@@ocaml.warning \"-4-26-27-32-41-42\"]@\n\
|
||||
@\n\
|
||||
(* Generated API *)@\n\
|
||||
@\n\
|
||||
%a@\n\
|
||||
%a@\n\
|
||||
@\n\
|
||||
@[<v 2>let _ =@ @[<hov 2> Js.export \"%a\"@\n\
|
||||
@[<v 2>(object%%js@ %a@]@\n\
|
||||
end)@]@]@?"
|
||||
(Option.fold ~none:"" ~some:(fun name -> name) module_name)
|
||||
(format_ctx type_ordering) prgm.decl_ctx
|
||||
(format_scopes_to_fun prgm.decl_ctx)
|
||||
prgm.scopes fmt_lib_name ()
|
||||
(format_scopes_to_callbacks prgm.decl_ctx)
|
||||
prgm.scopes)
|
||||
end
|
||||
|
||||
let apply
|
||||
~(source_file : Pos.input_file)
|
||||
~(output_file : string option)
|
||||
~scope
|
||||
(prgm : 'm Lcalc.Ast.program)
|
||||
(type_ordering : Scopelang.Dependency.TVertex.t list) =
|
||||
ignore scope;
|
||||
File.with_formatter_of_opt_file output_file (fun fmt ->
|
||||
Cli.trace_flag := true;
|
||||
Cli.debug_print "Writing OCaml code to %s..."
|
||||
(Option.value ~default:"stdout" output_file);
|
||||
To_ocaml.format_program fmt prgm type_ordering);
|
||||
|
||||
let output_file, filename_without_ext =
|
||||
match output_file with
|
||||
| Some "-" -> output_file, output_file
|
||||
| Some f ->
|
||||
output_file, Some (Filename.basename f |> Filename.remove_extension)
|
||||
| None -> Some "-", None
|
||||
in
|
||||
let jsoo_output_file, with_formatter =
|
||||
File.get_formatter_of_out_channel ~source_file
|
||||
~output_file:
|
||||
(Option.map
|
||||
(fun name ->
|
||||
if "-" = name then "-"
|
||||
else Filename.remove_extension name ^ "_api_web.ml")
|
||||
output_file)
|
||||
~ext:"_api_web.ml" ()
|
||||
in
|
||||
let module_name =
|
||||
Option.map
|
||||
(fun name -> Printf.sprintf "open %s" (String.capitalize_ascii name))
|
||||
filename_without_ext
|
||||
in
|
||||
with_formatter (fun fmt ->
|
||||
Cli.debug_print "Writing JSOO API code to %s..."
|
||||
(Option.value ~default:"stdout" jsoo_output_file);
|
||||
To_jsoo.format_program fmt module_name prgm type_ordering)
|
||||
|
||||
let () = Driver.Plugin.register_lcalc ~name ~extension apply
|
@ -5,10 +5,16 @@
|
||||
(libraries catala.driver))
|
||||
|
||||
(executable
|
||||
(name jsoo)
|
||||
(name api_web)
|
||||
(modes plugin)
|
||||
(modules jsoo)
|
||||
(libraries catala.driver catala.runtime))
|
||||
(modules api_web)
|
||||
(libraries catala.driver))
|
||||
|
||||
(executable
|
||||
(name json_schema)
|
||||
(modes plugin)
|
||||
(modules json_schema)
|
||||
(libraries catala.driver))
|
||||
|
||||
(documentation
|
||||
(package catala)
|
||||
|
244
compiler/plugins/json_schema.ml
Normal file
244
compiler/plugins/json_schema.ml
Normal file
@ -0,0 +1,244 @@
|
||||
(* This file is part of the Catala compiler, a specification language for tax
|
||||
and social benefits computation rules. Copyright (C) 2020 Inria,
|
||||
contributors: Emile Rolley <emile.rolley@tuta.io>.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
use this file except in compliance with the License. You may obtain a copy of
|
||||
the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
License for the specific language governing permissions and limitations under
|
||||
the License. *)
|
||||
|
||||
(** Catala plugin for generating {{:https://json-schema.org} JSON schemas} used
|
||||
to build forms for the Catala website. *)
|
||||
|
||||
let name = "json_schema"
|
||||
let extension = "_schema.json"
|
||||
|
||||
open Utils
|
||||
open String_common
|
||||
open Lcalc.Ast
|
||||
open Lcalc.To_ocaml
|
||||
module D = Dcalc.Ast
|
||||
|
||||
(** Contains all format functions used to format a Lcalc Catala program
|
||||
representation to a JSON schema describing the corresponding web form. *)
|
||||
module To_json = struct
|
||||
let to_camel_case (s : string) : string =
|
||||
String.split_on_char '_' s
|
||||
|> (function
|
||||
| hd :: tl -> hd :: List.map String.capitalize_ascii tl | l -> l)
|
||||
|> String.concat ""
|
||||
|
||||
let format_struct_field_name_camel_case
|
||||
(fmt : Format.formatter)
|
||||
(v : Dcalc.Ast.StructFieldName.t) : unit =
|
||||
let s =
|
||||
Format.asprintf "%a" Dcalc.Ast.StructFieldName.format_t v
|
||||
|> to_ascii
|
||||
|> to_snake_case
|
||||
|> avoid_keywords
|
||||
|> to_camel_case
|
||||
in
|
||||
Format.fprintf fmt "%s" s
|
||||
|
||||
let rec find_scope_def (target_name : string) :
|
||||
('m expr, 'm) D.scopes -> ('m expr, 'm) D.scope_def option = function
|
||||
| D.Nil -> None
|
||||
| D.ScopeDef scope_def ->
|
||||
let name =
|
||||
Format.asprintf "%a" D.ScopeName.format_t scope_def.scope_name
|
||||
in
|
||||
if name = target_name then Some scope_def
|
||||
else
|
||||
let _, next_scope = Bindlib.unbind scope_def.scope_next in
|
||||
find_scope_def target_name next_scope
|
||||
|
||||
let fmt_tlit fmt (tlit : D.typ_lit) =
|
||||
match tlit with
|
||||
| TUnit -> Format.fprintf fmt "\"type\": \"null\",@\n\"default\": null"
|
||||
| TInt | TRat -> Format.fprintf fmt "\"type\": \"number\",@\n\"default\": 0"
|
||||
| TMoney ->
|
||||
Format.fprintf fmt
|
||||
"\"type\": \"number\",@\n\"minimum\": 0,@\n\"default\": 0"
|
||||
| TBool -> Format.fprintf fmt "\"type\": \"boolean\",@\n\"default\": false"
|
||||
| TDate -> Format.fprintf fmt "\"type\": \"string\",@\n\"format\": \"date\""
|
||||
| TDuration -> failwith "TODO: tlit duration"
|
||||
|
||||
let rec fmt_type fmt (typ : D.marked_typ) =
|
||||
match Marked.unmark typ with
|
||||
| D.TLit tlit -> fmt_tlit fmt tlit
|
||||
| D.TTuple (_, Some sname) ->
|
||||
Format.fprintf fmt "\"$ref\": \"#/definitions/%a\"" format_struct_name
|
||||
sname
|
||||
| D.TEnum (_, ename) ->
|
||||
Format.fprintf fmt "\"$ref\": \"#/definitions/%a\"" format_enum_name ename
|
||||
| D.TArray t ->
|
||||
Format.fprintf fmt
|
||||
"\"type\": \"array\",@\n\
|
||||
\"default\": [],@\n\
|
||||
@[<hov 2>\"items\": {@\n\
|
||||
%a@]@\n\
|
||||
}"
|
||||
fmt_type t
|
||||
| _ -> ()
|
||||
|
||||
let fmt_struct_properties
|
||||
(ctx : D.decl_ctx)
|
||||
(fmt : Format.formatter)
|
||||
(sname : D.StructName.t) =
|
||||
Format.fprintf fmt "%a"
|
||||
(Format.pp_print_list
|
||||
~pp_sep:(fun fmt () -> Format.fprintf fmt ",@\n")
|
||||
(fun fmt (field_name, field_type) ->
|
||||
Format.fprintf fmt "@[<hov 2>\"%a\": {@\n%a@]@\n}"
|
||||
format_struct_field_name_camel_case field_name fmt_type field_type))
|
||||
(find_struct sname ctx)
|
||||
|
||||
let fmt_definitions
|
||||
(ctx : D.decl_ctx)
|
||||
(fmt : Format.formatter)
|
||||
(scope_def : ('m expr, 'm) D.scope_def) =
|
||||
let get_name t =
|
||||
match Marked.unmark t with
|
||||
| D.TTuple (_, Some sname) ->
|
||||
Format.asprintf "%a" format_struct_name sname
|
||||
| D.TEnum (_, ename) -> Format.asprintf "%a" format_enum_name ename
|
||||
| _ -> failwith "unreachable: only structs and enums are collected."
|
||||
in
|
||||
let rec collect_required_type_defs_from_scope_input
|
||||
(input_struct : D.StructName.t) : D.marked_typ list =
|
||||
let rec collect (acc : D.marked_typ list) (t : D.marked_typ) :
|
||||
D.marked_typ list =
|
||||
match Marked.unmark t with
|
||||
| D.TTuple (_, Some s) ->
|
||||
(* Scope's input is a struct. *)
|
||||
(t :: acc) @ collect_required_type_defs_from_scope_input s
|
||||
| D.TEnum (ts, _) -> List.fold_left collect (t :: acc) ts
|
||||
| D.TArray t -> collect acc t
|
||||
| _ -> acc
|
||||
in
|
||||
find_struct input_struct ctx
|
||||
|> List.fold_left (fun acc (_, field_typ) -> collect acc field_typ) []
|
||||
|> List.sort_uniq (fun t t' -> String.compare (get_name t) (get_name t'))
|
||||
in
|
||||
let fmt_enum_properties fmt ename =
|
||||
let enum_def = find_enum ename ctx in
|
||||
Format.fprintf fmt
|
||||
"@[<hov 2>\"kind\": {@\n\
|
||||
\"type\": \"string\",@\n\
|
||||
@[<hov 2>\"anyOf\": [@\n\
|
||||
%a@]@\n\
|
||||
]@]@\n\
|
||||
}@\n\
|
||||
},@\n\
|
||||
@[<hov 2>\"allOf\": [@\n\
|
||||
%a@]@\n\
|
||||
]@]@\n\
|
||||
}"
|
||||
(Format.pp_print_list
|
||||
~pp_sep:(fun fmt () -> Format.fprintf fmt ",@\n")
|
||||
(fun fmt (enum_cons, _) ->
|
||||
Format.fprintf fmt
|
||||
"@[<hov 2>{@\n\"type\": \"string\",@\n\"enum\": [\"%a\"]@]@\n}"
|
||||
format_enum_cons_name enum_cons))
|
||||
enum_def
|
||||
(Format.pp_print_list
|
||||
~pp_sep:(fun fmt () -> Format.fprintf fmt ",@\n")
|
||||
(fun fmt (enum_cons, payload_type) ->
|
||||
Format.fprintf fmt
|
||||
"@[<hov 2>{@\n\
|
||||
@[<hov 2>\"if\": {@\n\
|
||||
@[<hov 2>\"properties\": {@\n\
|
||||
@[<hov 2>\"kind\": {@\n\
|
||||
\"const\": \"%a\"@]@\n\
|
||||
}@]@\n\
|
||||
}@]@\n\
|
||||
},@\n\
|
||||
@[<hov 2>\"then\": {@\n\
|
||||
@[<hov 2>\"properties\": {@\n\
|
||||
@[<hov 2>\"payload\": {@\n\
|
||||
%a@]@\n\
|
||||
}@]@\n\
|
||||
}@]@\n\
|
||||
}@]@\n\
|
||||
}"
|
||||
format_enum_cons_name enum_cons fmt_type payload_type))
|
||||
enum_def
|
||||
in
|
||||
|
||||
Format.fprintf fmt "@\n%a"
|
||||
(Format.pp_print_list
|
||||
~pp_sep:(fun fmt () -> Format.fprintf fmt ",@\n")
|
||||
(fun fmt typ ->
|
||||
match Marked.unmark typ with
|
||||
| D.TTuple (_, Some sname) ->
|
||||
Format.fprintf fmt
|
||||
"@[<hov 2>\"%a\": {@\n\
|
||||
\"type\": \"object\",@\n\
|
||||
@[<hov 2>\"properties\": {@\n\
|
||||
%a@]@\n\
|
||||
}@]@\n\
|
||||
}"
|
||||
format_struct_name sname
|
||||
(fmt_struct_properties ctx)
|
||||
sname
|
||||
| D.TEnum (_, ename) ->
|
||||
Format.fprintf fmt
|
||||
"@[<hov 2>\"%a\": {@\n\
|
||||
\"type\": \"object\",@\n\
|
||||
@[<hov 2>\"properties\": {@\n\
|
||||
%a@]@]@\n"
|
||||
format_enum_name ename fmt_enum_properties ename
|
||||
| _ -> ()))
|
||||
(collect_required_type_defs_from_scope_input
|
||||
scope_def.scope_body.scope_body_input_struct)
|
||||
|
||||
let format_program
|
||||
(fmt : Format.formatter)
|
||||
(scope : string)
|
||||
(prgm : 'm Lcalc.Ast.program) =
|
||||
match find_scope_def scope prgm.scopes with
|
||||
| None -> Cli.error_print "Internal error: scope '%s' not found." scope
|
||||
| Some scope_def ->
|
||||
Cli.call_unstyled (fun _ ->
|
||||
Format.fprintf fmt
|
||||
"{@[<hov 2>@\n\
|
||||
\"type\": \"object\",@\n\
|
||||
\"@[<hov 2>definitions\": {%a@]@\n\
|
||||
},@\n\
|
||||
\"@[<hov 2>properties\": {@\n\
|
||||
%a@]@\n\
|
||||
}@]@\n\
|
||||
}"
|
||||
(fmt_definitions prgm.decl_ctx)
|
||||
scope_def
|
||||
(fmt_struct_properties prgm.decl_ctx)
|
||||
scope_def.scope_body.scope_body_input_struct)
|
||||
end
|
||||
|
||||
let apply
|
||||
~(source_file : Pos.input_file)
|
||||
~(output_file : string option)
|
||||
~(scope : string option)
|
||||
(prgm : 'm Lcalc.Ast.program)
|
||||
(type_ordering : Scopelang.Dependency.TVertex.t list) =
|
||||
ignore source_file;
|
||||
ignore type_ordering;
|
||||
match scope with
|
||||
| Some s ->
|
||||
File.with_formatter_of_opt_file output_file (fun fmt ->
|
||||
Cli.debug_print
|
||||
"Writing JSON schema corresponding to the scope '%s' to the file \
|
||||
%s..."
|
||||
s
|
||||
(Option.value ~default:"stdout" output_file);
|
||||
To_json.format_program fmt s prgm)
|
||||
| None -> Cli.error_print "A scope must be specified for the plugin: %s" name
|
||||
|
||||
let () = Driver.Plugin.register_lcalc ~name ~extension apply
|
@ -1,78 +0,0 @@
|
||||
(* This file is part of the Catala compiler, a specification language for tax
|
||||
and social benefits computation rules. Copyright (C) 2020 Inria, contributor:
|
||||
Louis Gesbert <louis.gesbert@inria.fr>.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
use this file except in compliance with the License. You may obtain a copy of
|
||||
the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
License for the specific language governing permissions and limitations under
|
||||
the License. *)
|
||||
|
||||
(** This file demonstrates the use of backend plugins for Catala. It's a simple
|
||||
wrapper on top of the OCaml backend that calls js_of_ocaml on the generated
|
||||
code. Not for production use. *)
|
||||
|
||||
let name = "jsoo"
|
||||
let extension = ".js"
|
||||
|
||||
let finalise e f =
|
||||
let bt = Printexc.get_raw_backtrace () in
|
||||
f ();
|
||||
Printexc.raise_with_backtrace e bt
|
||||
|
||||
let finally f k =
|
||||
match k () with
|
||||
| r ->
|
||||
f ();
|
||||
r
|
||||
| exception e -> finalise e f
|
||||
|
||||
let with_open_out file f =
|
||||
let oc = open_out file in
|
||||
finally (fun () -> close_out oc) (fun () -> f oc)
|
||||
|
||||
let with_temp_file pfx sfx f =
|
||||
let tmp = Filename.temp_file pfx sfx in
|
||||
match f tmp with
|
||||
| r ->
|
||||
Sys.remove tmp;
|
||||
r
|
||||
| exception e ->
|
||||
let bt = Printexc.get_raw_backtrace () in
|
||||
Sys.remove tmp;
|
||||
Printexc.raise_with_backtrace e bt
|
||||
|
||||
let apply output_file prgm type_ordering =
|
||||
with_temp_file "catala_jsoo_" ".ml" @@ fun ml_file ->
|
||||
Utils.File.with_formatter_of_opt_file output_file @@ fun fmt ->
|
||||
Lcalc.To_ocaml.format_program fmt prgm type_ordering;
|
||||
with_temp_file "catala_jsoo_" ".byte" @@ fun bytecode_file ->
|
||||
if
|
||||
Sys.command
|
||||
(Printf.sprintf
|
||||
"ocamlfind ocamlc -package catala.runtime -linkpkg %S -o %S" ml_file
|
||||
bytecode_file)
|
||||
<> 0
|
||||
then failwith "ocaml err";
|
||||
Utils.Cli.debug_print "OCaml compil ok";
|
||||
let out_arg =
|
||||
match output_file with Some f -> Printf.sprintf "%S" f | None -> "-"
|
||||
in
|
||||
if
|
||||
Sys.command
|
||||
(Printf.sprintf
|
||||
"js_of_ocaml +zarith_stubs_js/biginteger.js \
|
||||
+zarith_stubs_js/runtime.js %S -o %s"
|
||||
bytecode_file out_arg)
|
||||
<> 0
|
||||
then failwith "jsoo err";
|
||||
Utils.Cli.debug_print "Jsoo compil ok, output in %s"
|
||||
(Option.value ~default:"stdout" output_file)
|
||||
|
||||
let () = Driver.Plugin.register_lcalc ~name ~extension apply
|
@ -41,11 +41,25 @@ This trivial example registers a plugin that uses the [scalc] format as input.
|
||||
It simply calls the code of the built-in Python backend, and should be no
|
||||
different to using the normal Catala Python output mode.
|
||||
|
||||
{2 jsoo example}
|
||||
{2 [js_of_ocaml] wrapper generator example}
|
||||
|
||||
This slightly more involved plugin reads the [lcalc] format, applies the code of
|
||||
the [OCaml] backend normally, but then calls the [ocamlc] and [js_of_ocaml]
|
||||
compiler successively on the output in order to give a Javascript output.
|
||||
This plugin generates a [js_of_ocaml] wrapper from the [lcalc] representation
|
||||
of a Catala program.
|
||||
|
||||
Note that this output remains a library, it won't provide user-facing features,
|
||||
and no efforts are made to make it callable from normal JavaScript code.
|
||||
It start by generating the OCaml module before generating the [_api_web.ml]
|
||||
one, which contains all the class types and conversion functions between the
|
||||
OCaml types and their corresponding JS objects. At the end the module exposes
|
||||
all methods in a JS lib [<module_name>Lib].
|
||||
|
||||
See
|
||||
{{:https://github.com/CatalaLang/catala/tree/master/french_law/ocaml/law_source}
|
||||
law_source} for examples of generated code.
|
||||
|
||||
{2 JSON schema generator example}
|
||||
|
||||
This plugin generates a {{:https://json-schema.org} JSON schema} corresponding
|
||||
to a scope of a Catala program.
|
||||
|
||||
See
|
||||
{{:https://github.com/CatalaLang/catala/tree/master/french_law/json_schemas}
|
||||
json_schemas} for examples of generated schemas.
|
||||
|
@ -23,8 +23,10 @@
|
||||
let name = "python-plugin"
|
||||
let extension = ".py"
|
||||
|
||||
let apply output_file prgm type_ordering =
|
||||
Utils.File.with_formatter_of_opt_file output_file @@ fun fmt ->
|
||||
Scalc.To_python.format_program fmt prgm type_ordering
|
||||
let apply ~source_file ~output_file ~scope prgm type_ordering =
|
||||
ignore source_file;
|
||||
ignore scope;
|
||||
Utils.File.with_formatter_of_opt_file output_file
|
||||
@@ fun fmt -> Scalc.To_python.format_program fmt prgm type_ordering
|
||||
|
||||
let () = Driver.Plugin.register_scalc ~name ~extension apply
|
||||
|
@ -20,26 +20,30 @@ module L = Lcalc.Ast
|
||||
module TopLevelName = Uid.Make (Uid.MarkedString) ()
|
||||
module LocalName = Uid.Make (Uid.MarkedString) ()
|
||||
|
||||
let dead_value = LocalName.fresh ("dead_value", Pos.no_pos)
|
||||
let handle_default = TopLevelName.fresh ("handle_default", Pos.no_pos)
|
||||
let handle_default_opt = TopLevelName.fresh ("handle_default_opt", Pos.no_pos)
|
||||
|
||||
type expr =
|
||||
| EVar of LocalName.t
|
||||
| EFunc of TopLevelName.t
|
||||
| EStruct of expr Pos.marked list * D.StructName.t
|
||||
| EStructFieldAccess of expr Pos.marked * D.StructFieldName.t * D.StructName.t
|
||||
| EInj of expr Pos.marked * D.EnumConstructor.t * D.EnumName.t
|
||||
| EArray of expr Pos.marked list
|
||||
| EStruct of expr Marked.pos list * D.StructName.t
|
||||
| EStructFieldAccess of expr Marked.pos * D.StructFieldName.t * D.StructName.t
|
||||
| EInj of expr Marked.pos * D.EnumConstructor.t * D.EnumName.t
|
||||
| EArray of expr Marked.pos list
|
||||
| ELit of L.lit
|
||||
| EApp of expr Pos.marked * expr Pos.marked list
|
||||
| EApp of expr Marked.pos * expr Marked.pos list
|
||||
| EOp of Dcalc.Ast.operator
|
||||
|
||||
type stmt =
|
||||
| SInnerFuncDef of LocalName.t Pos.marked * func
|
||||
| SLocalDecl of LocalName.t Pos.marked * D.typ Pos.marked
|
||||
| SLocalDef of LocalName.t Pos.marked * expr Pos.marked
|
||||
| SInnerFuncDef of LocalName.t Marked.pos * func
|
||||
| SLocalDecl of LocalName.t Marked.pos * D.typ Marked.pos
|
||||
| SLocalDef of LocalName.t Marked.pos * expr Marked.pos
|
||||
| STryExcept of block * L.except * block
|
||||
| SRaise of L.except
|
||||
| SIfThenElse of expr Pos.marked * block * block
|
||||
| SIfThenElse of expr Marked.pos * block * block
|
||||
| SSwitch of
|
||||
expr Pos.marked
|
||||
expr Marked.pos
|
||||
* D.EnumName.t
|
||||
* (block (* Statements corresponding to arm closure body*)
|
||||
* (* Variable instantiated with enum payload *) LocalName.t)
|
||||
@ -47,10 +51,10 @@ type stmt =
|
||||
| SReturn of expr
|
||||
| SAssert of expr
|
||||
|
||||
and block = stmt Pos.marked list
|
||||
and block = stmt Marked.pos list
|
||||
|
||||
and func = {
|
||||
func_params : (LocalName.t Pos.marked * D.typ Pos.marked) list;
|
||||
func_params : (LocalName.t Marked.pos * D.typ Marked.pos) list;
|
||||
func_body : block;
|
||||
}
|
||||
|
||||
|
@ -29,15 +29,15 @@ type ctxt = {
|
||||
|
||||
(* Expressions can spill out side effect, hence this function also returns a
|
||||
list of statements to be prepended before the expression is evaluated *)
|
||||
let rec translate_expr (ctxt : ctxt) (expr : L.expr Pos.marked) :
|
||||
A.block * A.expr Pos.marked =
|
||||
match Pos.unmark expr with
|
||||
let rec translate_expr (ctxt : ctxt) (expr : 'm L.marked_expr) :
|
||||
A.block * A.expr Marked.pos =
|
||||
match Marked.unmark expr with
|
||||
| L.EVar v ->
|
||||
let local_var =
|
||||
try A.EVar (L.VarMap.find (Pos.unmark v) ctxt.var_dict)
|
||||
with Not_found -> A.EFunc (L.VarMap.find (Pos.unmark v) ctxt.func_dict)
|
||||
try A.EVar (L.VarMap.find (L.Var.t v) ctxt.var_dict)
|
||||
with Not_found -> A.EFunc (L.VarMap.find (L.Var.t v) ctxt.func_dict)
|
||||
in
|
||||
[], (local_var, Pos.get_position v)
|
||||
[], (local_var, D.pos expr)
|
||||
| L.ETuple (args, Some s_name) ->
|
||||
let args_stmts, new_args =
|
||||
List.fold_left
|
||||
@ -48,7 +48,7 @@ let rec translate_expr (ctxt : ctxt) (expr : L.expr Pos.marked) :
|
||||
in
|
||||
let new_args = List.rev new_args in
|
||||
let args_stmts = List.rev args_stmts in
|
||||
args_stmts, (A.EStruct (new_args, s_name), Pos.get_position expr)
|
||||
args_stmts, (A.EStruct (new_args, s_name), D.pos expr)
|
||||
| L.ETuple (_, None) ->
|
||||
failwith "Non-struct tuples cannot be compiled to scalc"
|
||||
| L.ETupleAccess (e1, num_field, Some s_name, _) ->
|
||||
@ -57,9 +57,7 @@ let rec translate_expr (ctxt : ctxt) (expr : L.expr Pos.marked) :
|
||||
fst
|
||||
(List.nth (D.StructMap.find s_name ctxt.decl_ctx.ctx_structs) num_field)
|
||||
in
|
||||
( e1_stmts,
|
||||
(A.EStructFieldAccess (new_e1, field_name, s_name), Pos.get_position expr)
|
||||
)
|
||||
e1_stmts, (A.EStructFieldAccess (new_e1, field_name, s_name), D.pos expr)
|
||||
| L.ETupleAccess (_, _, None, _) ->
|
||||
failwith "Non-struct tuples cannot be compiled to scalc"
|
||||
| L.EInj (e1, num_cons, e_name, _) ->
|
||||
@ -67,7 +65,7 @@ let rec translate_expr (ctxt : ctxt) (expr : L.expr Pos.marked) :
|
||||
let cons_name =
|
||||
fst (List.nth (D.EnumMap.find e_name ctxt.decl_ctx.ctx_enums) num_cons)
|
||||
in
|
||||
e1_stmts, (A.EInj (new_e1, cons_name, e_name), Pos.get_position expr)
|
||||
e1_stmts, (A.EInj (new_e1, cons_name, e_name), D.pos expr)
|
||||
| L.EApp (f, args) ->
|
||||
let f_stmts, new_f = translate_expr ctxt f in
|
||||
let args_stmts, new_args =
|
||||
@ -78,7 +76,7 @@ let rec translate_expr (ctxt : ctxt) (expr : L.expr Pos.marked) :
|
||||
([], []) args
|
||||
in
|
||||
let new_args = List.rev new_args in
|
||||
f_stmts @ args_stmts, (A.EApp (new_f, new_args), Pos.get_position expr)
|
||||
f_stmts @ args_stmts, (A.EApp (new_f, new_args), D.pos expr)
|
||||
| L.EArray args ->
|
||||
let args_stmts, new_args =
|
||||
List.fold_left
|
||||
@ -88,9 +86,9 @@ let rec translate_expr (ctxt : ctxt) (expr : L.expr Pos.marked) :
|
||||
([], []) args
|
||||
in
|
||||
let new_args = List.rev new_args in
|
||||
args_stmts, (A.EArray new_args, Pos.get_position expr)
|
||||
| L.EOp op -> [], (A.EOp op, Pos.get_position expr)
|
||||
| L.ELit l -> [], (A.ELit l, Pos.get_position expr)
|
||||
args_stmts, (A.EArray new_args, D.pos expr)
|
||||
| L.EOp op -> [], (A.EOp op, D.pos expr)
|
||||
| L.ELit l -> [], (A.ELit l, D.pos expr)
|
||||
| _ ->
|
||||
let tmp_var =
|
||||
A.LocalName.fresh
|
||||
@ -100,34 +98,33 @@ let rec translate_expr (ctxt : ctxt) (expr : L.expr Pos.marked) :
|
||||
(match ctxt.inside_definition_of with
|
||||
| None -> ctxt.context_name
|
||||
| Some v ->
|
||||
let v = Pos.unmark (A.LocalName.get_info v) in
|
||||
let v = Marked.unmark (A.LocalName.get_info v) in
|
||||
let tmp_rex = Re.Pcre.regexp "^temp_" in
|
||||
if Re.Pcre.pmatch ~rex:tmp_rex v then v else "temp_" ^ v),
|
||||
Pos.get_position expr )
|
||||
D.pos expr )
|
||||
in
|
||||
let ctxt =
|
||||
{
|
||||
ctxt with
|
||||
inside_definition_of = Some tmp_var;
|
||||
context_name = Pos.unmark (A.LocalName.get_info tmp_var);
|
||||
context_name = Marked.unmark (A.LocalName.get_info tmp_var);
|
||||
}
|
||||
in
|
||||
let tmp_stmts = translate_statements ctxt expr in
|
||||
( ( A.SLocalDecl
|
||||
((tmp_var, Pos.get_position expr), (D.TAny, Pos.get_position expr)),
|
||||
Pos.get_position expr )
|
||||
( (A.SLocalDecl ((tmp_var, D.pos expr), (D.TAny, D.pos expr)), D.pos expr)
|
||||
:: tmp_stmts,
|
||||
(A.EVar tmp_var, Pos.get_position expr) )
|
||||
(A.EVar tmp_var, D.pos expr) )
|
||||
|
||||
and translate_statements (ctxt : ctxt) (block_expr : L.expr Pos.marked) :
|
||||
A.block =
|
||||
match Pos.unmark block_expr with
|
||||
and translate_statements (ctxt : ctxt) (block_expr : 'm L.marked_expr) : A.block
|
||||
=
|
||||
match Marked.unmark block_expr with
|
||||
| L.EAssert e ->
|
||||
(* Assertions are always encapsulated in a unit-typed let binding *)
|
||||
let e_stmts, new_e = translate_expr ctxt e in
|
||||
e_stmts @ [A.SAssert (Pos.unmark new_e), Pos.get_position block_expr]
|
||||
| L.EApp ((L.EAbs ((binder, binder_pos), taus), eabs_pos), args) ->
|
||||
e_stmts @ [A.SAssert (Marked.unmark new_e), D.pos block_expr]
|
||||
| L.EApp ((L.EAbs (binder, taus), binder_mark), args) ->
|
||||
(* This defines multiple local variables at the time *)
|
||||
let binder_pos = D.mark_pos binder_mark in
|
||||
let vars, body = Bindlib.unmbind binder in
|
||||
let vars_tau = List.map2 (fun x tau -> x, tau) (Array.to_list vars) taus in
|
||||
let ctxt =
|
||||
@ -136,7 +133,7 @@ and translate_statements (ctxt : ctxt) (block_expr : L.expr Pos.marked) :
|
||||
var_dict =
|
||||
List.fold_left
|
||||
(fun var_dict (x, _) ->
|
||||
L.VarMap.add x
|
||||
L.VarMap.add (L.Var.t x)
|
||||
(A.LocalName.fresh (Bindlib.name_of x, binder_pos))
|
||||
var_dict)
|
||||
ctxt.var_dict vars_tau;
|
||||
@ -145,14 +142,15 @@ and translate_statements (ctxt : ctxt) (block_expr : L.expr Pos.marked) :
|
||||
let local_decls =
|
||||
List.map
|
||||
(fun (x, tau) ->
|
||||
( A.SLocalDecl ((L.VarMap.find x ctxt.var_dict, binder_pos), tau),
|
||||
eabs_pos ))
|
||||
( A.SLocalDecl
|
||||
((L.VarMap.find (L.Var.t x) ctxt.var_dict, binder_pos), tau),
|
||||
binder_pos ))
|
||||
vars_tau
|
||||
in
|
||||
let vars_args =
|
||||
List.map2
|
||||
(fun (x, tau) arg ->
|
||||
(L.VarMap.find x ctxt.var_dict, binder_pos), tau, arg)
|
||||
(L.VarMap.find (L.Var.t x) ctxt.var_dict, binder_pos), tau, arg)
|
||||
vars_tau args
|
||||
in
|
||||
let def_blocks =
|
||||
@ -161,8 +159,9 @@ and translate_statements (ctxt : ctxt) (block_expr : L.expr Pos.marked) :
|
||||
let ctxt =
|
||||
{
|
||||
ctxt with
|
||||
inside_definition_of = Some (Pos.unmark x);
|
||||
context_name = Pos.unmark (A.LocalName.get_info (Pos.unmark x));
|
||||
inside_definition_of = Some (Marked.unmark x);
|
||||
context_name =
|
||||
Marked.unmark (A.LocalName.get_info (Marked.unmark x));
|
||||
}
|
||||
in
|
||||
let arg_stmts, new_arg = translate_expr ctxt arg in
|
||||
@ -171,13 +170,13 @@ and translate_statements (ctxt : ctxt) (block_expr : L.expr Pos.marked) :
|
||||
in
|
||||
let rest_of_block = translate_statements ctxt body in
|
||||
local_decls @ List.flatten def_blocks @ rest_of_block
|
||||
| L.EAbs ((binder, binder_pos), taus) ->
|
||||
| L.EAbs (binder, taus) ->
|
||||
let vars, body = Bindlib.unmbind binder in
|
||||
let binder_pos = D.pos block_expr in
|
||||
let vars_tau = List.map2 (fun x tau -> x, tau) (Array.to_list vars) taus in
|
||||
let closure_name =
|
||||
match ctxt.inside_definition_of with
|
||||
| None ->
|
||||
A.LocalName.fresh (ctxt.context_name, Pos.get_position block_expr)
|
||||
| None -> A.LocalName.fresh (ctxt.context_name, D.pos block_expr)
|
||||
| Some x -> x
|
||||
in
|
||||
let ctxt =
|
||||
@ -186,7 +185,7 @@ and translate_statements (ctxt : ctxt) (block_expr : L.expr Pos.marked) :
|
||||
var_dict =
|
||||
List.fold_left
|
||||
(fun var_dict (x, _) ->
|
||||
L.VarMap.add x
|
||||
L.VarMap.add (L.Var.t x)
|
||||
(A.LocalName.fresh (Bindlib.name_of x, binder_pos))
|
||||
var_dict)
|
||||
ctxt.var_dict vars_tau;
|
||||
@ -201,7 +200,7 @@ and translate_statements (ctxt : ctxt) (block_expr : L.expr Pos.marked) :
|
||||
func_params =
|
||||
List.map
|
||||
(fun (var, tau) ->
|
||||
(L.VarMap.find var ctxt.var_dict, binder_pos), tau)
|
||||
(L.VarMap.find (L.Var.t var) ctxt.var_dict, binder_pos), tau)
|
||||
vars_tau;
|
||||
func_body = new_body;
|
||||
} ),
|
||||
@ -212,16 +211,19 @@ and translate_statements (ctxt : ctxt) (block_expr : L.expr Pos.marked) :
|
||||
let new_args =
|
||||
List.fold_left
|
||||
(fun new_args arg ->
|
||||
match Pos.unmark arg with
|
||||
| L.EAbs ((binder, pos_binder), _) ->
|
||||
match Marked.unmark arg with
|
||||
| L.EAbs (binder, _) ->
|
||||
let vars, body = Bindlib.unmbind binder in
|
||||
assert (Array.length vars = 1);
|
||||
let var = vars.(0) in
|
||||
let scalc_var =
|
||||
A.LocalName.fresh (Bindlib.name_of var, pos_binder)
|
||||
A.LocalName.fresh (Bindlib.name_of var, D.pos arg)
|
||||
in
|
||||
let ctxt =
|
||||
{ ctxt with var_dict = L.VarMap.add var scalc_var ctxt.var_dict }
|
||||
{
|
||||
ctxt with
|
||||
var_dict = L.VarMap.add (L.Var.t var) scalc_var ctxt.var_dict;
|
||||
}
|
||||
in
|
||||
let new_arg = translate_statements ctxt body in
|
||||
(new_arg, scalc_var) :: new_args
|
||||
@ -230,19 +232,28 @@ and translate_statements (ctxt : ctxt) (block_expr : L.expr Pos.marked) :
|
||||
[] args
|
||||
in
|
||||
let new_args = List.rev new_args in
|
||||
e1_stmts
|
||||
@ [A.SSwitch (new_e1, e_name, new_args), Pos.get_position block_expr]
|
||||
e1_stmts @ [A.SSwitch (new_e1, e_name, new_args), D.pos block_expr]
|
||||
| L.EIfThenElse (cond, e_true, e_false) ->
|
||||
let cond_stmts, s_cond = translate_expr ctxt cond in
|
||||
let s_e_true = translate_statements ctxt e_true in
|
||||
let s_e_false = translate_statements ctxt e_false in
|
||||
cond_stmts
|
||||
@ [A.SIfThenElse (s_cond, s_e_true, s_e_false), Pos.get_position block_expr]
|
||||
cond_stmts @ [A.SIfThenElse (s_cond, s_e_true, s_e_false), D.pos block_expr]
|
||||
| L.ECatch (e_try, except, e_catch) ->
|
||||
let s_e_try = translate_statements ctxt e_try in
|
||||
let s_e_catch = translate_statements ctxt e_catch in
|
||||
[A.STryExcept (s_e_try, except, s_e_catch), Pos.get_position block_expr]
|
||||
| L.ERaise except -> [A.SRaise except, Pos.get_position block_expr]
|
||||
[A.STryExcept (s_e_try, except, s_e_catch), D.pos block_expr]
|
||||
| L.ERaise except ->
|
||||
(* Before raising the exception, we still give a dummy definition to the
|
||||
current variable so that tools like mypy don't complain. *)
|
||||
(match ctxt.inside_definition_of with
|
||||
| None -> []
|
||||
| Some x ->
|
||||
[
|
||||
( A.SLocalDef
|
||||
((x, D.pos block_expr), (Ast.EVar Ast.dead_value, D.pos block_expr)),
|
||||
D.pos block_expr );
|
||||
])
|
||||
@ [A.SRaise except, D.pos block_expr]
|
||||
| _ -> (
|
||||
let e_stmts, new_e = translate_expr ctxt block_expr in
|
||||
e_stmts
|
||||
@ -256,9 +267,9 @@ and translate_statements (ctxt : ctxt) (block_expr : L.expr Pos.marked) :
|
||||
| _ ->
|
||||
[
|
||||
( (match ctxt.inside_definition_of with
|
||||
| None -> A.SReturn (Pos.unmark new_e)
|
||||
| Some x -> A.SLocalDef (Pos.same_pos_as x new_e, new_e)),
|
||||
Pos.get_position block_expr );
|
||||
| None -> A.SReturn (Marked.unmark new_e)
|
||||
| Some x -> A.SLocalDef (Marked.same_mark_as x new_e, new_e)),
|
||||
D.pos block_expr );
|
||||
])
|
||||
|
||||
let rec translate_scope_body_expr
|
||||
@ -266,7 +277,7 @@ let rec translate_scope_body_expr
|
||||
(decl_ctx : D.decl_ctx)
|
||||
(var_dict : A.LocalName.t L.VarMap.t)
|
||||
(func_dict : A.TopLevelName.t L.VarMap.t)
|
||||
(scope_expr : L.expr D.scope_body_expr) : A.block =
|
||||
(scope_expr : ('m L.expr, 'm) D.scope_body_expr) : A.block =
|
||||
match scope_expr with
|
||||
| Result e ->
|
||||
let block, new_e =
|
||||
@ -276,17 +287,17 @@ let rec translate_scope_body_expr
|
||||
func_dict;
|
||||
var_dict;
|
||||
inside_definition_of = None;
|
||||
context_name = Pos.unmark (D.ScopeName.get_info scope_name);
|
||||
context_name = Marked.unmark (D.ScopeName.get_info scope_name);
|
||||
}
|
||||
e
|
||||
in
|
||||
block @ [A.SReturn (Pos.unmark new_e), Pos.get_position new_e]
|
||||
block @ [A.SReturn (Marked.unmark new_e), Marked.get_mark new_e]
|
||||
| ScopeLet scope_let ->
|
||||
let let_var, scope_let_next = Bindlib.unbind scope_let.scope_let_next in
|
||||
let let_var_id =
|
||||
A.LocalName.fresh (Bindlib.name_of let_var, scope_let.scope_let_pos)
|
||||
in
|
||||
let new_var_dict = L.VarMap.add let_var let_var_id var_dict in
|
||||
let new_var_dict = L.VarMap.add (L.Var.t let_var) let_var_id var_dict in
|
||||
(match scope_let.scope_let_kind with
|
||||
| D.Assertion ->
|
||||
translate_statements
|
||||
@ -295,7 +306,7 @@ let rec translate_scope_body_expr
|
||||
func_dict;
|
||||
var_dict;
|
||||
inside_definition_of = Some let_var_id;
|
||||
context_name = Pos.unmark (D.ScopeName.get_info scope_name);
|
||||
context_name = Marked.unmark (D.ScopeName.get_info scope_name);
|
||||
}
|
||||
scope_let.scope_let_expr
|
||||
| _ ->
|
||||
@ -306,7 +317,7 @@ let rec translate_scope_body_expr
|
||||
func_dict;
|
||||
var_dict;
|
||||
inside_definition_of = Some let_var_id;
|
||||
context_name = Pos.unmark (D.ScopeName.get_info scope_name);
|
||||
context_name = Marked.unmark (D.ScopeName.get_info scope_name);
|
||||
}
|
||||
scope_let.scope_let_expr
|
||||
in
|
||||
@ -321,9 +332,9 @@ let rec translate_scope_body_expr
|
||||
@ translate_scope_body_expr scope_name decl_ctx new_var_dict func_dict
|
||||
scope_let_next
|
||||
|
||||
let translate_program (p : L.program) : A.program =
|
||||
let translate_program (p : 'm L.program) : A.program =
|
||||
{
|
||||
decl_ctx = p.L.decl_ctx;
|
||||
decl_ctx = p.D.decl_ctx;
|
||||
scopes =
|
||||
(let _, new_scopes =
|
||||
D.fold_left_scope_defs
|
||||
@ -332,13 +343,13 @@ let translate_program (p : L.program) : A.program =
|
||||
Bindlib.unbind scope_def.scope_body.scope_body_expr
|
||||
in
|
||||
let input_pos =
|
||||
Pos.get_position (D.ScopeName.get_info scope_def.scope_name)
|
||||
Marked.get_mark (D.ScopeName.get_info scope_def.scope_name)
|
||||
in
|
||||
let scope_input_var_id =
|
||||
A.LocalName.fresh (Bindlib.name_of scope_input_var, input_pos)
|
||||
in
|
||||
let var_dict =
|
||||
L.VarMap.singleton scope_input_var scope_input_var_id
|
||||
L.VarMap.singleton (L.Var.t scope_input_var) scope_input_var_id
|
||||
in
|
||||
let new_scope_body =
|
||||
translate_scope_body_expr scope_def.D.scope_name p.decl_ctx
|
||||
@ -347,7 +358,9 @@ let translate_program (p : L.program) : A.program =
|
||||
let func_id =
|
||||
A.TopLevelName.fresh (Bindlib.name_of scope_var, Pos.no_pos)
|
||||
in
|
||||
let func_dict = L.VarMap.add scope_var func_id func_dict in
|
||||
let func_dict =
|
||||
L.VarMap.add (L.Var.t scope_var) func_id func_dict
|
||||
in
|
||||
( func_dict,
|
||||
{
|
||||
Ast.scope_body_name = scope_def.D.scope_name;
|
||||
@ -362,7 +375,7 @@ let translate_program (p : L.program) : A.program =
|
||||
(D.StructMap.find
|
||||
scope_def.D.scope_body
|
||||
.D.scope_body_input_struct
|
||||
p.L.decl_ctx.ctx_structs),
|
||||
p.D.decl_ctx.ctx_structs),
|
||||
Some
|
||||
scope_def.D.scope_body
|
||||
.D.scope_body_input_struct ),
|
||||
@ -374,13 +387,10 @@ let translate_program (p : L.program) : A.program =
|
||||
:: new_scopes ))
|
||||
~init:
|
||||
( (if !Cli.avoid_exceptions_flag then
|
||||
L.VarMap.singleton L.handle_default_opt
|
||||
(A.TopLevelName.fresh ("handle_default_opt", Pos.no_pos))
|
||||
else
|
||||
L.VarMap.singleton L.handle_default
|
||||
(A.TopLevelName.fresh ("handle_default", Pos.no_pos))),
|
||||
L.VarMap.singleton L.handle_default_opt A.handle_default_opt
|
||||
else L.VarMap.singleton L.handle_default A.handle_default),
|
||||
[] )
|
||||
p.L.scopes
|
||||
p.D.scopes
|
||||
in
|
||||
List.rev new_scopes);
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
(library
|
||||
(name scalc)
|
||||
(public_name catala.scalc)
|
||||
(libraries bindlib lcalc runtime))
|
||||
(libraries bindlib lcalc catala.runtime_ocaml))
|
||||
|
||||
(documentation
|
||||
(package catala)
|
||||
|
@ -17,7 +17,7 @@
|
||||
open Utils
|
||||
open Ast
|
||||
|
||||
let needs_parens (_e : expr Pos.marked) : bool = false
|
||||
let needs_parens (_e : expr Marked.pos) : bool = false
|
||||
|
||||
let format_local_name (fmt : Format.formatter) (v : LocalName.t) : unit =
|
||||
Format.fprintf fmt "%a_%s" LocalName.format_t v
|
||||
@ -27,15 +27,15 @@ let rec format_expr
|
||||
(decl_ctx : Dcalc.Ast.decl_ctx)
|
||||
?(debug : bool = false)
|
||||
(fmt : Format.formatter)
|
||||
(e : expr Pos.marked) : unit =
|
||||
(e : expr Marked.pos) : unit =
|
||||
let format_expr = format_expr decl_ctx ~debug in
|
||||
let format_with_parens (fmt : Format.formatter) (e : expr Pos.marked) =
|
||||
let format_with_parens (fmt : Format.formatter) (e : expr Marked.pos) =
|
||||
if needs_parens e then
|
||||
Format.fprintf fmt "%a%a%a" Dcalc.Print.format_punctuation "(" format_expr
|
||||
e Dcalc.Print.format_punctuation ")"
|
||||
else Format.fprintf fmt "%a" format_expr e
|
||||
in
|
||||
match Pos.unmark e with
|
||||
match Marked.unmark e with
|
||||
| EVar v -> Format.fprintf fmt "%a" format_local_name v
|
||||
| EFunc v -> Format.fprintf fmt "%a" TopLevelName.format_t v
|
||||
| EStruct (es, s) ->
|
||||
@ -75,62 +75,59 @@ let rec format_expr
|
||||
(Dcalc.Ast.EnumMap.find enum decl_ctx.ctx_enums)))
|
||||
format_expr e
|
||||
| ELit l ->
|
||||
Format.fprintf fmt "%a" Lcalc.Print.format_lit (Pos.same_pos_as l e)
|
||||
Format.fprintf fmt "%a" Lcalc.Print.format_lit (Marked.same_mark_as l e)
|
||||
| EApp
|
||||
((EOp (Binop ((Dcalc.Ast.Map | Dcalc.Ast.Filter) as op)), _), [arg1; arg2])
|
||||
->
|
||||
Format.fprintf fmt "@[<hov 2>%a@ %a@ %a@]" Dcalc.Print.format_binop
|
||||
(op, Pos.no_pos) format_with_parens arg1 format_with_parens arg2
|
||||
Format.fprintf fmt "@[<hov 2>%a@ %a@ %a@]" Dcalc.Print.format_binop op
|
||||
format_with_parens arg1 format_with_parens arg2
|
||||
| EApp ((EOp (Binop op), _), [arg1; arg2]) ->
|
||||
Format.fprintf fmt "@[<hov 2>%a@ %a@ %a@]" format_with_parens arg1
|
||||
Dcalc.Print.format_binop (op, Pos.no_pos) format_with_parens arg2
|
||||
Dcalc.Print.format_binop op format_with_parens arg2
|
||||
| EApp ((EOp (Unop (Log _)), _), [arg1]) when not debug ->
|
||||
Format.fprintf fmt "%a" format_with_parens arg1
|
||||
| EApp ((EOp (Unop op), _), [arg1]) ->
|
||||
Format.fprintf fmt "@[<hov 2>%a@ %a@]" Dcalc.Print.format_unop
|
||||
(op, Pos.no_pos) format_with_parens arg1
|
||||
Format.fprintf fmt "@[<hov 2>%a@ %a@]" Dcalc.Print.format_unop op
|
||||
format_with_parens arg1
|
||||
| EApp (f, args) ->
|
||||
Format.fprintf fmt "@[<hov 2>%a@ %a@]" format_expr f
|
||||
(Format.pp_print_list
|
||||
~pp_sep:(fun fmt () -> Format.fprintf fmt "@ ")
|
||||
format_with_parens)
|
||||
args
|
||||
| EOp (Ternop op) ->
|
||||
Format.fprintf fmt "%a" Dcalc.Print.format_ternop (op, Pos.no_pos)
|
||||
| EOp (Binop op) ->
|
||||
Format.fprintf fmt "%a" Dcalc.Print.format_binop (op, Pos.no_pos)
|
||||
| EOp (Unop op) ->
|
||||
Format.fprintf fmt "%a" Dcalc.Print.format_unop (op, Pos.no_pos)
|
||||
| EOp (Ternop op) -> Format.fprintf fmt "%a" Dcalc.Print.format_ternop op
|
||||
| EOp (Binop op) -> Format.fprintf fmt "%a" Dcalc.Print.format_binop op
|
||||
| EOp (Unop op) -> Format.fprintf fmt "%a" Dcalc.Print.format_unop op
|
||||
|
||||
let rec format_statement
|
||||
(decl_ctx : Dcalc.Ast.decl_ctx)
|
||||
?(debug : bool = false)
|
||||
(fmt : Format.formatter)
|
||||
(stmt : stmt Pos.marked) : unit =
|
||||
(stmt : stmt Marked.pos) : unit =
|
||||
if debug then () else ();
|
||||
match Pos.unmark stmt with
|
||||
match Marked.unmark stmt with
|
||||
| SInnerFuncDef (name, func) ->
|
||||
Format.fprintf fmt "@[<hov 2>%a@ %a@ %a@ %a@]@\n@[<v 2> %a@]"
|
||||
Dcalc.Print.format_keyword "let" LocalName.format_t (Pos.unmark name)
|
||||
Dcalc.Print.format_keyword "let" LocalName.format_t (Marked.unmark name)
|
||||
(Format.pp_print_list
|
||||
~pp_sep:(fun fmt () -> Format.fprintf fmt "@ ")
|
||||
(fun fmt ((name, _), typ) ->
|
||||
Format.fprintf fmt "%a%a %a@ %a%a" Dcalc.Print.format_punctuation "("
|
||||
LocalName.format_t name Dcalc.Print.format_punctuation ":"
|
||||
(Dcalc.Print.format_typ decl_ctx)
|
||||
typ Dcalc.Print.format_punctuation ")"))
|
||||
(Marked.unmark typ) Dcalc.Print.format_punctuation ")"))
|
||||
func.func_params Dcalc.Print.format_punctuation "="
|
||||
(format_block decl_ctx ~debug)
|
||||
func.func_body
|
||||
| SLocalDecl (name, typ) ->
|
||||
Format.fprintf fmt "@[<hov 2>%a %a %a@ %a@]" Dcalc.Print.format_keyword
|
||||
"decl" LocalName.format_t (Pos.unmark name) Dcalc.Print.format_punctuation
|
||||
":"
|
||||
"decl" LocalName.format_t (Marked.unmark name)
|
||||
Dcalc.Print.format_punctuation ":"
|
||||
(Dcalc.Print.format_typ decl_ctx)
|
||||
typ
|
||||
(Marked.unmark typ)
|
||||
| SLocalDef (name, expr) ->
|
||||
Format.fprintf fmt "@[<hov 2>%a %a@ %a@]" LocalName.format_t
|
||||
(Pos.unmark name) Dcalc.Print.format_punctuation "="
|
||||
(Marked.unmark name) Dcalc.Print.format_punctuation "="
|
||||
(format_expr decl_ctx ~debug)
|
||||
expr
|
||||
| STryExcept (b_try, except, b_with) ->
|
||||
@ -157,11 +154,11 @@ let rec format_statement
|
||||
| SReturn ret ->
|
||||
Format.fprintf fmt "@[<hov 2>%a %a@]" Dcalc.Print.format_keyword "return"
|
||||
(format_expr decl_ctx ~debug)
|
||||
(ret, Pos.get_position stmt)
|
||||
(ret, Marked.get_mark stmt)
|
||||
| SAssert expr ->
|
||||
Format.fprintf fmt "@[<hov 2>%a %a@]" Dcalc.Print.format_keyword "assert"
|
||||
(format_expr decl_ctx ~debug)
|
||||
(expr, Pos.get_position stmt)
|
||||
(expr, Marked.get_mark stmt)
|
||||
| SSwitch (e_switch, enum, arms) ->
|
||||
Format.fprintf fmt "@[<v 0>%a @[<hov 2>%a@]%a@]%a"
|
||||
Dcalc.Print.format_keyword "switch"
|
||||
@ -204,7 +201,7 @@ let format_scope
|
||||
Format.fprintf fmt "%a%a %a@ %a%a" Dcalc.Print.format_punctuation "("
|
||||
LocalName.format_t name Dcalc.Print.format_punctuation ":"
|
||||
(Dcalc.Print.format_typ decl_ctx)
|
||||
typ Dcalc.Print.format_punctuation ")"))
|
||||
(Marked.unmark typ) Dcalc.Print.format_punctuation ")"))
|
||||
body.scope_body_func.func_params Dcalc.Print.format_punctuation "="
|
||||
(format_block decl_ctx ~debug)
|
||||
body.scope_body_func.func_body
|
||||
|
@ -17,12 +17,13 @@
|
||||
|
||||
open Utils
|
||||
open Ast
|
||||
open Lcalc.Backends
|
||||
open String_common
|
||||
module Runtime = Runtime_ocaml.Runtime
|
||||
module D = Dcalc.Ast
|
||||
module L = Lcalc.Ast
|
||||
|
||||
let format_lit (fmt : Format.formatter) (l : L.lit Pos.marked) : unit =
|
||||
match Pos.unmark l with
|
||||
let format_lit (fmt : Format.formatter) (l : L.lit Marked.pos) : unit =
|
||||
match Marked.unmark l with
|
||||
| LBool true -> Format.fprintf fmt "True"
|
||||
| LBool false -> Format.fprintf fmt "False"
|
||||
| LInt i ->
|
||||
@ -30,7 +31,7 @@ let format_lit (fmt : Format.formatter) (l : L.lit Pos.marked) : unit =
|
||||
| LUnit -> Format.fprintf fmt "Unit()"
|
||||
| LRat i ->
|
||||
Format.fprintf fmt "decimal_of_string(\"%a\")" Dcalc.Print.format_lit
|
||||
(Pos.same_pos_as (Dcalc.Ast.LRat i) l)
|
||||
(Dcalc.Ast.LRat i)
|
||||
| LMoney e ->
|
||||
Format.fprintf fmt "money_of_cents_string(\"%s\")"
|
||||
(Runtime.integer_to_string (Runtime.money_to_cents e))
|
||||
@ -51,9 +52,9 @@ let format_log_entry (fmt : Format.formatter) (entry : Dcalc.Ast.log_entry) :
|
||||
| EndCall -> Format.fprintf fmt "%s" "← "
|
||||
| PosRecordIfTrueBool -> Format.fprintf fmt "☛ "
|
||||
|
||||
let format_binop (fmt : Format.formatter) (op : Dcalc.Ast.binop Pos.marked) :
|
||||
let format_binop (fmt : Format.formatter) (op : Dcalc.Ast.binop Marked.pos) :
|
||||
unit =
|
||||
match Pos.unmark op with
|
||||
match Marked.unmark op with
|
||||
| Add _ | Concat -> Format.fprintf fmt "+"
|
||||
| Sub _ -> Format.fprintf fmt "-"
|
||||
| Mult _ -> Format.fprintf fmt "*"
|
||||
@ -70,9 +71,9 @@ let format_binop (fmt : Format.formatter) (op : Dcalc.Ast.binop Pos.marked) :
|
||||
| Map -> Format.fprintf fmt "list_map"
|
||||
| Filter -> Format.fprintf fmt "list_filter"
|
||||
|
||||
let format_ternop (fmt : Format.formatter) (op : Dcalc.Ast.ternop Pos.marked) :
|
||||
let format_ternop (fmt : Format.formatter) (op : Dcalc.Ast.ternop Marked.pos) :
|
||||
unit =
|
||||
match Pos.unmark op with Fold -> Format.fprintf fmt "list_fold_left"
|
||||
match Marked.unmark op with Fold -> Format.fprintf fmt "list_fold_left"
|
||||
|
||||
let format_uid_list (fmt : Format.formatter) (uids : Uid.MarkedString.info list)
|
||||
: unit =
|
||||
@ -84,23 +85,30 @@ let format_uid_list (fmt : Format.formatter) (uids : Uid.MarkedString.info list)
|
||||
uids
|
||||
|
||||
let format_string_list (fmt : Format.formatter) (uids : string list) : unit =
|
||||
let sanitize_quotes = Re.compile (Re.char '"') in
|
||||
Format.fprintf fmt "[%a]"
|
||||
(Format.pp_print_list
|
||||
~pp_sep:(fun fmt () -> Format.fprintf fmt ",@ ")
|
||||
(fun fmt info -> Format.fprintf fmt "\"%s\"" info))
|
||||
(fun fmt info ->
|
||||
Format.fprintf fmt "\"%s\""
|
||||
(Re.replace sanitize_quotes ~f:(fun _ -> "\\\"") info)))
|
||||
uids
|
||||
|
||||
let format_unop (fmt : Format.formatter) (op : Dcalc.Ast.unop Pos.marked) : unit
|
||||
let format_unop (fmt : Format.formatter) (op : Dcalc.Ast.unop Marked.pos) : unit
|
||||
=
|
||||
match Pos.unmark op with
|
||||
match Marked.unmark op with
|
||||
| Minus _ -> Format.fprintf fmt "-"
|
||||
| Not -> Format.fprintf fmt "not"
|
||||
| Log (entry, infos) -> assert false (* should not happen *)
|
||||
| Length -> Format.fprintf fmt "%s" "list_length"
|
||||
| IntToRat -> Format.fprintf fmt "%s" "decimal_of_integer"
|
||||
| MoneyToRat -> Format.fprintf fmt "%s" "decimal_of_money"
|
||||
| RatToMoney -> Format.fprintf fmt "%s" "money_of_decimal"
|
||||
| GetDay -> Format.fprintf fmt "%s" "day_of_month_of_date"
|
||||
| GetMonth -> Format.fprintf fmt "%s" "month_number_of_date"
|
||||
| GetYear -> Format.fprintf fmt "%s" "year_of_date"
|
||||
| FirstDayOfMonth -> Format.fprintf fmt "%s" "first_day_of_month"
|
||||
| LastDayOfMonth -> Format.fprintf fmt "%s" "last_day_of_month"
|
||||
| RoundMoney -> Format.fprintf fmt "%s" "money_round"
|
||||
| RoundDecimal -> Format.fprintf fmt "%s" "decimal_round"
|
||||
|
||||
@ -123,7 +131,7 @@ let format_struct_name (fmt : Format.formatter) (v : Dcalc.Ast.StructName.t) :
|
||||
unit =
|
||||
Format.fprintf fmt "%s"
|
||||
(avoid_keywords
|
||||
(to_uppercase
|
||||
(to_camel_case
|
||||
(to_ascii (Format.asprintf "%a" Dcalc.Ast.StructName.format_t v))))
|
||||
|
||||
let format_struct_field_name
|
||||
@ -137,7 +145,7 @@ let format_enum_name (fmt : Format.formatter) (v : Dcalc.Ast.EnumName.t) : unit
|
||||
=
|
||||
Format.fprintf fmt "%s"
|
||||
(avoid_keywords
|
||||
(to_uppercase
|
||||
(to_camel_case
|
||||
(to_ascii (Format.asprintf "%a" Dcalc.Ast.EnumName.format_t v))))
|
||||
|
||||
let format_enum_cons_name
|
||||
@ -147,19 +155,19 @@ let format_enum_cons_name
|
||||
(avoid_keywords
|
||||
(to_ascii (Format.asprintf "%a" Dcalc.Ast.EnumConstructor.format_t v)))
|
||||
|
||||
let typ_needs_parens (e : Dcalc.Ast.typ Pos.marked) : bool =
|
||||
match Pos.unmark e with TArrow _ | TArray _ -> true | _ -> false
|
||||
let typ_needs_parens (e : Dcalc.Ast.typ Marked.pos) : bool =
|
||||
match Marked.unmark e with TArrow _ | TArray _ -> true | _ -> false
|
||||
|
||||
let rec format_typ (fmt : Format.formatter) (typ : Dcalc.Ast.typ Pos.marked) :
|
||||
let rec format_typ (fmt : Format.formatter) (typ : Dcalc.Ast.typ Marked.pos) :
|
||||
unit =
|
||||
let format_typ = format_typ in
|
||||
let format_typ_with_parens
|
||||
(fmt : Format.formatter)
|
||||
(t : Dcalc.Ast.typ Pos.marked) =
|
||||
(t : Dcalc.Ast.typ Marked.pos) =
|
||||
if typ_needs_parens t then Format.fprintf fmt "(%a)" format_typ t
|
||||
else Format.fprintf fmt "%a" format_typ t
|
||||
in
|
||||
match Pos.unmark typ with
|
||||
match Marked.unmark typ with
|
||||
| TLit TUnit -> Format.fprintf fmt "Unit"
|
||||
| TLit TMoney -> Format.fprintf fmt "Money"
|
||||
| TLit TInt -> Format.fprintf fmt "Integer"
|
||||
@ -185,14 +193,13 @@ let rec format_typ (fmt : Format.formatter) (typ : Dcalc.Ast.typ Pos.marked) :
|
||||
| TAny -> Format.fprintf fmt "Any"
|
||||
|
||||
let format_name_cleaned (fmt : Format.formatter) (s : string) : unit =
|
||||
let lowercase_name = to_lowercase (to_ascii s) in
|
||||
let lowercase_name =
|
||||
Re.Pcre.substitute ~rex:(Re.Pcre.regexp "\\.")
|
||||
~subst:(fun _ -> "_dot_")
|
||||
lowercase_name
|
||||
in
|
||||
let lowercase_name = avoid_keywords (to_ascii lowercase_name) in
|
||||
Format.fprintf fmt "%s" lowercase_name
|
||||
s
|
||||
|> to_ascii
|
||||
|> to_snake_case
|
||||
|> Re.Pcre.substitute ~rex:(Re.Pcre.regexp "\\.") ~subst:(fun _ -> "_dot_")
|
||||
|> to_ascii
|
||||
|> avoid_keywords
|
||||
|> Format.fprintf fmt "%s"
|
||||
|
||||
module StringMap = Map.Make (String)
|
||||
module IntMap = Map.Make (Int)
|
||||
@ -205,7 +212,7 @@ module IntMap = Map.Make (Int)
|
||||
let string_counter_map : int IntMap.t StringMap.t ref = ref StringMap.empty
|
||||
|
||||
let format_var (fmt : Format.formatter) (v : LocalName.t) : unit =
|
||||
let v_str = Pos.unmark (LocalName.get_info v) in
|
||||
let v_str = Marked.unmark (LocalName.get_info v) in
|
||||
let hash = LocalName.hash v in
|
||||
let local_id =
|
||||
match StringMap.find_opt v_str !string_counter_map with
|
||||
@ -236,22 +243,29 @@ let format_var (fmt : Format.formatter) (v : LocalName.t) : unit =
|
||||
else Format.fprintf fmt "%a_%d" format_name_cleaned v_str local_id
|
||||
|
||||
let format_toplevel_name (fmt : Format.formatter) (v : TopLevelName.t) : unit =
|
||||
let v_str = Pos.unmark (TopLevelName.get_info v) in
|
||||
let v_str = Marked.unmark (TopLevelName.get_info v) in
|
||||
format_name_cleaned fmt v_str
|
||||
|
||||
let needs_parens (e : expr Pos.marked) : bool =
|
||||
match Pos.unmark e with
|
||||
let needs_parens (e : expr Marked.pos) : bool =
|
||||
match Marked.unmark e with
|
||||
| ELit (LBool _ | LUnit) | EVar _ | EOp _ -> false
|
||||
| _ -> true
|
||||
|
||||
let format_exception (fmt : Format.formatter) (exc : L.except Pos.marked) : unit
|
||||
let format_exception (fmt : Format.formatter) (exc : L.except Marked.pos) : unit
|
||||
=
|
||||
match Pos.unmark exc with
|
||||
| ConflictError -> Format.fprintf fmt "ConflictError"
|
||||
let pos = Marked.get_mark exc in
|
||||
match Marked.unmark exc with
|
||||
| ConflictError ->
|
||||
Format.fprintf fmt
|
||||
"ConflictError(@[<hov 0>SourcePosition(@[<hov 0>filename=\"%s\",@ \
|
||||
start_line=%d,@ start_column=%d,@ end_line=%d,@ end_column=%d,@ \
|
||||
law_headings=%a)@])@]"
|
||||
(Pos.get_file pos) (Pos.get_start_line pos) (Pos.get_start_column pos)
|
||||
(Pos.get_end_line pos) (Pos.get_end_column pos) format_string_list
|
||||
(Pos.get_law_info pos)
|
||||
| EmptyError -> Format.fprintf fmt "EmptyError"
|
||||
| Crash -> Format.fprintf fmt "Crash"
|
||||
| NoValueProvided ->
|
||||
let pos = Pos.get_position exc in
|
||||
Format.fprintf fmt
|
||||
"NoValueProvided(@[<hov 0>SourcePosition(@[<hov 0>filename=\"%s\",@ \
|
||||
start_line=%d,@ start_column=%d,@ end_line=%d,@ end_column=%d,@ \
|
||||
@ -263,8 +277,8 @@ let format_exception (fmt : Format.formatter) (exc : L.except Pos.marked) : unit
|
||||
let rec format_expression
|
||||
(ctx : Dcalc.Ast.decl_ctx)
|
||||
(fmt : Format.formatter)
|
||||
(e : expr Pos.marked) : unit =
|
||||
match Pos.unmark e with
|
||||
(e : expr Marked.pos) : unit =
|
||||
match Marked.unmark e with
|
||||
| EVar v -> format_var fmt v
|
||||
| EFunc f -> format_toplevel_name fmt f
|
||||
| EStruct (es, s) ->
|
||||
@ -299,7 +313,7 @@ let rec format_expression
|
||||
~pp_sep:(fun fmt () -> Format.fprintf fmt ",@ ")
|
||||
(fun fmt e -> Format.fprintf fmt "%a" (format_expression ctx) e))
|
||||
es
|
||||
| ELit l -> Format.fprintf fmt "%a" format_lit (Pos.same_pos_as l e)
|
||||
| ELit l -> Format.fprintf fmt "%a" format_lit (Marked.same_mark_as l e)
|
||||
| EApp
|
||||
((EOp (Binop ((Dcalc.Ast.Map | Dcalc.Ast.Filter) as op)), _), [arg1; arg2])
|
||||
->
|
||||
@ -336,6 +350,19 @@ let rec format_expression
|
||||
| EApp ((EOp (Unop op), _), [arg1]) ->
|
||||
Format.fprintf fmt "%a(%a)" format_unop (op, Pos.no_pos)
|
||||
(format_expression ctx) arg1
|
||||
| EApp ((EFunc x, pos), args)
|
||||
when Ast.TopLevelName.compare x Ast.handle_default = 0
|
||||
|| Ast.TopLevelName.compare x Ast.handle_default_opt = 0 ->
|
||||
Format.fprintf fmt
|
||||
"%a(@[<hov 0>SourcePosition(filename=\"%s\",@ start_line=%d,@ \
|
||||
start_column=%d,@ end_line=%d, end_column=%d,@ law_headings=%a), %a)@]"
|
||||
format_toplevel_name x (Pos.get_file pos) (Pos.get_start_line pos)
|
||||
(Pos.get_start_column pos) (Pos.get_end_line pos) (Pos.get_end_column pos)
|
||||
format_string_list (Pos.get_law_info pos)
|
||||
(Format.pp_print_list
|
||||
~pp_sep:(fun fmt () -> Format.fprintf fmt ",@ ")
|
||||
(format_expression ctx))
|
||||
args
|
||||
| EApp (f, args) ->
|
||||
Format.fprintf fmt "%a(@[<hov 0>%a)@]" (format_expression ctx) f
|
||||
(Format.pp_print_list
|
||||
@ -349,20 +376,21 @@ let rec format_expression
|
||||
let rec format_statement
|
||||
(ctx : Dcalc.Ast.decl_ctx)
|
||||
(fmt : Format.formatter)
|
||||
(s : stmt Pos.marked) : unit =
|
||||
match Pos.unmark s with
|
||||
(s : stmt Marked.pos) : unit =
|
||||
match Marked.unmark s with
|
||||
| SInnerFuncDef (name, { func_params; func_body }) ->
|
||||
Format.fprintf fmt "@[<hov 4>def %a(%a):@\n%a@]" format_var
|
||||
(Pos.unmark name)
|
||||
(Marked.unmark name)
|
||||
(Format.pp_print_list
|
||||
~pp_sep:(fun fmt () -> Format.fprintf fmt ", ")
|
||||
(fun fmt (var, typ) ->
|
||||
Format.fprintf fmt "%a:%a" format_var (Pos.unmark var) format_typ typ))
|
||||
Format.fprintf fmt "%a:%a" format_var (Marked.unmark var) format_typ
|
||||
typ))
|
||||
func_params (format_block ctx) func_body
|
||||
| SLocalDecl _ ->
|
||||
assert false (* We don't need to declare variables in Python *)
|
||||
| SLocalDef (v, e) ->
|
||||
Format.fprintf fmt "@[<hov 4>%a = %a@]" format_var (Pos.unmark v)
|
||||
Format.fprintf fmt "@[<hov 4>%a = %a@]" format_var (Marked.unmark v)
|
||||
(format_expression ctx) e
|
||||
| STryExcept (try_b, except, catch_b) ->
|
||||
Format.fprintf fmt "@[<hov 4>try:@\n%a@]@\n@[<hov 4>except %a:@\n%a@]"
|
||||
@ -370,7 +398,7 @@ let rec format_statement
|
||||
(format_block ctx) catch_b
|
||||
| SRaise except ->
|
||||
Format.fprintf fmt "@[<hov 4>raise %a@]" format_exception
|
||||
(except, Pos.get_position s)
|
||||
(except, Marked.get_mark s)
|
||||
| SIfThenElse (cond, b1, b2) ->
|
||||
Format.fprintf fmt "@[<hov 4>if %a:@\n%a@]@\n@[<hov 4>else:@\n%a@]"
|
||||
(format_expression ctx) cond (format_block ctx) b1 (format_block ctx) b2
|
||||
@ -408,10 +436,19 @@ let rec format_statement
|
||||
cases
|
||||
| SReturn e1 ->
|
||||
Format.fprintf fmt "@[<hov 4>return %a@]" (format_expression ctx)
|
||||
(e1, Pos.get_position s)
|
||||
(e1, Marked.get_mark s)
|
||||
| SAssert e1 ->
|
||||
Format.fprintf fmt "@[<hov 4>assert %a@]" (format_expression ctx)
|
||||
(e1, Pos.get_position s)
|
||||
let pos = Marked.get_mark s in
|
||||
Format.fprintf fmt
|
||||
"@[<hov 4>if not (%a):@\n\
|
||||
raise AssertionFailure(@[<hov 0>SourcePosition(@[<hov \
|
||||
0>filename=\"%s\",@ start_line=%d,@ start_column=%d,@ end_line=%d,@ \
|
||||
end_column=%d,@ law_headings=@[<hv>%a@])@])@]@]"
|
||||
(format_expression ctx)
|
||||
(e1, Marked.get_mark s)
|
||||
(Pos.get_file pos) (Pos.get_start_line pos) (Pos.get_start_column pos)
|
||||
(Pos.get_end_line pos) (Pos.get_end_column pos) format_string_list
|
||||
(Pos.get_law_info pos)
|
||||
|
||||
and format_block (ctx : Dcalc.Ast.decl_ctx) (fmt : Format.formatter) (b : block)
|
||||
: unit =
|
||||
@ -419,7 +456,7 @@ and format_block (ctx : Dcalc.Ast.decl_ctx) (fmt : Format.formatter) (b : block)
|
||||
~pp_sep:(fun fmt () -> Format.fprintf fmt "@\n")
|
||||
(format_statement ctx) fmt
|
||||
(List.filter
|
||||
(fun s -> match Pos.unmark s with SLocalDecl _ -> false | _ -> true)
|
||||
(fun s -> match Marked.unmark s with SLocalDecl _ -> false | _ -> true)
|
||||
b)
|
||||
|
||||
let format_ctx
|
||||
@ -429,20 +466,20 @@ let format_ctx
|
||||
let format_struct_decl fmt (struct_name, struct_fields) =
|
||||
Format.fprintf fmt
|
||||
"class %a:@\n\
|
||||
\tdef __init__(self, %a) -> None:@\n\
|
||||
\ def __init__(self, %a) -> None:@\n\
|
||||
%a@\n\
|
||||
@\n\
|
||||
\tdef __eq__(self, other: object) -> bool:@\n\
|
||||
\t\tif isinstance(other, %a):@\n\
|
||||
\t\t\treturn @[<hov>(%a)@]@\n\
|
||||
\t\telse:@\n\
|
||||
\t\t\treturn False@\n\
|
||||
\ def __eq__(self, other: object) -> bool:@\n\
|
||||
\ if isinstance(other, %a):@\n\
|
||||
\ return @[<hov>(%a)@]@\n\
|
||||
\ else:@\n\
|
||||
\ return False@\n\
|
||||
@\n\
|
||||
\tdef __ne__(self, other: object) -> bool:@\n\
|
||||
\t\treturn not (self == other)@\n\
|
||||
\ def __ne__(self, other: object) -> bool:@\n\
|
||||
\ return not (self == other)@\n\
|
||||
@\n\
|
||||
\tdef __str__(self) -> str:@\n\
|
||||
\t\t@[<hov 4>return \"%a(%a)\".format(%a)@]" format_struct_name
|
||||
\ def __str__(self) -> str:@\n\
|
||||
\ @[<hov 4>return \"%a(%a)\".format(%a)@]" format_struct_name
|
||||
struct_name
|
||||
(Format.pp_print_list
|
||||
~pp_sep:(fun fmt () -> Format.fprintf fmt ", ")
|
||||
@ -451,12 +488,12 @@ let format_ctx
|
||||
format_typ struct_field_type))
|
||||
struct_fields
|
||||
(if List.length struct_fields = 0 then fun fmt _ ->
|
||||
Format.fprintf fmt "\t\tpass"
|
||||
Format.fprintf fmt " pass"
|
||||
else
|
||||
Format.pp_print_list
|
||||
~pp_sep:(fun fmt () -> Format.fprintf fmt "@\n")
|
||||
(fun _fmt (struct_field, _) ->
|
||||
Format.fprintf fmt "\t\tself.%a = %a" format_struct_field_name
|
||||
Format.fprintf fmt " self.%a = %a" format_struct_field_name
|
||||
struct_field format_struct_field_name struct_field))
|
||||
struct_fields format_struct_name struct_name
|
||||
(if List.length struct_fields > 0 then
|
||||
@ -486,23 +523,24 @@ let format_ctx
|
||||
%a@]@\n\
|
||||
@\n\
|
||||
class %a:@\n\
|
||||
\tdef __init__(self, code: %a_Code, value: Any) -> None:@\n\
|
||||
\t\tself.code = code@\n\
|
||||
\t\tself.value = value@\n\
|
||||
\ def __init__(self, code: %a_Code, value: Any) -> None:@\n\
|
||||
\ self.code = code@\n\
|
||||
\ self.value = value@\n\
|
||||
@\n\
|
||||
@\n\
|
||||
\tdef __eq__(self, other: object) -> bool:@\n\
|
||||
\t\tif isinstance(other, %a):@\n\
|
||||
\t\t\treturn self.code == other.code and self.value == other.value@\n\
|
||||
\t\telse:@\n\
|
||||
\t\t\treturn False@\n\
|
||||
\ def __eq__(self, other: object) -> bool:@\n\
|
||||
\ if isinstance(other, %a):@\n\
|
||||
\ return self.code == other.code and self.value == \
|
||||
other.value@\n\
|
||||
\ else:@\n\
|
||||
\ return False@\n\
|
||||
@\n\
|
||||
@\n\
|
||||
\tdef __ne__(self, other: object) -> bool:@\n\
|
||||
\t\treturn not (self == other)@\n\
|
||||
\ def __ne__(self, other: object) -> bool:@\n\
|
||||
\ return not (self == other)@\n\
|
||||
@\n\
|
||||
\tdef __str__(self) -> str:@\n\
|
||||
\t\t@[<hov 4>return \"{}({})\".format(self.code, self.value)@]"
|
||||
\ def __str__(self) -> str:@\n\
|
||||
\ @[<hov 4>return \"{}({})\".format(self.code, self.value)@]"
|
||||
format_enum_name enum_name
|
||||
(Format.pp_print_list
|
||||
~pp_sep:(fun fmt () -> Format.fprintf fmt "@\n")
|
||||
@ -547,28 +585,28 @@ let format_program
|
||||
(* We disable the style flag in order to enjoy formatting from the
|
||||
pretty-printers of Dcalc and Lcalc but without the color terminal
|
||||
markers. *)
|
||||
Cli.style_flag := false;
|
||||
Format.fprintf fmt
|
||||
"# This file has been generated by the Catala compiler, do not edit!\n\
|
||||
@\n\
|
||||
from catala.runtime import *@\n\
|
||||
from typing import Any, List, Callable, Tuple\n\
|
||||
from enum import Enum\n\
|
||||
@\n\
|
||||
%a@\n\
|
||||
@\n\
|
||||
%a@?"
|
||||
(format_ctx type_ordering) p.decl_ctx
|
||||
(Format.pp_print_list
|
||||
~pp_sep:(fun fmt () -> Format.fprintf fmt "@\n@\n")
|
||||
(fun fmt body ->
|
||||
let { Ast.func_params; Ast.func_body } = body.scope_body_func in
|
||||
Format.fprintf fmt "@[<hov 4>def %a(%a):@\n%a@]" format_toplevel_name
|
||||
body.scope_body_var
|
||||
(Format.pp_print_list
|
||||
~pp_sep:(fun fmt () -> Format.fprintf fmt ", ")
|
||||
(fun fmt (var, typ) ->
|
||||
Format.fprintf fmt "%a:%a" format_var (Pos.unmark var)
|
||||
format_typ typ))
|
||||
func_params (format_block p.decl_ctx) func_body))
|
||||
p.scopes
|
||||
Cli.call_unstyled (fun _ ->
|
||||
Format.fprintf fmt
|
||||
"# This file has been generated by the Catala compiler, do not edit!\n\
|
||||
@\n\
|
||||
from catala.runtime import *@\n\
|
||||
from typing import Any, List, Callable, Tuple\n\
|
||||
from enum import Enum\n\
|
||||
@\n\
|
||||
%a@\n\
|
||||
@\n\
|
||||
%a@?"
|
||||
(format_ctx type_ordering) p.decl_ctx
|
||||
(Format.pp_print_list
|
||||
~pp_sep:(fun fmt () -> Format.fprintf fmt "@\n@\n")
|
||||
(fun fmt body ->
|
||||
let { Ast.func_params; Ast.func_body } = body.scope_body_func in
|
||||
Format.fprintf fmt "@[<hov 4>def %a(%a):@\n%a@]"
|
||||
format_toplevel_name body.scope_body_var
|
||||
(Format.pp_print_list
|
||||
~pp_sep:(fun fmt () -> Format.fprintf fmt ", ")
|
||||
(fun fmt (var, typ) ->
|
||||
Format.fprintf fmt "%a:%a" format_var (Marked.unmark var)
|
||||
format_typ typ))
|
||||
func_params (format_block p.decl_ctx) func_body))
|
||||
p.scopes)
|
||||
|
@ -51,16 +51,16 @@ module EnumConstructorMap : Map.S with type key = EnumConstructor.t =
|
||||
module EnumConstructorMapLift = Bindlib.Lift (EnumConstructorMap)
|
||||
|
||||
type location =
|
||||
| ScopeVar of ScopeVar.t Pos.marked
|
||||
| ScopeVar of ScopeVar.t Marked.pos
|
||||
| SubScopeVar of
|
||||
ScopeName.t * SubScopeName.t Pos.marked * ScopeVar.t Pos.marked
|
||||
ScopeName.t * SubScopeName.t Marked.pos * ScopeVar.t Marked.pos
|
||||
|
||||
module LocationSet : Set.S with type elt = location Pos.marked =
|
||||
module LocationSet : Set.S with type elt = location Marked.pos =
|
||||
Set.Make (struct
|
||||
type t = location Pos.marked
|
||||
type t = location Marked.pos
|
||||
|
||||
let compare x y =
|
||||
match Pos.unmark x, Pos.unmark y with
|
||||
match Marked.unmark x, Marked.unmark y with
|
||||
| ScopeVar (vx, _), ScopeVar (vy, _) -> ScopeVar.compare vx vy
|
||||
| ( SubScopeVar (_, (xsubindex, _), (xsubvar, _)),
|
||||
SubScopeVar (_, (ysubindex, _), (ysubvar, _)) ) ->
|
||||
@ -74,7 +74,7 @@ type typ =
|
||||
| TLit of Dcalc.Ast.typ_lit
|
||||
| TStruct of StructName.t
|
||||
| TEnum of EnumName.t
|
||||
| TArrow of typ Pos.marked * typ Pos.marked
|
||||
| TArrow of typ Marked.pos * typ Marked.pos
|
||||
| TArray of typ
|
||||
| TAny
|
||||
|
||||
@ -102,23 +102,23 @@ module Typ = struct
|
||||
| _, TArray _ -> 1
|
||||
end
|
||||
|
||||
type expr =
|
||||
type marked_expr = expr Marked.pos
|
||||
|
||||
and expr =
|
||||
| ELocation of location
|
||||
| EVar of expr Bindlib.var Pos.marked
|
||||
| EStruct of StructName.t * expr Pos.marked StructFieldMap.t
|
||||
| EStructAccess of expr Pos.marked * StructFieldName.t * StructName.t
|
||||
| EEnumInj of expr Pos.marked * EnumConstructor.t * EnumName.t
|
||||
| EMatch of
|
||||
expr Pos.marked * EnumName.t * expr Pos.marked EnumConstructorMap.t
|
||||
| EVar of expr Bindlib.var
|
||||
| EStruct of StructName.t * marked_expr StructFieldMap.t
|
||||
| EStructAccess of marked_expr * StructFieldName.t * StructName.t
|
||||
| EEnumInj of marked_expr * EnumConstructor.t * EnumName.t
|
||||
| EMatch of marked_expr * EnumName.t * marked_expr EnumConstructorMap.t
|
||||
| ELit of Dcalc.Ast.lit
|
||||
| EAbs of
|
||||
(expr, expr Pos.marked) Bindlib.mbinder Pos.marked * typ Pos.marked list
|
||||
| EApp of expr Pos.marked * expr Pos.marked list
|
||||
| EAbs of (expr, marked_expr) Bindlib.mbinder * typ Marked.pos list
|
||||
| EApp of marked_expr * marked_expr list
|
||||
| EOp of Dcalc.Ast.operator
|
||||
| EDefault of expr Pos.marked list * expr Pos.marked * expr Pos.marked
|
||||
| EIfThenElse of expr Pos.marked * expr Pos.marked * expr Pos.marked
|
||||
| EArray of expr Pos.marked list
|
||||
| ErrorOnEmpty of expr Pos.marked
|
||||
| EDefault of marked_expr list * marked_expr * marked_expr
|
||||
| EIfThenElse of marked_expr * marked_expr * marked_expr
|
||||
| EArray of marked_expr list
|
||||
| ErrorOnEmpty of marked_expr
|
||||
|
||||
module Expr = struct
|
||||
type t = expr
|
||||
@ -136,13 +136,11 @@ module Expr = struct
|
||||
in
|
||||
match e1, e2 with
|
||||
| ELocation _, ELocation _ -> 0
|
||||
| EVar (v1, _), EVar (v2, _) -> Bindlib.compare_vars v1 v2
|
||||
| EVar v1, EVar v2 -> Bindlib.compare_vars v1 v2
|
||||
| EStruct (name1, field_map1), EStruct (name2, field_map2) -> (
|
||||
match StructName.compare name1 name2 with
|
||||
| 0 ->
|
||||
StructFieldMap.compare
|
||||
(Pos.compare_marked compare)
|
||||
field_map1 field_map2
|
||||
StructFieldMap.compare (Marked.compare compare) field_map1 field_map2
|
||||
| n -> n)
|
||||
| ( EStructAccess ((e1, _), field_name1, struct_name1),
|
||||
EStructAccess ((e2, _), field_name2, struct_name2) ) -> (
|
||||
@ -163,13 +161,12 @@ module Expr = struct
|
||||
match compare e1 e2 with
|
||||
| 0 -> (
|
||||
match EnumName.compare name1 name2 with
|
||||
| 0 ->
|
||||
EnumConstructorMap.compare (Pos.compare_marked compare) emap1 emap2
|
||||
| 0 -> EnumConstructorMap.compare (Marked.compare compare) emap1 emap2
|
||||
| n -> n)
|
||||
| n -> n)
|
||||
| ELit l1, ELit l2 -> Stdlib.compare l1 l2
|
||||
| EAbs ((binder1, _), typs1), EAbs ((binder2, _), typs2) -> (
|
||||
match list_compare (Pos.compare_marked Typ.compare) typs1 typs2 with
|
||||
| EAbs (binder1, typs1), EAbs (binder2, typs2) -> (
|
||||
match list_compare (Marked.compare Typ.compare) typs1 typs2 with
|
||||
| 0 ->
|
||||
let _, (e1, _), (e2, _) = Bindlib.unmbind2 binder1 binder2 in
|
||||
compare e1 e2
|
||||
@ -184,7 +181,7 @@ module Expr = struct
|
||||
match compare just1 just2 with
|
||||
| 0 -> (
|
||||
match compare cons1 cons2 with
|
||||
| 0 -> list_compare (Pos.compare_marked compare) exs1 exs2
|
||||
| 0 -> list_compare (Marked.compare compare) exs1 exs2
|
||||
| n -> n)
|
||||
| n -> n)
|
||||
| ( EIfThenElse ((i1, _), (t1, _), (e1, _)),
|
||||
@ -225,11 +222,11 @@ end
|
||||
|
||||
module ExprMap = Map.Make (Expr)
|
||||
|
||||
let rec locations_used (e : expr Pos.marked) : LocationSet.t =
|
||||
match Pos.unmark e with
|
||||
| ELocation l -> LocationSet.singleton (l, Pos.get_position e)
|
||||
let rec locations_used (e : expr Marked.pos) : LocationSet.t =
|
||||
match Marked.unmark e with
|
||||
| ELocation l -> LocationSet.singleton (l, Marked.get_mark e)
|
||||
| EVar _ | ELit _ | EOp _ -> LocationSet.empty
|
||||
| EAbs ((binder, _), _) ->
|
||||
| EAbs (binder, _) ->
|
||||
let _, body = Bindlib.unmbind binder in
|
||||
locations_used body
|
||||
| EStruct (_, es) ->
|
||||
@ -261,21 +258,21 @@ let rec locations_used (e : expr Pos.marked) : LocationSet.t =
|
||||
| ErrorOnEmpty e' -> locations_used e'
|
||||
|
||||
type io_input = NoInput | OnlyInput | Reentrant
|
||||
type io = { io_output : bool Pos.marked; io_input : io_input Pos.marked }
|
||||
type io = { io_output : bool Marked.pos; io_input : io_input Marked.pos }
|
||||
|
||||
type rule =
|
||||
| Definition of location Pos.marked * typ Pos.marked * io * expr Pos.marked
|
||||
| Assertion of expr Pos.marked
|
||||
| Definition of location Marked.pos * typ Marked.pos * io * expr Marked.pos
|
||||
| Assertion of expr Marked.pos
|
||||
| Call of ScopeName.t * SubScopeName.t
|
||||
|
||||
type scope_decl = {
|
||||
scope_decl_name : ScopeName.t;
|
||||
scope_sig : (typ Pos.marked * io) ScopeVarMap.t;
|
||||
scope_sig : (typ Marked.pos * io) ScopeVarMap.t;
|
||||
scope_decl_rules : rule list;
|
||||
}
|
||||
|
||||
type struct_ctx = (StructFieldName.t * typ Pos.marked) list StructMap.t
|
||||
type enum_ctx = (EnumConstructor.t * typ Pos.marked) list EnumMap.t
|
||||
type struct_ctx = (StructFieldName.t * typ Marked.pos) list StructMap.t
|
||||
type enum_ctx = (EnumConstructor.t * typ Marked.pos) list EnumMap.t
|
||||
|
||||
type program = {
|
||||
program_scopes : scope_decl ScopeMap.t;
|
||||
@ -286,46 +283,38 @@ type program = {
|
||||
module Var = struct
|
||||
type t = expr Bindlib.var
|
||||
|
||||
let make (s : string Pos.marked) : t =
|
||||
Bindlib.new_var
|
||||
(fun (x : expr Bindlib.var) : expr -> EVar (x, Pos.get_position s))
|
||||
(Pos.unmark s)
|
||||
let make (s : string) : t =
|
||||
Bindlib.new_var (fun (x : expr Bindlib.var) : expr -> EVar x) s
|
||||
|
||||
let compare x y = Bindlib.compare_vars x y
|
||||
end
|
||||
|
||||
type vars = expr Bindlib.mvar
|
||||
|
||||
let make_var ((x, pos) : Var.t Pos.marked) : expr Pos.marked Bindlib.box =
|
||||
let make_var ((x, pos) : Var.t Marked.pos) : expr Marked.pos Bindlib.box =
|
||||
Bindlib.box_apply (fun v -> v, pos) (Bindlib.box_var x)
|
||||
|
||||
let make_abs
|
||||
(xs : vars)
|
||||
(e : expr Pos.marked Bindlib.box)
|
||||
(pos_binder : Pos.t)
|
||||
(taus : typ Pos.marked list)
|
||||
(pos : Pos.t) : expr Pos.marked Bindlib.box =
|
||||
Bindlib.box_apply
|
||||
(fun b -> EAbs ((b, pos_binder), taus), pos)
|
||||
(Bindlib.bind_mvar xs e)
|
||||
(e : expr Marked.pos Bindlib.box)
|
||||
(taus : typ Marked.pos list)
|
||||
(pos : Pos.t) : expr Marked.pos Bindlib.box =
|
||||
Bindlib.box_apply (fun b -> EAbs (b, taus), pos) (Bindlib.bind_mvar xs e)
|
||||
|
||||
let make_app
|
||||
(e : expr Pos.marked Bindlib.box)
|
||||
(u : expr Pos.marked Bindlib.box list)
|
||||
(pos : Pos.t) : expr Pos.marked Bindlib.box =
|
||||
(e : expr Marked.pos Bindlib.box)
|
||||
(u : expr Marked.pos Bindlib.box list)
|
||||
(pos : Pos.t) : expr Marked.pos Bindlib.box =
|
||||
Bindlib.box_apply2 (fun e u -> EApp (e, u), pos) e (Bindlib.box_list u)
|
||||
|
||||
let make_let_in
|
||||
(x : Var.t)
|
||||
(tau : typ Pos.marked)
|
||||
(e1 : expr Pos.marked Bindlib.box)
|
||||
(e2 : expr Pos.marked Bindlib.box) : expr Pos.marked Bindlib.box =
|
||||
(tau : typ Marked.pos)
|
||||
(e1 : expr Marked.pos Bindlib.box)
|
||||
(e2 : expr Marked.pos Bindlib.box) : expr Marked.pos Bindlib.box =
|
||||
Bindlib.box_apply2
|
||||
(fun e u -> EApp (e, u), Pos.get_position (Bindlib.unbox e2))
|
||||
(make_abs (Array.of_list [x]) e2
|
||||
(Pos.get_position (Bindlib.unbox e2))
|
||||
[tau]
|
||||
(Pos.get_position (Bindlib.unbox e2)))
|
||||
(fun e u -> EApp (e, u), Marked.get_mark (Bindlib.unbox e2))
|
||||
(make_abs (Array.of_list [x]) e2 [tau] (Marked.get_mark (Bindlib.unbox e2)))
|
||||
(Bindlib.box_list [e1])
|
||||
|
||||
let make_default ?(pos = Pos.no_pos) exceptions just cons =
|
||||
@ -344,7 +333,7 @@ let make_default ?(pos = Pos.no_pos) exceptions just cons =
|
||||
EDefault (exceptions, just, cons), pos
|
||||
| [except], Some false, _ -> except
|
||||
| exceptions, _, cons ->
|
||||
let pos = if pos <> Pos.no_pos then pos else Pos.get_position just in
|
||||
let pos = if pos <> Pos.no_pos then pos else Marked.get_mark just in
|
||||
EDefault (exceptions, just, cons), pos
|
||||
|
||||
module VarMap = Map.Make (Var)
|
||||
|
@ -50,11 +50,11 @@ module EnumConstructorMapLift : sig
|
||||
end
|
||||
|
||||
type location =
|
||||
| ScopeVar of ScopeVar.t Pos.marked
|
||||
| ScopeVar of ScopeVar.t Marked.pos
|
||||
| SubScopeVar of
|
||||
ScopeName.t * SubScopeName.t Pos.marked * ScopeVar.t Pos.marked
|
||||
ScopeName.t * SubScopeName.t Marked.pos * ScopeVar.t Marked.pos
|
||||
|
||||
module LocationSet : Set.S with type elt = location Pos.marked
|
||||
module LocationSet : Set.S with type elt = location Marked.pos
|
||||
|
||||
(** {1 Abstract syntax tree} *)
|
||||
|
||||
@ -62,36 +62,36 @@ type typ =
|
||||
| TLit of Dcalc.Ast.typ_lit
|
||||
| TStruct of StructName.t
|
||||
| TEnum of EnumName.t
|
||||
| TArrow of typ Pos.marked * typ Pos.marked
|
||||
| TArrow of typ Marked.pos * typ Marked.pos
|
||||
| TArray of typ
|
||||
| TAny
|
||||
|
||||
module Typ : Set.OrderedType with type t = typ
|
||||
|
||||
type marked_expr = expr Marked.pos
|
||||
(** The expressions use the {{:https://lepigre.fr/ocaml-bindlib/} Bindlib}
|
||||
library, based on higher-order abstract syntax*)
|
||||
type expr =
|
||||
|
||||
and expr =
|
||||
| ELocation of location
|
||||
| EVar of expr Bindlib.var Pos.marked
|
||||
| EStruct of StructName.t * expr Pos.marked StructFieldMap.t
|
||||
| EStructAccess of expr Pos.marked * StructFieldName.t * StructName.t
|
||||
| EEnumInj of expr Pos.marked * EnumConstructor.t * EnumName.t
|
||||
| EMatch of
|
||||
expr Pos.marked * EnumName.t * expr Pos.marked EnumConstructorMap.t
|
||||
| EVar of expr Bindlib.var
|
||||
| EStruct of StructName.t * marked_expr StructFieldMap.t
|
||||
| EStructAccess of marked_expr * StructFieldName.t * StructName.t
|
||||
| EEnumInj of marked_expr * EnumConstructor.t * EnumName.t
|
||||
| EMatch of marked_expr * EnumName.t * marked_expr EnumConstructorMap.t
|
||||
| ELit of Dcalc.Ast.lit
|
||||
| EAbs of
|
||||
(expr, expr Pos.marked) Bindlib.mbinder Pos.marked * typ Pos.marked list
|
||||
| EApp of expr Pos.marked * expr Pos.marked list
|
||||
| EAbs of (expr, marked_expr) Bindlib.mbinder * typ Marked.pos list
|
||||
| EApp of marked_expr * marked_expr list
|
||||
| EOp of Dcalc.Ast.operator
|
||||
| EDefault of expr Pos.marked list * expr Pos.marked * expr Pos.marked
|
||||
| EIfThenElse of expr Pos.marked * expr Pos.marked * expr Pos.marked
|
||||
| EArray of expr Pos.marked list
|
||||
| ErrorOnEmpty of expr Pos.marked
|
||||
| EDefault of marked_expr list * marked_expr * marked_expr
|
||||
| EIfThenElse of marked_expr * marked_expr * marked_expr
|
||||
| EArray of marked_expr list
|
||||
| ErrorOnEmpty of marked_expr
|
||||
|
||||
module Expr : Set.OrderedType with type t = expr
|
||||
module ExprMap : Map.S with type key = expr
|
||||
|
||||
val locations_used : expr Pos.marked -> LocationSet.t
|
||||
val locations_used : expr Marked.pos -> LocationSet.t
|
||||
|
||||
(** This type characterizes the three levels of visibility for a given scope
|
||||
variable with regards to the scope's input and possible redefinitions inside
|
||||
@ -108,25 +108,25 @@ type io_input =
|
||||
caller as they appear in the input. *)
|
||||
|
||||
type io = {
|
||||
io_output : bool Pos.marked;
|
||||
io_output : bool Marked.pos;
|
||||
(** [true] is present in the output of the scope. *)
|
||||
io_input : io_input Pos.marked;
|
||||
io_input : io_input Marked.pos;
|
||||
}
|
||||
(** Characterization of the input/output status of a scope variable. *)
|
||||
|
||||
type rule =
|
||||
| Definition of location Pos.marked * typ Pos.marked * io * expr Pos.marked
|
||||
| Assertion of expr Pos.marked
|
||||
| Definition of location Marked.pos * typ Marked.pos * io * expr Marked.pos
|
||||
| Assertion of expr Marked.pos
|
||||
| Call of ScopeName.t * SubScopeName.t
|
||||
|
||||
type scope_decl = {
|
||||
scope_decl_name : ScopeName.t;
|
||||
scope_sig : (typ Pos.marked * io) ScopeVarMap.t;
|
||||
scope_sig : (typ Marked.pos * io) ScopeVarMap.t;
|
||||
scope_decl_rules : rule list;
|
||||
}
|
||||
|
||||
type struct_ctx = (StructFieldName.t * typ Pos.marked) list StructMap.t
|
||||
type enum_ctx = (EnumConstructor.t * typ Pos.marked) list EnumMap.t
|
||||
type struct_ctx = (StructFieldName.t * typ Marked.pos) list StructMap.t
|
||||
type enum_ctx = (EnumConstructor.t * typ Marked.pos) list EnumMap.t
|
||||
|
||||
type program = {
|
||||
program_scopes : scope_decl ScopeMap.t;
|
||||
@ -139,7 +139,7 @@ type program = {
|
||||
module Var : sig
|
||||
type t = expr Bindlib.var
|
||||
|
||||
val make : string Pos.marked -> t
|
||||
val make : string -> t
|
||||
val compare : t -> t -> int
|
||||
end
|
||||
|
||||
@ -147,35 +147,34 @@ module VarMap : Map.S with type key = Var.t
|
||||
|
||||
type vars = expr Bindlib.mvar
|
||||
|
||||
val make_var : Var.t Pos.marked -> expr Pos.marked Bindlib.box
|
||||
val make_var : Var.t Marked.pos -> expr Marked.pos Bindlib.box
|
||||
|
||||
val make_abs :
|
||||
vars ->
|
||||
expr Pos.marked Bindlib.box ->
|
||||
expr Marked.pos Bindlib.box ->
|
||||
typ Marked.pos list ->
|
||||
Pos.t ->
|
||||
typ Pos.marked list ->
|
||||
Pos.t ->
|
||||
expr Pos.marked Bindlib.box
|
||||
expr Marked.pos Bindlib.box
|
||||
|
||||
val make_app :
|
||||
expr Pos.marked Bindlib.box ->
|
||||
expr Pos.marked Bindlib.box list ->
|
||||
expr Marked.pos Bindlib.box ->
|
||||
expr Marked.pos Bindlib.box list ->
|
||||
Pos.t ->
|
||||
expr Pos.marked Bindlib.box
|
||||
expr Marked.pos Bindlib.box
|
||||
|
||||
val make_let_in :
|
||||
Var.t ->
|
||||
typ Pos.marked ->
|
||||
expr Pos.marked Bindlib.box ->
|
||||
expr Pos.marked Bindlib.box ->
|
||||
expr Pos.marked Bindlib.box
|
||||
typ Marked.pos ->
|
||||
expr Marked.pos Bindlib.box ->
|
||||
expr Marked.pos Bindlib.box ->
|
||||
expr Marked.pos Bindlib.box
|
||||
|
||||
val make_default :
|
||||
?pos:Pos.t ->
|
||||
expr Pos.marked list ->
|
||||
expr Pos.marked ->
|
||||
expr Pos.marked ->
|
||||
expr Pos.marked
|
||||
expr Marked.pos list ->
|
||||
expr Marked.pos ->
|
||||
expr Marked.pos ->
|
||||
expr Marked.pos
|
||||
(** [make_default ?pos exceptions just cons] builds a term semantically
|
||||
equivalent to [<exceptions | just :- cons>] (the [EDefault] constructor)
|
||||
while avoiding redundant nested constructions. The position is extracted
|
||||
|
@ -61,14 +61,14 @@ let build_program_dep_graph (prgm : Ast.program) : SDependencies.t =
|
||||
| Ast.Call (subscope, subindex) ->
|
||||
if subscope = scope_name then
|
||||
Errors.raise_spanned_error
|
||||
(Pos.get_position
|
||||
(Marked.get_mark
|
||||
(Ast.ScopeName.get_info scope.Ast.scope_decl_name))
|
||||
"The scope %a is calling into itself as a subscope, which is \
|
||||
forbidden since Catala does not provide recursion"
|
||||
Ast.ScopeName.format_t scope.Ast.scope_decl_name
|
||||
else
|
||||
Ast.ScopeMap.add subscope
|
||||
(Pos.get_position (Ast.SubScopeName.get_info subindex))
|
||||
(Marked.get_mark (Ast.SubScopeName.get_info subindex))
|
||||
acc)
|
||||
Ast.ScopeMap.empty scope.Ast.scope_decl_rules
|
||||
in
|
||||
@ -100,10 +100,11 @@ let check_for_cycle_in_scope (g : SDependencies.t) : unit =
|
||||
let succ_str = Format.asprintf "%a" Ast.ScopeName.format_t succ in
|
||||
[
|
||||
( Some ("Cycle variable " ^ var_str ^ ", declared:"),
|
||||
Pos.get_position var_info );
|
||||
Marked.get_mark var_info );
|
||||
( Some
|
||||
("Used here in the definition of another cycle variable "
|
||||
^ succ_str ^ ":"),
|
||||
^ succ_str
|
||||
^ ":"),
|
||||
edge_pos );
|
||||
])
|
||||
scc)
|
||||
@ -165,8 +166,8 @@ module TTopologicalTraversal = Graph.Topological.Make (TDependencies)
|
||||
module TSCC = Graph.Components.Make (TDependencies)
|
||||
(** Tarjan's stongly connected components algorithm, provided by OCamlGraph *)
|
||||
|
||||
let rec get_structs_or_enums_in_type (t : Ast.typ Pos.marked) : TVertexSet.t =
|
||||
match Pos.unmark t with
|
||||
let rec get_structs_or_enums_in_type (t : Ast.typ Marked.pos) : TVertexSet.t =
|
||||
match Marked.unmark t with
|
||||
| Ast.TStruct s -> TVertexSet.singleton (TVertex.Struct s)
|
||||
| Ast.TEnum e -> TVertexSet.singleton (TVertex.Enum e)
|
||||
| Ast.TArrow (t1, t2) ->
|
||||
@ -174,7 +175,7 @@ let rec get_structs_or_enums_in_type (t : Ast.typ Pos.marked) : TVertexSet.t =
|
||||
(get_structs_or_enums_in_type t1)
|
||||
(get_structs_or_enums_in_type t2)
|
||||
| Ast.TLit _ | Ast.TAny -> TVertexSet.empty
|
||||
| Ast.TArray t1 -> get_structs_or_enums_in_type (Pos.same_pos_as t1 t)
|
||||
| Ast.TArray t1 -> get_structs_or_enums_in_type (Marked.same_mark_as t1 t)
|
||||
|
||||
let build_type_graph (structs : Ast.struct_ctx) (enums : Ast.enum_ctx) :
|
||||
TDependencies.t =
|
||||
@ -190,13 +191,13 @@ let build_type_graph (structs : Ast.struct_ctx) (enums : Ast.enum_ctx) :
|
||||
TVertexSet.fold
|
||||
(fun used g ->
|
||||
if TVertex.equal used def then
|
||||
Errors.raise_spanned_error (Pos.get_position typ)
|
||||
Errors.raise_spanned_error (Marked.get_mark typ)
|
||||
"The type %a is defined using itself, which is forbidden \
|
||||
since Catala does not provide recursive types"
|
||||
TVertex.format_t used
|
||||
else
|
||||
let edge =
|
||||
TDependencies.E.create used (Pos.get_position typ) def
|
||||
TDependencies.E.create used (Marked.get_mark typ) def
|
||||
in
|
||||
TDependencies.add_edge_e g edge)
|
||||
used g)
|
||||
@ -214,13 +215,13 @@ let build_type_graph (structs : Ast.struct_ctx) (enums : Ast.enum_ctx) :
|
||||
TVertexSet.fold
|
||||
(fun used g ->
|
||||
if TVertex.equal used def then
|
||||
Errors.raise_spanned_error (Pos.get_position typ)
|
||||
Errors.raise_spanned_error (Marked.get_mark typ)
|
||||
"The type %a is defined using itself, which is forbidden \
|
||||
since Catala does not provide recursive types"
|
||||
TVertex.format_t used
|
||||
else
|
||||
let edge =
|
||||
TDependencies.E.create used (Pos.get_position typ) def
|
||||
TDependencies.E.create used (Marked.get_mark typ) def
|
||||
in
|
||||
TDependencies.add_edge_e g edge)
|
||||
used g)
|
||||
@ -251,10 +252,11 @@ let check_type_cycles (structs : Ast.struct_ctx) (enums : Ast.enum_ctx) :
|
||||
let succ_str = Format.asprintf "%a" TVertex.format_t succ in
|
||||
[
|
||||
( Some ("Cycle type " ^ var_str ^ ", declared:"),
|
||||
Pos.get_position var_info );
|
||||
Marked.get_mark var_info );
|
||||
( Some
|
||||
("Used here in the definition of another cycle type "
|
||||
^ succ_str ^ ":"),
|
||||
^ succ_str
|
||||
^ ":"),
|
||||
edge_pos );
|
||||
])
|
||||
scc)
|
||||
|
@ -48,6 +48,6 @@ module TVertexSet : Set.S with type elt = TVertex.t
|
||||
module TDependencies :
|
||||
Graph.Sig.P with type V.t = TVertex.t and type E.label = Pos.t
|
||||
|
||||
val get_structs_or_enums_in_type : Ast.typ Pos.marked -> TVertexSet.t
|
||||
val get_structs_or_enums_in_type : Ast.typ Marked.pos -> TVertexSet.t
|
||||
val build_type_graph : Ast.struct_ctx -> Ast.enum_ctx -> TDependencies.t
|
||||
val check_type_cycles : Ast.struct_ctx -> Ast.enum_ctx -> TVertex.t list
|
||||
|
@ -17,30 +17,30 @@
|
||||
open Utils
|
||||
open Ast
|
||||
|
||||
let needs_parens (e : expr Pos.marked) : bool =
|
||||
match Pos.unmark e with EAbs _ -> true | _ -> false
|
||||
let needs_parens (e : expr Marked.pos) : bool =
|
||||
match Marked.unmark e with EAbs _ -> true | _ -> false
|
||||
|
||||
let format_var (fmt : Format.formatter) (v : Var.t) : unit =
|
||||
Format.fprintf fmt "%s_%d" (Bindlib.name_of v) (Bindlib.uid_of v)
|
||||
|
||||
let format_location (fmt : Format.formatter) (l : location) : unit =
|
||||
match l with
|
||||
| ScopeVar v -> Format.fprintf fmt "%a" ScopeVar.format_t (Pos.unmark v)
|
||||
| ScopeVar v -> Format.fprintf fmt "%a" ScopeVar.format_t (Marked.unmark v)
|
||||
| SubScopeVar (_, subindex, subvar) ->
|
||||
Format.fprintf fmt "%a.%a" SubScopeName.format_t (Pos.unmark subindex)
|
||||
ScopeVar.format_t (Pos.unmark subvar)
|
||||
Format.fprintf fmt "%a.%a" SubScopeName.format_t (Marked.unmark subindex)
|
||||
ScopeVar.format_t (Marked.unmark subvar)
|
||||
|
||||
let typ_needs_parens (e : typ Pos.marked) : bool =
|
||||
match Pos.unmark e with TArrow _ -> true | _ -> false
|
||||
let typ_needs_parens (e : typ Marked.pos) : bool =
|
||||
match Marked.unmark e with TArrow _ -> true | _ -> false
|
||||
|
||||
let rec format_typ (fmt : Format.formatter) (typ : typ Pos.marked) : unit =
|
||||
let format_typ_with_parens (fmt : Format.formatter) (t : typ Pos.marked) =
|
||||
let rec format_typ (fmt : Format.formatter) (typ : typ Marked.pos) : unit =
|
||||
let format_typ_with_parens (fmt : Format.formatter) (t : typ Marked.pos) =
|
||||
if typ_needs_parens t then
|
||||
Format.fprintf fmt "%a%a%a" Dcalc.Print.format_punctuation "(" format_typ
|
||||
t Dcalc.Print.format_punctuation ")"
|
||||
else Format.fprintf fmt "%a" format_typ t
|
||||
in
|
||||
match Pos.unmark typ with
|
||||
match Marked.unmark typ with
|
||||
| TLit l -> Dcalc.Print.format_tlit fmt l
|
||||
| TStruct s -> Format.fprintf fmt "%a" Ast.StructName.format_t s
|
||||
| TEnum e -> Format.fprintf fmt "%a" Ast.EnumName.format_t e
|
||||
@ -48,24 +48,24 @@ let rec format_typ (fmt : Format.formatter) (typ : typ Pos.marked) : unit =
|
||||
Format.fprintf fmt "@[<hov 2>%a %a@ %a@]" format_typ_with_parens t1
|
||||
Dcalc.Print.format_operator "→" format_typ t2
|
||||
| TArray t1 ->
|
||||
Format.fprintf fmt "@[%a@ %a@]" format_typ (Pos.same_pos_as t1 typ)
|
||||
Format.fprintf fmt "@[%a@ %a@]" format_typ
|
||||
(Marked.same_mark_as t1 typ)
|
||||
Dcalc.Print.format_base_type "array"
|
||||
| TAny -> Format.fprintf fmt "any"
|
||||
|
||||
let rec format_expr
|
||||
?(debug : bool = false)
|
||||
(fmt : Format.formatter)
|
||||
(e : expr Pos.marked) : unit =
|
||||
(e : expr Marked.pos) : unit =
|
||||
let format_expr = format_expr ~debug in
|
||||
let format_with_parens (fmt : Format.formatter) (e : expr Pos.marked) =
|
||||
let format_with_parens (fmt : Format.formatter) (e : expr Marked.pos) =
|
||||
if needs_parens e then Format.fprintf fmt "(%a)" format_expr e
|
||||
else Format.fprintf fmt "%a" format_expr e
|
||||
in
|
||||
match Pos.unmark e with
|
||||
match Marked.unmark e with
|
||||
| ELocation l -> Format.fprintf fmt "%a" format_location l
|
||||
| EVar v -> Format.fprintf fmt "%a" format_var (Pos.unmark v)
|
||||
| ELit l ->
|
||||
Format.fprintf fmt "%a" Dcalc.Print.format_lit (Pos.same_pos_as l e)
|
||||
| EVar v -> Format.fprintf fmt "%a" format_var v
|
||||
| ELit l -> Format.fprintf fmt "%a" Dcalc.Print.format_lit l
|
||||
| EStruct (name, fields) ->
|
||||
Format.fprintf fmt " @[<hov 2>%a@ %a@ %a@ %a@]" Ast.StructName.format_t name
|
||||
Dcalc.Print.format_punctuation "{"
|
||||
@ -97,7 +97,7 @@ let rec format_expr
|
||||
Dcalc.Print.format_enum_constructor cons_name
|
||||
Dcalc.Print.format_punctuation "→" format_expr case_expr))
|
||||
(Ast.EnumConstructorMap.bindings cases)
|
||||
| EApp ((EAbs ((binder, _), taus), _), args) ->
|
||||
| EApp ((EAbs (binder, taus), _), args) ->
|
||||
let xs, body = Bindlib.unmbind binder in
|
||||
let xs_tau = List.map2 (fun x tau -> x, tau) (Array.to_list xs) taus in
|
||||
let xs_tau_arg = List.map2 (fun (x, tau) arg -> x, tau, arg) xs_tau args in
|
||||
@ -111,7 +111,7 @@ let rec format_expr
|
||||
Dcalc.Print.format_punctuation "=" format_expr arg
|
||||
Dcalc.Print.format_keyword "in"))
|
||||
xs_tau_arg format_expr body
|
||||
| EAbs ((binder, _), taus) ->
|
||||
| EAbs (binder, taus) ->
|
||||
let xs, body = Bindlib.unmbind binder in
|
||||
let xs_tau = List.map2 (fun x tau -> x, tau) (Array.to_list xs) taus in
|
||||
Format.fprintf fmt "@[<hov 2>%a@ %a@ %a@ %a@]"
|
||||
@ -125,11 +125,11 @@ let rec format_expr
|
||||
xs_tau Dcalc.Print.format_punctuation "→" format_expr body
|
||||
| EApp ((EOp (Binop op), _), [arg1; arg2]) ->
|
||||
Format.fprintf fmt "@[%a@ %a@ %a@]" format_with_parens arg1
|
||||
Dcalc.Print.format_binop (op, Pos.no_pos) format_with_parens arg2
|
||||
Dcalc.Print.format_binop op format_with_parens arg2
|
||||
| EApp ((EOp (Unop (Log _)), _), [arg1]) when not debug ->
|
||||
format_expr fmt arg1
|
||||
| EApp ((EOp (Unop op), _), [arg1]) ->
|
||||
Format.fprintf fmt "@[%a@ %a@]" Dcalc.Print.format_unop (op, Pos.no_pos)
|
||||
Format.fprintf fmt "@[%a@ %a@]" Dcalc.Print.format_unop op
|
||||
format_with_parens arg1
|
||||
| EApp (f, args) ->
|
||||
Format.fprintf fmt "@[%a@ %a@]" format_expr f
|
||||
@ -141,12 +141,9 @@ let rec format_expr
|
||||
Format.fprintf fmt "@[<hov 2>%a@ %a@ %a@ %a@ %a@ %a@]"
|
||||
Dcalc.Print.format_keyword "if" format_expr e1 Dcalc.Print.format_keyword
|
||||
"then" format_expr e2 Dcalc.Print.format_keyword "else" format_expr e3
|
||||
| EOp (Ternop op) ->
|
||||
Format.fprintf fmt "%a" Dcalc.Print.format_ternop (op, Pos.no_pos)
|
||||
| EOp (Binop op) ->
|
||||
Format.fprintf fmt "%a" Dcalc.Print.format_binop (op, Pos.no_pos)
|
||||
| EOp (Unop op) ->
|
||||
Format.fprintf fmt "%a" Dcalc.Print.format_unop (op, Pos.no_pos)
|
||||
| EOp (Ternop op) -> Format.fprintf fmt "%a" Dcalc.Print.format_ternop op
|
||||
| EOp (Binop op) -> Format.fprintf fmt "%a" Dcalc.Print.format_binop op
|
||||
| EOp (Unop op) -> Format.fprintf fmt "%a" Dcalc.Print.format_unop op
|
||||
| EDefault (excepts, just, cons) ->
|
||||
if List.length excepts = 0 then
|
||||
Format.fprintf fmt "@[%a%a %a@ %a%a@]" Dcalc.Print.format_punctuation "⟨"
|
||||
@ -172,7 +169,7 @@ let rec format_expr
|
||||
|
||||
let format_struct
|
||||
(fmt : Format.formatter)
|
||||
((name, fields) : StructName.t * (StructFieldName.t * typ Pos.marked) list)
|
||||
((name, fields) : StructName.t * (StructFieldName.t * typ Marked.pos) list)
|
||||
: unit =
|
||||
Format.fprintf fmt "%a %a %a %a@\n@[<hov 2> %a@]@\n%a"
|
||||
Dcalc.Print.format_keyword "type" StructName.format_t name
|
||||
@ -186,7 +183,7 @@ let format_struct
|
||||
|
||||
let format_enum
|
||||
(fmt : Format.formatter)
|
||||
((name, cases) : EnumName.t * (EnumConstructor.t * typ Pos.marked) list) :
|
||||
((name, cases) : EnumName.t * (EnumConstructor.t * typ Marked.pos) list) :
|
||||
unit =
|
||||
Format.fprintf fmt "%a %a %a @\n@[<hov 2> %a@]" Dcalc.Print.format_keyword
|
||||
"type" EnumName.format_t name Dcalc.Print.format_punctuation "="
|
||||
@ -212,11 +209,11 @@ let format_scope
|
||||
"(" ScopeVar.format_t scope_var Dcalc.Print.format_punctuation ":"
|
||||
format_typ typ Dcalc.Print.format_punctuation "|"
|
||||
Dcalc.Print.format_keyword
|
||||
(match Pos.unmark vis.io_input with
|
||||
(match Marked.unmark vis.io_input with
|
||||
| NoInput -> "internal"
|
||||
| OnlyInput -> "input"
|
||||
| Reentrant -> "context")
|
||||
(if Pos.unmark vis.io_output then fun fmt () ->
|
||||
(if Marked.unmark vis.io_output then fun fmt () ->
|
||||
Format.fprintf fmt "%a@,%a" Dcalc.Print.format_punctuation "|"
|
||||
Dcalc.Print.format_keyword "output"
|
||||
else fun fmt () -> Format.fprintf fmt "@<0>")
|
||||
@ -230,16 +227,16 @@ let format_scope
|
||||
match rule with
|
||||
| Definition (loc, typ, _, e) ->
|
||||
Format.fprintf fmt "@[<hov 2>%a %a %a %a %a@ %a@]"
|
||||
Dcalc.Print.format_keyword "let" format_location (Pos.unmark loc)
|
||||
Dcalc.Print.format_punctuation ":" format_typ typ
|
||||
Dcalc.Print.format_punctuation "="
|
||||
Dcalc.Print.format_keyword "let" format_location
|
||||
(Marked.unmark loc) Dcalc.Print.format_punctuation ":" format_typ
|
||||
typ Dcalc.Print.format_punctuation "="
|
||||
(fun fmt e ->
|
||||
match Pos.unmark loc with
|
||||
match Marked.unmark loc with
|
||||
| SubScopeVar _ -> format_expr fmt e
|
||||
| ScopeVar v -> (
|
||||
match
|
||||
Pos.unmark
|
||||
(snd (ScopeVarMap.find (Pos.unmark v) decl.scope_sig))
|
||||
Marked.unmark
|
||||
(snd (ScopeVarMap.find (Marked.unmark v) decl.scope_sig))
|
||||
.io_input
|
||||
with
|
||||
| Reentrant ->
|
||||
|
@ -18,12 +18,12 @@ open Utils
|
||||
|
||||
val format_var : Format.formatter -> Ast.Var.t -> unit
|
||||
val format_location : Format.formatter -> Ast.location -> unit
|
||||
val format_typ : Format.formatter -> Ast.typ Pos.marked -> unit
|
||||
val format_typ : Format.formatter -> Ast.typ Marked.pos -> unit
|
||||
|
||||
val format_expr :
|
||||
?debug:bool (** [true] for debug printing *) ->
|
||||
Format.formatter ->
|
||||
Ast.expr Pos.marked ->
|
||||
Ast.expr Marked.pos ->
|
||||
unit
|
||||
|
||||
val format_scope :
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -17,7 +17,7 @@
|
||||
(** Scope language to default calculus translator *)
|
||||
|
||||
val translate_program :
|
||||
Ast.program -> Dcalc.Ast.program * Dependency.TVertex.t list
|
||||
Ast.program -> Dcalc.Ast.untyped Dcalc.Ast.program * Dependency.TVertex.t list
|
||||
(** Usage [translate_program p] returns a tuple [(new_program, types_list)]
|
||||
where [new_program] is the map of translated scopes. Finally, [types_list]
|
||||
is a list of all types (structs and enums) used in the program, correctly
|
||||
|
@ -42,18 +42,18 @@ type ident = (string[@opaque])
|
||||
visitors { variety = "iter"; name = "ident_iter"; nude = true }]
|
||||
(** Idents are snake_case *)
|
||||
|
||||
type qident = ident Pos.marked list
|
||||
type qident = ident Marked.pos list
|
||||
[@@deriving
|
||||
visitors
|
||||
{
|
||||
variety = "map";
|
||||
ancestors = ["Pos.marked_map"; "ident_map"];
|
||||
ancestors = ["Marked.pos_map"; "ident_map"];
|
||||
name = "qident_map";
|
||||
},
|
||||
visitors
|
||||
{
|
||||
variety = "iter";
|
||||
ancestors = ["Pos.marked_iter"; "ident_iter"];
|
||||
ancestors = ["Marked.pos_iter"; "ident_iter"];
|
||||
name = "qident_iter";
|
||||
}]
|
||||
|
||||
@ -82,18 +82,18 @@ type primitive_typ =
|
||||
|
||||
type base_typ_data =
|
||||
| Primitive of primitive_typ
|
||||
| Collection of base_typ_data Pos.marked
|
||||
| Collection of base_typ_data Marked.pos
|
||||
[@@deriving
|
||||
visitors
|
||||
{
|
||||
variety = "map";
|
||||
ancestors = ["Pos.marked_map"; "primitive_typ_map"];
|
||||
ancestors = ["Marked.pos_map"; "primitive_typ_map"];
|
||||
name = "base_typ_data_map";
|
||||
},
|
||||
visitors
|
||||
{
|
||||
variety = "iter";
|
||||
ancestors = ["Pos.marked_iter"; "primitive_typ_iter"];
|
||||
ancestors = ["Marked.pos_iter"; "primitive_typ_iter"];
|
||||
name = "base_typ_data_iter";
|
||||
}]
|
||||
|
||||
@ -115,8 +115,8 @@ type base_typ = Condition | Data of base_typ_data
|
||||
}]
|
||||
|
||||
type func_typ = {
|
||||
arg_typ : base_typ Pos.marked;
|
||||
return_typ : base_typ Pos.marked;
|
||||
arg_typ : base_typ Marked.pos;
|
||||
return_typ : base_typ Marked.pos;
|
||||
}
|
||||
[@@deriving
|
||||
visitors
|
||||
@ -152,8 +152,8 @@ type typ = Base of base_typ | Func of func_typ
|
||||
}]
|
||||
|
||||
type struct_decl_field = {
|
||||
struct_decl_field_name : ident Pos.marked;
|
||||
struct_decl_field_typ : typ Pos.marked;
|
||||
struct_decl_field_name : ident Marked.pos;
|
||||
struct_decl_field_typ : typ Marked.pos;
|
||||
}
|
||||
[@@deriving
|
||||
visitors
|
||||
@ -170,8 +170,8 @@ type struct_decl_field = {
|
||||
}]
|
||||
|
||||
type struct_decl = {
|
||||
struct_decl_name : constructor Pos.marked;
|
||||
struct_decl_fields : struct_decl_field Pos.marked list;
|
||||
struct_decl_name : constructor Marked.pos;
|
||||
struct_decl_fields : struct_decl_field Marked.pos list;
|
||||
}
|
||||
[@@deriving
|
||||
visitors
|
||||
@ -188,8 +188,8 @@ type struct_decl = {
|
||||
}]
|
||||
|
||||
type enum_decl_case = {
|
||||
enum_decl_case_name : constructor Pos.marked;
|
||||
enum_decl_case_typ : typ Pos.marked option;
|
||||
enum_decl_case_name : constructor Marked.pos;
|
||||
enum_decl_case_typ : typ Marked.pos option;
|
||||
}
|
||||
[@@deriving
|
||||
visitors
|
||||
@ -208,8 +208,8 @@ type enum_decl_case = {
|
||||
}]
|
||||
|
||||
type enum_decl = {
|
||||
enum_decl_name : constructor Pos.marked;
|
||||
enum_decl_cases : enum_decl_case Pos.marked list;
|
||||
enum_decl_name : constructor Marked.pos;
|
||||
enum_decl_cases : enum_decl_case Marked.pos list;
|
||||
}
|
||||
[@@deriving
|
||||
visitors
|
||||
@ -228,19 +228,19 @@ type enum_decl = {
|
||||
}]
|
||||
|
||||
type match_case_pattern =
|
||||
(constructor Pos.marked option * constructor Pos.marked) list
|
||||
* ident Pos.marked option
|
||||
(constructor Marked.pos option * constructor Marked.pos) list
|
||||
* ident Marked.pos option
|
||||
[@@deriving
|
||||
visitors
|
||||
{
|
||||
variety = "map";
|
||||
ancestors = ["ident_map"; "constructor_map"; "Pos.marked_map"];
|
||||
ancestors = ["ident_map"; "constructor_map"; "Marked.pos_map"];
|
||||
name = "match_case_pattern_map";
|
||||
},
|
||||
visitors
|
||||
{
|
||||
variety = "iter";
|
||||
ancestors = ["ident_iter"; "constructor_iter"; "Pos.marked_iter"];
|
||||
ancestors = ["ident_iter"; "constructor_iter"; "Marked.pos_iter"];
|
||||
name = "match_case_pattern_iter";
|
||||
}]
|
||||
|
||||
@ -300,9 +300,13 @@ type unop = Not | Minus of op_kind
|
||||
type builtin_expression =
|
||||
| Cardinal
|
||||
| IntToDec
|
||||
| MoneyToDec
|
||||
| DecToMoney
|
||||
| GetDay
|
||||
| GetMonth
|
||||
| GetYear
|
||||
| LastDayOfMonth
|
||||
| FirstDayOfMonth
|
||||
| RoundMoney
|
||||
| RoundDecimal
|
||||
[@@deriving
|
||||
@ -310,21 +314,21 @@ type builtin_expression =
|
||||
visitors { variety = "iter"; name = "builtin_expression_iter"; nude = true }]
|
||||
|
||||
type literal_date = {
|
||||
literal_date_day : (int[@opaque]) Pos.marked;
|
||||
literal_date_month : (int[@opaque]) Pos.marked;
|
||||
literal_date_year : (int[@opaque]) Pos.marked;
|
||||
literal_date_day : (int[@opaque]);
|
||||
literal_date_month : (int[@opaque]);
|
||||
literal_date_year : (int[@opaque]);
|
||||
}
|
||||
[@@deriving
|
||||
visitors
|
||||
{
|
||||
variety = "map";
|
||||
ancestors = ["Pos.marked_map"];
|
||||
ancestors = ["Marked.pos_map"];
|
||||
name = "literal_date_map";
|
||||
},
|
||||
visitors
|
||||
{
|
||||
variety = "iter";
|
||||
ancestors = ["Pos.marked_iter"];
|
||||
ancestors = ["Marked.pos_iter"];
|
||||
name = "literal_date_iter";
|
||||
}]
|
||||
|
||||
@ -349,7 +353,7 @@ type money_amount = {
|
||||
visitors { variety = "iter"; name = "money_amount_iter"; nude = true }]
|
||||
|
||||
type literal =
|
||||
| LNumber of literal_number Pos.marked * literal_unit Pos.marked option
|
||||
| LNumber of literal_number Marked.pos * literal_unit Marked.pos option
|
||||
| LBool of bool
|
||||
| LMoneyAmount of money_amount
|
||||
| LDate of literal_date
|
||||
@ -382,8 +386,8 @@ type literal =
|
||||
type aggregate_func =
|
||||
| AggregateSum of primitive_typ
|
||||
| AggregateCount
|
||||
| AggregateExtremum of bool * primitive_typ * expression Pos.marked
|
||||
| AggregateArgExtremum of bool * primitive_typ * expression Pos.marked
|
||||
| AggregateExtremum of bool * primitive_typ * expression Marked.pos
|
||||
| AggregateArgExtremum of bool * primitive_typ * expression Marked.pos
|
||||
|
||||
and collection_op =
|
||||
| Exists
|
||||
@ -393,42 +397,42 @@ and collection_op =
|
||||
| Filter
|
||||
|
||||
and explicit_match_case = {
|
||||
match_case_pattern : match_case_pattern Pos.marked;
|
||||
match_case_expr : expression Pos.marked;
|
||||
match_case_pattern : match_case_pattern Marked.pos;
|
||||
match_case_expr : expression Marked.pos;
|
||||
}
|
||||
|
||||
and match_case =
|
||||
| WildCard of expression Pos.marked
|
||||
| WildCard of expression Marked.pos
|
||||
| MatchCase of explicit_match_case
|
||||
|
||||
and match_cases = match_case Pos.marked list
|
||||
and match_cases = match_case Marked.pos list
|
||||
|
||||
and expression =
|
||||
| MatchWith of expression Pos.marked * match_cases Pos.marked
|
||||
| MatchWith of expression Marked.pos * match_cases Marked.pos
|
||||
| IfThenElse of
|
||||
expression Pos.marked * expression Pos.marked * expression Pos.marked
|
||||
| Binop of binop Pos.marked * expression Pos.marked * expression Pos.marked
|
||||
| Unop of unop Pos.marked * expression Pos.marked
|
||||
expression Marked.pos * expression Marked.pos * expression Marked.pos
|
||||
| Binop of binop Marked.pos * expression Marked.pos * expression Marked.pos
|
||||
| Unop of unop Marked.pos * expression Marked.pos
|
||||
| CollectionOp of
|
||||
collection_op Pos.marked
|
||||
* ident Pos.marked
|
||||
* expression Pos.marked
|
||||
* expression Pos.marked
|
||||
| MemCollection of expression Pos.marked * expression Pos.marked
|
||||
| TestMatchCase of expression Pos.marked * match_case_pattern Pos.marked
|
||||
| FunCall of expression Pos.marked * expression Pos.marked
|
||||
collection_op Marked.pos
|
||||
* ident Marked.pos
|
||||
* expression Marked.pos
|
||||
* expression Marked.pos
|
||||
| MemCollection of expression Marked.pos * expression Marked.pos
|
||||
| TestMatchCase of expression Marked.pos * match_case_pattern Marked.pos
|
||||
| FunCall of expression Marked.pos * expression Marked.pos
|
||||
| Builtin of builtin_expression
|
||||
| Literal of literal
|
||||
| EnumInject of
|
||||
constructor Pos.marked option
|
||||
* constructor Pos.marked
|
||||
* expression Pos.marked option
|
||||
constructor Marked.pos option
|
||||
* constructor Marked.pos
|
||||
* expression Marked.pos option
|
||||
| StructLit of
|
||||
constructor Pos.marked * (ident Pos.marked * expression Pos.marked) list
|
||||
| ArrayLit of expression Pos.marked list
|
||||
constructor Marked.pos * (ident Marked.pos * expression Marked.pos) list
|
||||
| ArrayLit of expression Marked.pos list
|
||||
| Ident of ident
|
||||
| Dotted of
|
||||
expression Pos.marked * constructor Pos.marked option * ident Pos.marked
|
||||
expression Marked.pos * constructor Marked.pos option * ident Marked.pos
|
||||
(** Dotted is for both struct field projection and sub-scope variables *)
|
||||
[@@deriving
|
||||
visitors
|
||||
@ -463,30 +467,30 @@ and expression =
|
||||
type exception_to =
|
||||
| NotAnException
|
||||
| UnlabeledException
|
||||
| ExceptionToLabel of ident Pos.marked
|
||||
| ExceptionToLabel of ident Marked.pos
|
||||
[@@deriving
|
||||
visitors
|
||||
{
|
||||
variety = "map";
|
||||
ancestors = ["ident_map"; "Pos.marked_map"];
|
||||
ancestors = ["ident_map"; "Marked.pos_map"];
|
||||
name = "exception_to_map";
|
||||
},
|
||||
visitors
|
||||
{
|
||||
variety = "iter";
|
||||
ancestors = ["ident_iter"; "Pos.marked_iter"];
|
||||
ancestors = ["ident_iter"; "Marked.pos_iter"];
|
||||
name = "exception_to_iter";
|
||||
}]
|
||||
|
||||
type rule = {
|
||||
rule_label : ident Pos.marked option;
|
||||
rule_label : ident Marked.pos option;
|
||||
rule_exception_to : exception_to;
|
||||
rule_parameter : ident Pos.marked option;
|
||||
rule_condition : expression Pos.marked option;
|
||||
rule_name : qident Pos.marked;
|
||||
rule_parameter : ident Marked.pos option;
|
||||
rule_condition : expression Marked.pos option;
|
||||
rule_name : qident Marked.pos;
|
||||
rule_id : Desugared.Ast.RuleName.t; [@opaque]
|
||||
rule_consequence : (bool[@opaque]) Pos.marked;
|
||||
rule_state : ident Pos.marked option;
|
||||
rule_consequence : (bool[@opaque]) Marked.pos;
|
||||
rule_state : ident Marked.pos option;
|
||||
}
|
||||
[@@deriving
|
||||
visitors
|
||||
@ -503,14 +507,14 @@ type rule = {
|
||||
}]
|
||||
|
||||
type definition = {
|
||||
definition_label : ident Pos.marked option;
|
||||
definition_label : ident Marked.pos option;
|
||||
definition_exception_to : exception_to;
|
||||
definition_name : qident Pos.marked;
|
||||
definition_parameter : ident Pos.marked option;
|
||||
definition_condition : expression Pos.marked option;
|
||||
definition_name : qident Marked.pos;
|
||||
definition_parameter : ident Marked.pos option;
|
||||
definition_condition : expression Marked.pos option;
|
||||
definition_id : Desugared.Ast.RuleName.t; [@opaque]
|
||||
definition_expr : expression Pos.marked;
|
||||
definition_state : ident Pos.marked option;
|
||||
definition_expr : expression Marked.pos;
|
||||
definition_state : ident Marked.pos option;
|
||||
}
|
||||
[@@deriving
|
||||
visitors
|
||||
@ -532,11 +536,11 @@ type variation_typ = Increasing | Decreasing
|
||||
visitors { variety = "iter"; name = "variation_typ_iter" }]
|
||||
|
||||
type meta_assertion =
|
||||
| FixedBy of qident Pos.marked * ident Pos.marked
|
||||
| FixedBy of qident Marked.pos * ident Marked.pos
|
||||
| VariesWith of
|
||||
qident Pos.marked
|
||||
* expression Pos.marked
|
||||
* variation_typ Pos.marked option
|
||||
qident Marked.pos
|
||||
* expression Marked.pos
|
||||
* variation_typ Marked.pos option
|
||||
[@@deriving
|
||||
visitors
|
||||
{
|
||||
@ -552,8 +556,8 @@ type meta_assertion =
|
||||
}]
|
||||
|
||||
type assertion = {
|
||||
assertion_condition : expression Pos.marked option;
|
||||
assertion_content : expression Pos.marked;
|
||||
assertion_condition : expression Marked.pos option;
|
||||
assertion_content : expression Marked.pos;
|
||||
}
|
||||
[@@deriving
|
||||
visitors
|
||||
@ -592,9 +596,9 @@ type scope_use_item =
|
||||
}]
|
||||
|
||||
type scope_use = {
|
||||
scope_use_condition : expression Pos.marked option;
|
||||
scope_use_name : constructor Pos.marked;
|
||||
scope_use_items : scope_use_item Pos.marked list;
|
||||
scope_use_condition : expression Marked.pos option;
|
||||
scope_use_name : constructor Marked.pos;
|
||||
scope_use_items : scope_use_item Marked.pos list;
|
||||
}
|
||||
[@@deriving
|
||||
visitors
|
||||
@ -616,26 +620,26 @@ type io_input = Input | Context | Internal
|
||||
visitors { variety = "iter"; name = "io_input_iter" }]
|
||||
|
||||
type scope_decl_context_io = {
|
||||
scope_decl_context_io_input : io_input Pos.marked;
|
||||
scope_decl_context_io_output : bool Pos.marked;
|
||||
scope_decl_context_io_input : io_input Marked.pos;
|
||||
scope_decl_context_io_output : bool Marked.pos;
|
||||
}
|
||||
[@@deriving
|
||||
visitors
|
||||
{
|
||||
variety = "map";
|
||||
ancestors = ["io_input_map"; "Pos.marked_map"];
|
||||
ancestors = ["io_input_map"; "Marked.pos_map"];
|
||||
name = "scope_decl_context_io_map";
|
||||
},
|
||||
visitors
|
||||
{
|
||||
variety = "iter";
|
||||
ancestors = ["io_input_iter"; "Pos.marked_iter"];
|
||||
ancestors = ["io_input_iter"; "Marked.pos_iter"];
|
||||
name = "scope_decl_context_io_iter";
|
||||
}]
|
||||
|
||||
type scope_decl_context_scope = {
|
||||
scope_decl_context_scope_name : ident Pos.marked;
|
||||
scope_decl_context_scope_sub_scope : constructor Pos.marked;
|
||||
scope_decl_context_scope_name : ident Marked.pos;
|
||||
scope_decl_context_scope_sub_scope : constructor Marked.pos;
|
||||
scope_decl_context_scope_attribute : scope_decl_context_io;
|
||||
}
|
||||
[@@deriving
|
||||
@ -647,7 +651,7 @@ type scope_decl_context_scope = {
|
||||
"ident_map";
|
||||
"constructor_map";
|
||||
"scope_decl_context_io_map";
|
||||
"Pos.marked_map";
|
||||
"Marked.pos_map";
|
||||
];
|
||||
name = "scope_decl_context_scope_map";
|
||||
},
|
||||
@ -659,16 +663,16 @@ type scope_decl_context_scope = {
|
||||
"ident_iter";
|
||||
"constructor_iter";
|
||||
"scope_decl_context_io_iter";
|
||||
"Pos.marked_iter";
|
||||
"Marked.pos_iter";
|
||||
];
|
||||
name = "scope_decl_context_scope_iter";
|
||||
}]
|
||||
|
||||
type scope_decl_context_data = {
|
||||
scope_decl_context_item_name : ident Pos.marked;
|
||||
scope_decl_context_item_typ : typ Pos.marked;
|
||||
scope_decl_context_item_name : ident Marked.pos;
|
||||
scope_decl_context_item_typ : typ Marked.pos;
|
||||
scope_decl_context_item_attribute : scope_decl_context_io;
|
||||
scope_decl_context_item_states : ident Pos.marked list;
|
||||
scope_decl_context_item_states : ident Marked.pos list;
|
||||
}
|
||||
[@@deriving
|
||||
visitors
|
||||
@ -704,8 +708,8 @@ type scope_decl_context_item =
|
||||
}]
|
||||
|
||||
type scope_decl = {
|
||||
scope_decl_name : constructor Pos.marked;
|
||||
scope_decl_context : scope_decl_context_item Pos.marked list;
|
||||
scope_decl_name : constructor Marked.pos;
|
||||
scope_decl_context : scope_decl_context_item Marked.pos list;
|
||||
}
|
||||
[@@deriving
|
||||
visitors
|
||||
@ -747,7 +751,7 @@ type code_item =
|
||||
name = "code_item_iter";
|
||||
}]
|
||||
|
||||
type code_block = code_item Pos.marked list
|
||||
type code_block = code_item Marked.pos list
|
||||
[@@deriving
|
||||
visitors
|
||||
{ variety = "map"; ancestors = ["code_item_map"]; name = "code_block_map" },
|
||||
@ -758,23 +762,23 @@ type code_block = code_item Pos.marked list
|
||||
name = "code_block_iter";
|
||||
}]
|
||||
|
||||
type source_repr = (string[@opaque]) Pos.marked
|
||||
type source_repr = (string[@opaque]) Marked.pos
|
||||
[@@deriving
|
||||
visitors
|
||||
{
|
||||
variety = "map";
|
||||
ancestors = ["Pos.marked_map"];
|
||||
ancestors = ["Marked.pos_map"];
|
||||
name = "source_repr_map";
|
||||
},
|
||||
visitors
|
||||
{
|
||||
variety = "iter";
|
||||
ancestors = ["Pos.marked_iter"];
|
||||
ancestors = ["Marked.pos_iter"];
|
||||
name = "source_repr_iter";
|
||||
}]
|
||||
|
||||
type law_heading = {
|
||||
law_heading_name : (string[@opaque]) Pos.marked;
|
||||
law_heading_name : (string[@opaque]) Marked.pos;
|
||||
law_heading_id : (string[@opaque]) option;
|
||||
law_heading_expiration_date : (string[@opaque]) option;
|
||||
law_heading_precedence : (int[@opaque]);
|
||||
@ -783,31 +787,31 @@ type law_heading = {
|
||||
visitors
|
||||
{
|
||||
variety = "map";
|
||||
ancestors = ["Pos.marked_map"];
|
||||
ancestors = ["Marked.pos_map"];
|
||||
name = "law_heading_map";
|
||||
},
|
||||
visitors
|
||||
{
|
||||
variety = "iter";
|
||||
ancestors = ["Pos.marked_iter"];
|
||||
ancestors = ["Marked.pos_iter"];
|
||||
name = "law_heading_iter";
|
||||
}]
|
||||
|
||||
type law_include =
|
||||
| PdfFile of (string[@opaque]) Pos.marked * (int[@opaque]) option
|
||||
| CatalaFile of (string[@opaque]) Pos.marked
|
||||
| LegislativeText of (string[@opaque]) Pos.marked
|
||||
| PdfFile of (string[@opaque]) Marked.pos * (int[@opaque]) option
|
||||
| CatalaFile of (string[@opaque]) Marked.pos
|
||||
| LegislativeText of (string[@opaque]) Marked.pos
|
||||
[@@deriving
|
||||
visitors
|
||||
{
|
||||
variety = "map";
|
||||
ancestors = ["Pos.marked_map"];
|
||||
ancestors = ["Marked.pos_map"];
|
||||
name = "law_include_map";
|
||||
},
|
||||
visitors
|
||||
{
|
||||
variety = "iter";
|
||||
ancestors = ["Pos.marked_iter"];
|
||||
ancestors = ["Marked.pos_iter"];
|
||||
name = "law_include_iter";
|
||||
}]
|
||||
|
||||
@ -862,7 +866,9 @@ type source_file = law_structure list
|
||||
|
||||
(** Translates a {!type: rule} into the corresponding {!type: definition} *)
|
||||
let rule_to_def (rule : rule) : definition =
|
||||
let consequence_expr = Literal (LBool (Pos.unmark rule.rule_consequence)) in
|
||||
let consequence_expr =
|
||||
Literal (LBool (Marked.unmark rule.rule_consequence))
|
||||
in
|
||||
{
|
||||
definition_label = rule.rule_label;
|
||||
definition_exception_to = rule.rule_exception_to;
|
||||
@ -870,6 +876,6 @@ let rule_to_def (rule : rule) : definition =
|
||||
definition_parameter = rule.rule_parameter;
|
||||
definition_condition = rule.rule_condition;
|
||||
definition_id = rule.rule_id;
|
||||
definition_expr = consequence_expr, Pos.get_position rule.rule_consequence;
|
||||
definition_expr = consequence_expr, Marked.get_mark rule.rule_consequence;
|
||||
definition_state = rule.rule_state;
|
||||
}
|
||||
|
@ -16,6 +16,8 @@
|
||||
the License. *)
|
||||
|
||||
open Utils
|
||||
module Runtime = Runtime_ocaml.Runtime
|
||||
|
||||
(** Translation from {!module: Surface.Ast} to {!module: Desugaring.Ast}.
|
||||
|
||||
- Removes syntactic sugars
|
||||
@ -62,7 +64,7 @@ module LiftEnumConstructorMap = Bindlib.Lift (Scopelang.Ast.EnumConstructorMap)
|
||||
|
||||
let disambiguate_constructor
|
||||
(ctxt : Name_resolution.context)
|
||||
(constructor : (string Pos.marked option * string Pos.marked) list)
|
||||
(constructor : (string Marked.pos option * string Marked.pos) list)
|
||||
(pos : Pos.t) : Scopelang.Ast.EnumName.t * Scopelang.Ast.EnumConstructor.t =
|
||||
let enum, constructor =
|
||||
match constructor with
|
||||
@ -73,11 +75,12 @@ let disambiguate_constructor
|
||||
in
|
||||
let possible_c_uids =
|
||||
try
|
||||
Desugared.Ast.IdentMap.find (Pos.unmark constructor)
|
||||
Desugared.Ast.IdentMap.find
|
||||
(Marked.unmark constructor)
|
||||
ctxt.constructor_idmap
|
||||
with Not_found ->
|
||||
Errors.raise_spanned_error
|
||||
(Pos.get_position constructor)
|
||||
(Marked.get_mark constructor)
|
||||
"The name of this constructor has not been defined before, maybe it is \
|
||||
a typo?"
|
||||
in
|
||||
@ -85,7 +88,7 @@ let disambiguate_constructor
|
||||
| None ->
|
||||
if Scopelang.Ast.EnumMap.cardinal possible_c_uids > 1 then
|
||||
Errors.raise_spanned_error
|
||||
(Pos.get_position constructor)
|
||||
(Marked.get_mark constructor)
|
||||
"This constructor name is ambiguous, it can belong to %a. Disambiguate \
|
||||
it by prefixing it with the enum name."
|
||||
(Format.pp_print_list
|
||||
@ -98,17 +101,18 @@ let disambiguate_constructor
|
||||
try
|
||||
(* The path is fully qualified *)
|
||||
let e_uid =
|
||||
Desugared.Ast.IdentMap.find (Pos.unmark enum) ctxt.enum_idmap
|
||||
Desugared.Ast.IdentMap.find (Marked.unmark enum) ctxt.enum_idmap
|
||||
in
|
||||
try
|
||||
let c_uid = Scopelang.Ast.EnumMap.find e_uid possible_c_uids in
|
||||
e_uid, c_uid
|
||||
with Not_found ->
|
||||
Errors.raise_spanned_error pos "Enum %s does not contain case %s"
|
||||
(Pos.unmark enum) (Pos.unmark constructor)
|
||||
(Marked.unmark enum)
|
||||
(Marked.unmark constructor)
|
||||
with Not_found ->
|
||||
Errors.raise_spanned_error (Pos.get_position enum)
|
||||
"Enum %s has not been defined before" (Pos.unmark enum))
|
||||
Errors.raise_spanned_error (Marked.get_mark enum)
|
||||
"Enum %s has not been defined before" (Marked.unmark enum))
|
||||
|
||||
(** Usage: [translate_expr scope ctxt expr]
|
||||
|
||||
@ -116,10 +120,10 @@ let disambiguate_constructor
|
||||
disambiguate the scope and subscopes variables than occur in the expresion *)
|
||||
let rec translate_expr
|
||||
(scope : Scopelang.Ast.ScopeName.t)
|
||||
(inside_definition_of : Desugared.Ast.ScopeDef.t Pos.marked option)
|
||||
(inside_definition_of : Desugared.Ast.ScopeDef.t Marked.pos option)
|
||||
(ctxt : Name_resolution.context)
|
||||
((expr, pos) : Ast.expression Pos.marked) :
|
||||
Desugared.Ast.expr Pos.marked Bindlib.box =
|
||||
((expr, pos) : Ast.expression Marked.pos) :
|
||||
Desugared.Ast.expr Marked.pos Bindlib.box =
|
||||
let scope_ctxt = Scopelang.Ast.ScopeMap.find scope ctxt.scopes in
|
||||
let rec_helper = translate_expr scope inside_definition_of ctxt in
|
||||
match expr with
|
||||
@ -137,18 +141,18 @@ let rec translate_expr
|
||||
Scopelang.Ast.EnumConstructorMap.mapi
|
||||
(fun c_uid' tau ->
|
||||
if Scopelang.Ast.EnumConstructor.compare c_uid c_uid' <> 0 then
|
||||
let nop_var = Desugared.Ast.Var.make ("_", pos) in
|
||||
let nop_var = Desugared.Ast.Var.make "_" in
|
||||
Bindlib.unbox
|
||||
(Desugared.Ast.make_abs [| nop_var |]
|
||||
(Bindlib.box (Desugared.Ast.ELit (Dcalc.Ast.LBool false), pos))
|
||||
pos [tau] pos)
|
||||
[tau] pos)
|
||||
else
|
||||
let ctxt, binding_var =
|
||||
Name_resolution.add_def_local_var ctxt binding
|
||||
Name_resolution.add_def_local_var ctxt (Marked.unmark binding)
|
||||
in
|
||||
let e2 = translate_expr scope inside_definition_of ctxt e2 in
|
||||
Bindlib.unbox
|
||||
(Desugared.Ast.make_abs [| binding_var |] e2 pos [tau] pos))
|
||||
(Desugared.Ast.make_abs [| binding_var |] e2 [tau] pos))
|
||||
(Scopelang.Ast.EnumMap.find enum_uid ctxt.enums)
|
||||
in
|
||||
Bindlib.box_apply
|
||||
@ -161,8 +165,9 @@ let rec translate_expr
|
||||
(rec_helper e_if) (rec_helper e_then) (rec_helper e_else)
|
||||
| Binop (op, e1, e2) ->
|
||||
let op_term =
|
||||
Pos.same_pos_as
|
||||
(Desugared.Ast.EOp (Dcalc.Ast.Binop (translate_binop (Pos.unmark op))))
|
||||
Marked.same_mark_as
|
||||
(Desugared.Ast.EOp
|
||||
(Dcalc.Ast.Binop (translate_binop (Marked.unmark op))))
|
||||
op
|
||||
in
|
||||
Bindlib.box_apply2
|
||||
@ -170,8 +175,8 @@ let rec translate_expr
|
||||
(rec_helper e1) (rec_helper e2)
|
||||
| Unop (op, e) ->
|
||||
let op_term =
|
||||
Pos.same_pos_as
|
||||
(Desugared.Ast.EOp (Dcalc.Ast.Unop (translate_unop (Pos.unmark op))))
|
||||
Marked.same_mark_as
|
||||
(Desugared.Ast.EOp (Dcalc.Ast.Unop (translate_unop (Marked.unmark op))))
|
||||
op
|
||||
in
|
||||
Bindlib.box_apply
|
||||
@ -218,21 +223,17 @@ let rec translate_expr
|
||||
Errors.raise_spanned_error pos
|
||||
"Impossible to specify decimal amounts of days, months or years"
|
||||
| LDate date ->
|
||||
if Pos.unmark date.literal_date_month > 12 then
|
||||
Errors.raise_spanned_error
|
||||
(Pos.get_position date.literal_date_month)
|
||||
if date.literal_date_month > 12 then
|
||||
Errors.raise_spanned_error pos
|
||||
"There is an error in this date: the month number is bigger than 12";
|
||||
if Pos.unmark date.literal_date_day > 31 then
|
||||
Errors.raise_spanned_error
|
||||
(Pos.get_position date.literal_date_day)
|
||||
if date.literal_date_day > 31 then
|
||||
Errors.raise_spanned_error pos
|
||||
"There is an error in this date: the day number is bigger than 31";
|
||||
Desugared.Ast.ELit
|
||||
(Dcalc.Ast.LDate
|
||||
(try
|
||||
Runtime.date_of_numbers
|
||||
(Pos.unmark date.literal_date_year)
|
||||
(Pos.unmark date.literal_date_month)
|
||||
(Pos.unmark date.literal_date_day)
|
||||
Runtime.date_of_numbers date.literal_date_year
|
||||
date.literal_date_month date.literal_date_day
|
||||
with Runtime.ImpossibleDate ->
|
||||
Errors.raise_spanned_error pos
|
||||
"There is an error in this date, it does not correspond to a \
|
||||
@ -300,11 +301,11 @@ let rec translate_expr
|
||||
Desugared.Ast.make_var (uid, pos)
|
||||
(* the whole box thing is to accomodate for this case *))
|
||||
| Dotted (e, c, x) -> (
|
||||
match Pos.unmark e with
|
||||
match Marked.unmark e with
|
||||
| Ident y when Name_resolution.is_subscope_uid scope ctxt y ->
|
||||
(* In this case, y.x is a subscope variable *)
|
||||
let subscope_uid : Scopelang.Ast.SubScopeName.t =
|
||||
Name_resolution.get_subscope_uid scope ctxt (Pos.same_pos_as y e)
|
||||
Name_resolution.get_subscope_uid scope ctxt (Marked.same_mark_as y e)
|
||||
in
|
||||
let subscope_real_uid : Scopelang.Ast.ScopeName.t =
|
||||
Scopelang.Ast.SubScopeMap.find subscope_uid scope_ctxt.sub_scopes
|
||||
@ -321,16 +322,16 @@ let rec translate_expr
|
||||
(* In this case e.x is the struct field x access of expression e *)
|
||||
let e = translate_expr scope inside_definition_of ctxt e in
|
||||
let x_possible_structs =
|
||||
try Desugared.Ast.IdentMap.find (Pos.unmark x) ctxt.field_idmap
|
||||
try Desugared.Ast.IdentMap.find (Marked.unmark x) ctxt.field_idmap
|
||||
with Not_found ->
|
||||
Errors.raise_spanned_error (Pos.get_position x)
|
||||
Errors.raise_spanned_error (Marked.get_mark x)
|
||||
"Unknown subscope or struct field name"
|
||||
in
|
||||
match c with
|
||||
| None ->
|
||||
(* No constructor name was specified *)
|
||||
if Scopelang.Ast.StructMap.cardinal x_possible_structs > 1 then
|
||||
Errors.raise_spanned_error (Pos.get_position x)
|
||||
Errors.raise_spanned_error (Marked.get_mark x)
|
||||
"This struct field name is ambiguous, it can belong to %a. \
|
||||
Disambiguate it by prefixing it with the struct name."
|
||||
(Format.pp_print_list
|
||||
@ -349,7 +350,7 @@ let rec translate_expr
|
||||
| Some c_name -> (
|
||||
try
|
||||
let c_uid =
|
||||
Desugared.Ast.IdentMap.find (Pos.unmark c_name) ctxt.struct_idmap
|
||||
Desugared.Ast.IdentMap.find (Marked.unmark c_name) ctxt.struct_idmap
|
||||
in
|
||||
try
|
||||
let f_uid = Scopelang.Ast.StructMap.find c_uid x_possible_structs in
|
||||
@ -358,19 +359,19 @@ let rec translate_expr
|
||||
e
|
||||
with Not_found ->
|
||||
Errors.raise_spanned_error pos "Struct %s does not contain field %s"
|
||||
(Pos.unmark c_name) (Pos.unmark x)
|
||||
(Marked.unmark c_name) (Marked.unmark x)
|
||||
with Not_found ->
|
||||
Errors.raise_spanned_error (Pos.get_position c_name)
|
||||
"Struct %s has not been defined before" (Pos.unmark c_name))))
|
||||
Errors.raise_spanned_error (Marked.get_mark c_name)
|
||||
"Struct %s has not been defined before" (Marked.unmark c_name))))
|
||||
| FunCall (f, arg) ->
|
||||
Bindlib.box_apply2
|
||||
(fun f arg -> Desugared.Ast.EApp (f, [arg]), pos)
|
||||
(rec_helper f) (rec_helper arg)
|
||||
| StructLit (s_name, fields) ->
|
||||
let s_uid =
|
||||
try Desugared.Ast.IdentMap.find (Pos.unmark s_name) ctxt.struct_idmap
|
||||
try Desugared.Ast.IdentMap.find (Marked.unmark s_name) ctxt.struct_idmap
|
||||
with Not_found ->
|
||||
Errors.raise_spanned_error (Pos.get_position s_name)
|
||||
Errors.raise_spanned_error (Marked.get_mark s_name)
|
||||
"This identifier should refer to a struct name"
|
||||
in
|
||||
|
||||
@ -380,20 +381,20 @@ let rec translate_expr
|
||||
let f_uid =
|
||||
try
|
||||
Scopelang.Ast.StructMap.find s_uid
|
||||
(Desugared.Ast.IdentMap.find (Pos.unmark f_name)
|
||||
(Desugared.Ast.IdentMap.find (Marked.unmark f_name)
|
||||
ctxt.field_idmap)
|
||||
with Not_found ->
|
||||
Errors.raise_spanned_error (Pos.get_position f_name)
|
||||
Errors.raise_spanned_error (Marked.get_mark f_name)
|
||||
"This identifier should refer to a field of struct %s"
|
||||
(Pos.unmark s_name)
|
||||
(Marked.unmark s_name)
|
||||
in
|
||||
(match Scopelang.Ast.StructFieldMap.find_opt f_uid s_fields with
|
||||
| None -> ()
|
||||
| Some e_field ->
|
||||
Errors.raise_multispanned_error
|
||||
[
|
||||
None, Pos.get_position f_e;
|
||||
None, Pos.get_position (Bindlib.unbox e_field);
|
||||
None, Marked.get_mark f_e;
|
||||
None, Marked.get_mark (Bindlib.unbox e_field);
|
||||
]
|
||||
"The field %a has been defined twice:"
|
||||
Scopelang.Ast.StructFieldName.format_t f_uid);
|
||||
@ -417,11 +418,12 @@ let rec translate_expr
|
||||
| EnumInject (enum, constructor, payload) -> (
|
||||
let possible_c_uids =
|
||||
try
|
||||
Desugared.Ast.IdentMap.find (Pos.unmark constructor)
|
||||
Desugared.Ast.IdentMap.find
|
||||
(Marked.unmark constructor)
|
||||
ctxt.constructor_idmap
|
||||
with Not_found ->
|
||||
Errors.raise_spanned_error
|
||||
(Pos.get_position constructor)
|
||||
(Marked.get_mark constructor)
|
||||
"The name of this constructor has not been defined before, maybe it \
|
||||
is a typo?"
|
||||
in
|
||||
@ -433,7 +435,7 @@ let rec translate_expr
|
||||
Scopelang.Ast.EnumMap.cardinal possible_c_uids > 1
|
||||
then
|
||||
Errors.raise_spanned_error
|
||||
(Pos.get_position constructor)
|
||||
(Marked.get_mark constructor)
|
||||
"This constructor name is ambiguous, it can belong to %a. \
|
||||
Desambiguate it by prefixing it with the enum name."
|
||||
(Format.pp_print_list
|
||||
@ -453,7 +455,7 @@ let rec translate_expr
|
||||
| Some e' -> e'
|
||||
| None ->
|
||||
( Desugared.Ast.ELit Dcalc.Ast.LUnit,
|
||||
Pos.get_position constructor )),
|
||||
Marked.get_mark constructor )),
|
||||
c_uid,
|
||||
e_uid ),
|
||||
pos ))
|
||||
@ -462,7 +464,7 @@ let rec translate_expr
|
||||
try
|
||||
(* The path has been fully qualified *)
|
||||
let e_uid =
|
||||
Desugared.Ast.IdentMap.find (Pos.unmark enum) ctxt.enum_idmap
|
||||
Desugared.Ast.IdentMap.find (Marked.unmark enum) ctxt.enum_idmap
|
||||
in
|
||||
try
|
||||
let c_uid = Scopelang.Ast.EnumMap.find e_uid possible_c_uids in
|
||||
@ -476,17 +478,18 @@ let rec translate_expr
|
||||
| Some e' -> e'
|
||||
| None ->
|
||||
( Desugared.Ast.ELit Dcalc.Ast.LUnit,
|
||||
Pos.get_position constructor )),
|
||||
Marked.get_mark constructor )),
|
||||
c_uid,
|
||||
e_uid ),
|
||||
pos ))
|
||||
(Bindlib.box_opt payload)
|
||||
with Not_found ->
|
||||
Errors.raise_spanned_error pos "Enum %s does not contain case %s"
|
||||
(Pos.unmark enum) (Pos.unmark constructor)
|
||||
(Marked.unmark enum)
|
||||
(Marked.unmark constructor)
|
||||
with Not_found ->
|
||||
Errors.raise_spanned_error (Pos.get_position enum)
|
||||
"Enum %s has not been defined before" (Pos.unmark enum)))
|
||||
Errors.raise_spanned_error (Marked.get_mark enum)
|
||||
"Enum %s has not been defined before" (Marked.unmark enum)))
|
||||
| MatchWith (e1, (cases, _cases_pos)) ->
|
||||
let e1 = translate_expr scope inside_definition_of ctxt e1 in
|
||||
let cases_d, e_uid =
|
||||
@ -498,20 +501,20 @@ let rec translate_expr
|
||||
e1
|
||||
(LiftEnumConstructorMap.lift_box cases_d)
|
||||
| TestMatchCase (e1, pattern) ->
|
||||
(match snd (Pos.unmark pattern) with
|
||||
(match snd (Marked.unmark pattern) with
|
||||
| None -> ()
|
||||
| Some binding ->
|
||||
Errors.format_spanned_warning (Pos.get_position binding)
|
||||
Errors.format_spanned_warning (Marked.get_mark binding)
|
||||
"This binding will be ignored (remove it to suppress warning)");
|
||||
let enum_uid, c_uid =
|
||||
disambiguate_constructor ctxt
|
||||
(fst (Pos.unmark pattern))
|
||||
(Pos.get_position pattern)
|
||||
(fst (Marked.unmark pattern))
|
||||
(Marked.get_mark pattern)
|
||||
in
|
||||
let cases =
|
||||
Scopelang.Ast.EnumConstructorMap.mapi
|
||||
(fun c_uid' tau ->
|
||||
let nop_var = Desugared.Ast.Var.make ("_", pos) in
|
||||
let nop_var = Desugared.Ast.Var.make "_" in
|
||||
Bindlib.unbox
|
||||
(Desugared.Ast.make_abs [| nop_var |]
|
||||
(Bindlib.box
|
||||
@ -519,7 +522,7 @@ let rec translate_expr
|
||||
(Dcalc.Ast.LBool
|
||||
(Scopelang.Ast.EnumConstructor.compare c_uid c_uid' = 0)),
|
||||
pos ))
|
||||
pos [tau] pos))
|
||||
[tau] pos))
|
||||
(Scopelang.Ast.EnumMap.find enum_uid ctxt.enums)
|
||||
in
|
||||
Bindlib.box_apply
|
||||
@ -535,11 +538,12 @@ let rec translate_expr
|
||||
collection,
|
||||
predicate ) ->
|
||||
let collection = rec_helper collection in
|
||||
let ctxt, param = Name_resolution.add_def_local_var ctxt param' in
|
||||
let ctxt, param =
|
||||
Name_resolution.add_def_local_var ctxt (Marked.unmark param')
|
||||
in
|
||||
let f_pred =
|
||||
Desugared.Ast.make_abs [| param |]
|
||||
(translate_expr scope inside_definition_of ctxt predicate)
|
||||
pos
|
||||
[Scopelang.Ast.TAny, pos]
|
||||
pos
|
||||
in
|
||||
@ -563,7 +567,9 @@ let rec translate_expr
|
||||
predicate ) ->
|
||||
let init = rec_helper init in
|
||||
let collection = rec_helper collection in
|
||||
let ctxt, param = Name_resolution.add_def_local_var ctxt param' in
|
||||
let ctxt, param =
|
||||
Name_resolution.add_def_local_var ctxt (Marked.unmark param')
|
||||
in
|
||||
let op_kind =
|
||||
match pred_typ with
|
||||
| Ast.Integer -> Dcalc.Ast.KInt
|
||||
@ -583,25 +589,19 @@ let rec translate_expr
|
||||
let f_pred =
|
||||
Desugared.Ast.make_abs [| param |]
|
||||
(translate_expr scope inside_definition_of ctxt predicate)
|
||||
pos
|
||||
[Scopelang.Ast.TAny, pos]
|
||||
pos
|
||||
in
|
||||
let f_pred_var =
|
||||
Desugared.Ast.Var.make ("predicate", Pos.get_position predicate)
|
||||
in
|
||||
let f_pred_var = Desugared.Ast.Var.make "predicate" in
|
||||
let f_pred_var_e =
|
||||
Desugared.Ast.make_var (f_pred_var, Pos.get_position predicate)
|
||||
Desugared.Ast.make_var (f_pred_var, Marked.get_mark predicate)
|
||||
in
|
||||
let acc_var = Desugared.Ast.Var.make ("acc", pos) in
|
||||
let acc_var = Desugared.Ast.Var.make "acc" in
|
||||
let acc_var_e = Desugared.Ast.make_var (acc_var, pos) in
|
||||
let item_var =
|
||||
Desugared.Ast.Var.make
|
||||
("item", Pos.get_position (Bindlib.unbox collection))
|
||||
in
|
||||
let item_var = Desugared.Ast.Var.make "item" in
|
||||
let item_var_e =
|
||||
Desugared.Ast.make_var
|
||||
(item_var, Pos.get_position (Bindlib.unbox collection))
|
||||
(item_var, Marked.get_mark (Bindlib.unbox collection))
|
||||
in
|
||||
let fold_body =
|
||||
Bindlib.box_apply3
|
||||
@ -620,7 +620,7 @@ let rec translate_expr
|
||||
acc_var_e item_var_e f_pred_var_e
|
||||
in
|
||||
let fold_f =
|
||||
Desugared.Ast.make_abs [| acc_var; item_var |] fold_body pos
|
||||
Desugared.Ast.make_abs [| acc_var; item_var |] fold_body
|
||||
[Scopelang.Ast.TAny, pos; Scopelang.Ast.TAny, pos]
|
||||
pos
|
||||
in
|
||||
@ -635,37 +635,39 @@ let rec translate_expr
|
||||
in
|
||||
Desugared.Ast.make_let_in f_pred_var (Scopelang.Ast.TAny, pos) f_pred fold
|
||||
| CollectionOp (op', param', collection, predicate) ->
|
||||
let ctxt, param = Name_resolution.add_def_local_var ctxt param' in
|
||||
let ctxt, param =
|
||||
Name_resolution.add_def_local_var ctxt (Marked.unmark param')
|
||||
in
|
||||
let collection = rec_helper collection in
|
||||
let init =
|
||||
match Pos.unmark op' with
|
||||
match Marked.unmark op' with
|
||||
| Ast.Map | Ast.Filter | Ast.Aggregate (Ast.AggregateArgExtremum _) ->
|
||||
assert false (* should not happen *)
|
||||
| Ast.Exists ->
|
||||
Bindlib.box
|
||||
(Desugared.Ast.ELit (Dcalc.Ast.LBool false), Pos.get_position op')
|
||||
(Desugared.Ast.ELit (Dcalc.Ast.LBool false), Marked.get_mark op')
|
||||
| Ast.Forall ->
|
||||
Bindlib.box
|
||||
(Desugared.Ast.ELit (Dcalc.Ast.LBool true), Pos.get_position op')
|
||||
(Desugared.Ast.ELit (Dcalc.Ast.LBool true), Marked.get_mark op')
|
||||
| Ast.Aggregate (Ast.AggregateSum Ast.Integer) ->
|
||||
Bindlib.box
|
||||
( Desugared.Ast.ELit (Dcalc.Ast.LInt (Runtime.integer_of_int 0)),
|
||||
Pos.get_position op' )
|
||||
Marked.get_mark op' )
|
||||
| Ast.Aggregate (Ast.AggregateSum Ast.Decimal) ->
|
||||
Bindlib.box
|
||||
( Desugared.Ast.ELit (Dcalc.Ast.LRat (Runtime.decimal_of_string "0")),
|
||||
Pos.get_position op' )
|
||||
Marked.get_mark op' )
|
||||
| Ast.Aggregate (Ast.AggregateSum Ast.Money) ->
|
||||
Bindlib.box
|
||||
( Desugared.Ast.ELit
|
||||
(Dcalc.Ast.LMoney
|
||||
(Runtime.money_of_cents_integer (Runtime.integer_of_int 0))),
|
||||
Pos.get_position op' )
|
||||
Marked.get_mark op' )
|
||||
| Ast.Aggregate (Ast.AggregateSum Ast.Duration) ->
|
||||
Bindlib.box
|
||||
( Desugared.Ast.ELit
|
||||
(Dcalc.Ast.LDuration (Runtime.duration_of_numbers 0 0 0)),
|
||||
Pos.get_position op' )
|
||||
Marked.get_mark op' )
|
||||
| Ast.Aggregate (Ast.AggregateSum t) ->
|
||||
Errors.raise_spanned_error pos
|
||||
"It is impossible to sum two values of type %a together"
|
||||
@ -674,16 +676,16 @@ let rec translate_expr
|
||||
| Ast.Aggregate Ast.AggregateCount ->
|
||||
Bindlib.box
|
||||
( Desugared.Ast.ELit (Dcalc.Ast.LInt (Runtime.integer_of_int 0)),
|
||||
Pos.get_position op' )
|
||||
Marked.get_mark op' )
|
||||
in
|
||||
let acc_var = Desugared.Ast.Var.make ("acc", Pos.get_position param') in
|
||||
let acc = Desugared.Ast.make_var (acc_var, Pos.get_position param') in
|
||||
let acc_var = Desugared.Ast.Var.make "acc" in
|
||||
let acc = Desugared.Ast.make_var (acc_var, Marked.get_mark param') in
|
||||
let f_body =
|
||||
let make_body (op : Dcalc.Ast.binop) =
|
||||
Bindlib.box_apply2
|
||||
(fun predicate acc ->
|
||||
( Desugared.Ast.EApp
|
||||
( (Desugared.Ast.EOp (Dcalc.Ast.Binop op), Pos.get_position op'),
|
||||
( (Desugared.Ast.EOp (Dcalc.Ast.Binop op), Marked.get_mark op'),
|
||||
[acc; predicate] ),
|
||||
pos ))
|
||||
(translate_expr scope inside_definition_of ctxt predicate)
|
||||
@ -691,9 +693,9 @@ let rec translate_expr
|
||||
in
|
||||
let make_extr_body
|
||||
(cmp_op : Dcalc.Ast.binop)
|
||||
(t : Scopelang.Ast.typ Pos.marked) =
|
||||
let tmp_var = Desugared.Ast.Var.make ("tmp", Pos.get_position param') in
|
||||
let tmp = Desugared.Ast.make_var (tmp_var, Pos.get_position param') in
|
||||
(t : Scopelang.Ast.typ Marked.pos) =
|
||||
let tmp_var = Desugared.Ast.Var.make "tmp" in
|
||||
let tmp = Desugared.Ast.make_var (tmp_var, Marked.get_mark param') in
|
||||
Desugared.Ast.make_let_in tmp_var t
|
||||
(translate_expr scope inside_definition_of ctxt predicate)
|
||||
(Bindlib.box_apply2
|
||||
@ -701,7 +703,7 @@ let rec translate_expr
|
||||
( Desugared.Ast.EIfThenElse
|
||||
( ( Desugared.Ast.EApp
|
||||
( ( Desugared.Ast.EOp (Dcalc.Ast.Binop cmp_op),
|
||||
Pos.get_position op' ),
|
||||
Marked.get_mark op' ),
|
||||
[acc; tmp] ),
|
||||
pos ),
|
||||
acc,
|
||||
@ -709,7 +711,7 @@ let rec translate_expr
|
||||
pos ))
|
||||
acc tmp)
|
||||
in
|
||||
match Pos.unmark op' with
|
||||
match Marked.unmark op' with
|
||||
| Ast.Map | Ast.Filter | Ast.Aggregate (Ast.AggregateArgExtremum _) ->
|
||||
assert false (* should not happen *)
|
||||
| Ast.Exists -> make_body Dcalc.Ast.Or
|
||||
@ -751,12 +753,12 @@ let rec translate_expr
|
||||
( Desugared.Ast.EApp
|
||||
( ( Desugared.Ast.EOp
|
||||
(Dcalc.Ast.Binop (Dcalc.Ast.Add Dcalc.Ast.KInt)),
|
||||
Pos.get_position op' ),
|
||||
Marked.get_mark op' ),
|
||||
[
|
||||
acc;
|
||||
( Desugared.Ast.ELit
|
||||
(Dcalc.Ast.LInt (Runtime.integer_of_int 1)),
|
||||
Pos.get_position predicate );
|
||||
Marked.get_mark predicate );
|
||||
] ),
|
||||
pos ),
|
||||
acc ),
|
||||
@ -769,9 +771,9 @@ let rec translate_expr
|
||||
Bindlib.box_apply
|
||||
(fun binder ->
|
||||
( Desugared.Ast.EAbs
|
||||
( (binder, pos),
|
||||
( binder,
|
||||
[
|
||||
Scopelang.Ast.TLit t, Pos.get_position op';
|
||||
Scopelang.Ast.TLit t, Marked.get_mark op';
|
||||
Scopelang.Ast.TAny, pos
|
||||
(* we put any here because the type of the elements of the
|
||||
arrays is not always the type of the accumulator; for
|
||||
@ -780,7 +782,7 @@ let rec translate_expr
|
||||
pos ))
|
||||
(Bindlib.bind_mvar [| acc_var; param |] f_body)
|
||||
in
|
||||
match Pos.unmark op' with
|
||||
match Marked.unmark op' with
|
||||
| Ast.Map | Ast.Filter | Ast.Aggregate (Ast.AggregateArgExtremum _) ->
|
||||
assert false (* should not happen *)
|
||||
| Ast.Exists -> make_f Dcalc.Ast.TBool
|
||||
@ -810,11 +812,11 @@ let rec translate_expr
|
||||
pos ))
|
||||
f collection init
|
||||
| MemCollection (member, collection) ->
|
||||
let param_var = Desugared.Ast.Var.make ("collection_member", pos) in
|
||||
let param_var = Desugared.Ast.Var.make "collection_member" in
|
||||
let param = Desugared.Ast.make_var (param_var, pos) in
|
||||
let collection = rec_helper collection in
|
||||
let init = Bindlib.box (Desugared.Ast.ELit (Dcalc.Ast.LBool false), pos) in
|
||||
let acc_var = Desugared.Ast.Var.make ("acc", pos) in
|
||||
let acc_var = Desugared.Ast.Var.make "acc" in
|
||||
let acc = Desugared.Ast.make_var (acc_var, pos) in
|
||||
let f_body =
|
||||
Bindlib.box_apply3
|
||||
@ -836,7 +838,7 @@ let rec translate_expr
|
||||
Bindlib.box_apply
|
||||
(fun binder ->
|
||||
( Desugared.Ast.EAbs
|
||||
( (binder, pos),
|
||||
( binder,
|
||||
[
|
||||
Scopelang.Ast.TLit Dcalc.Ast.TBool, pos;
|
||||
Scopelang.Ast.TAny, pos;
|
||||
@ -853,6 +855,10 @@ let rec translate_expr
|
||||
f collection init
|
||||
| Builtin IntToDec ->
|
||||
Bindlib.box (Desugared.Ast.EOp (Dcalc.Ast.Unop Dcalc.Ast.IntToRat), pos)
|
||||
| Builtin MoneyToDec ->
|
||||
Bindlib.box (Desugared.Ast.EOp (Dcalc.Ast.Unop Dcalc.Ast.MoneyToRat), pos)
|
||||
| Builtin DecToMoney ->
|
||||
Bindlib.box (Desugared.Ast.EOp (Dcalc.Ast.Unop Dcalc.Ast.RatToMoney), pos)
|
||||
| Builtin Cardinal ->
|
||||
Bindlib.box (Desugared.Ast.EOp (Dcalc.Ast.Unop Dcalc.Ast.Length), pos)
|
||||
| Builtin GetDay ->
|
||||
@ -861,6 +867,12 @@ let rec translate_expr
|
||||
Bindlib.box (Desugared.Ast.EOp (Dcalc.Ast.Unop Dcalc.Ast.GetMonth), pos)
|
||||
| Builtin GetYear ->
|
||||
Bindlib.box (Desugared.Ast.EOp (Dcalc.Ast.Unop Dcalc.Ast.GetYear), pos)
|
||||
| Builtin FirstDayOfMonth ->
|
||||
Bindlib.box
|
||||
(Desugared.Ast.EOp (Dcalc.Ast.Unop Dcalc.Ast.FirstDayOfMonth), pos)
|
||||
| Builtin LastDayOfMonth ->
|
||||
Bindlib.box
|
||||
(Desugared.Ast.EOp (Dcalc.Ast.Unop Dcalc.Ast.LastDayOfMonth), pos)
|
||||
| Builtin RoundMoney ->
|
||||
Bindlib.box (Desugared.Ast.EOp (Dcalc.Ast.Unop Dcalc.Ast.RoundMoney), pos)
|
||||
| Builtin RoundDecimal ->
|
||||
@ -868,31 +880,30 @@ let rec translate_expr
|
||||
|
||||
and disambiguate_match_and_build_expression
|
||||
(scope : Scopelang.Ast.ScopeName.t)
|
||||
(inside_definition_of : Desugared.Ast.ScopeDef.t Pos.marked option)
|
||||
(inside_definition_of : Desugared.Ast.ScopeDef.t Marked.pos option)
|
||||
(ctxt : Name_resolution.context)
|
||||
(cases : Ast.match_case Pos.marked list) :
|
||||
Desugared.Ast.expr Pos.marked Bindlib.box Scopelang.Ast.EnumConstructorMap.t
|
||||
(cases : Ast.match_case Marked.pos list) :
|
||||
Desugared.Ast.expr Marked.pos Bindlib.box Scopelang.Ast.EnumConstructorMap.t
|
||||
* Scopelang.Ast.EnumName.t =
|
||||
let create_var = function
|
||||
| None -> ctxt, (Desugared.Ast.Var.make ("_", Pos.no_pos), Pos.no_pos)
|
||||
| None -> ctxt, Desugared.Ast.Var.make "_"
|
||||
| Some param ->
|
||||
let ctxt, param_var = Name_resolution.add_def_local_var ctxt param in
|
||||
ctxt, (param_var, Pos.get_position param)
|
||||
ctxt, param_var
|
||||
in
|
||||
let bind_case_body
|
||||
(c_uid : Dcalc.Ast.EnumConstructor.t)
|
||||
(e_uid : Dcalc.Ast.EnumName.t)
|
||||
(ctxt : Name_resolution.context)
|
||||
(param_pos : Pos.t)
|
||||
(case_body : ('a * Pos.t) Bindlib.box)
|
||||
(e_binder :
|
||||
(Desugared.Ast.expr, Desugared.Ast.expr * Pos.t) Bindlib.mbinder
|
||||
Bindlib.box) : 'c Bindlib.box =
|
||||
Bindlib.box_apply2
|
||||
(fun e_binder case_body ->
|
||||
Pos.same_pos_as
|
||||
Marked.same_mark_as
|
||||
(Desugared.Ast.EAbs
|
||||
( (e_binder, param_pos),
|
||||
( e_binder,
|
||||
[
|
||||
Scopelang.Ast.EnumConstructorMap.find c_uid
|
||||
(Scopelang.Ast.EnumMap.find e_uid ctxt.Name_resolution.enums);
|
||||
@ -903,10 +914,10 @@ and disambiguate_match_and_build_expression
|
||||
let bind_match_cases (cases_d, e_uid, curr_index) (case, case_pos) =
|
||||
match case with
|
||||
| Ast.MatchCase case ->
|
||||
let constructor, binding = Pos.unmark case.Ast.match_case_pattern in
|
||||
let constructor, binding = Marked.unmark case.Ast.match_case_pattern in
|
||||
let e_uid', c_uid =
|
||||
disambiguate_constructor ctxt constructor
|
||||
(Pos.get_position case.Ast.match_case_pattern)
|
||||
(Marked.get_mark case.Ast.match_case_pattern)
|
||||
in
|
||||
let e_uid =
|
||||
match e_uid with
|
||||
@ -915,7 +926,7 @@ and disambiguate_match_and_build_expression
|
||||
if e_uid = e_uid' then e_uid
|
||||
else
|
||||
Errors.raise_spanned_error
|
||||
(Pos.get_position case.Ast.match_case_pattern)
|
||||
(Marked.get_mark case.Ast.match_case_pattern)
|
||||
"This case matches a constructor of enumeration %a but previous \
|
||||
case were matching constructors of enumeration %a"
|
||||
Scopelang.Ast.EnumName.format_t e_uid
|
||||
@ -926,19 +937,17 @@ and disambiguate_match_and_build_expression
|
||||
| Some e_case ->
|
||||
Errors.raise_multispanned_error
|
||||
[
|
||||
None, Pos.get_position case.match_case_expr;
|
||||
None, Pos.get_position (Bindlib.unbox e_case);
|
||||
None, Marked.get_mark case.match_case_expr;
|
||||
None, Marked.get_mark (Bindlib.unbox e_case);
|
||||
]
|
||||
"The constructor %a has been matched twice:"
|
||||
Scopelang.Ast.EnumConstructor.format_t c_uid);
|
||||
let ctxt, (param_var, param_pos) = create_var binding in
|
||||
let ctxt, param_var = create_var (Option.map Marked.unmark binding) in
|
||||
let case_body =
|
||||
translate_expr scope inside_definition_of ctxt case.Ast.match_case_expr
|
||||
in
|
||||
let e_binder = Bindlib.bind_mvar (Array.of_list [param_var]) case_body in
|
||||
let case_expr =
|
||||
bind_case_body c_uid e_uid ctxt param_pos case_body e_binder
|
||||
in
|
||||
let case_expr = bind_case_body c_uid e_uid ctxt case_body e_binder in
|
||||
( Scopelang.Ast.EnumConstructorMap.add c_uid case_expr cases_d,
|
||||
Some e_uid,
|
||||
curr_index + 1 )
|
||||
@ -949,7 +958,7 @@ and disambiguate_match_and_build_expression
|
||||
[
|
||||
Some "Not ending wildcard:", case_pos;
|
||||
( Some "Next reachable case:",
|
||||
curr_index + 1 |> List.nth cases |> Pos.get_position );
|
||||
curr_index + 1 |> List.nth cases |> Marked.get_mark );
|
||||
]
|
||||
"Wildcard must be the last match case"
|
||||
in
|
||||
@ -988,7 +997,7 @@ and disambiguate_match_and_build_expression
|
||||
...
|
||||
| CaseN -> wildcard_payload *)
|
||||
(* Creates the wildcard payload *)
|
||||
let ctxt, (payload_var, var_pos) = create_var None in
|
||||
let ctxt, payload_var = create_var None in
|
||||
let case_body =
|
||||
translate_expr scope inside_definition_of ctxt match_case_expr
|
||||
in
|
||||
@ -1000,7 +1009,7 @@ and disambiguate_match_and_build_expression
|
||||
Scopelang.Ast.EnumConstructorMap.fold
|
||||
(fun c_uid _ (cases_d, e_uid_opt, curr_index) ->
|
||||
let case_expr =
|
||||
bind_case_body c_uid e_uid ctxt var_pos case_body e_binder
|
||||
bind_case_body c_uid e_uid ctxt case_body e_binder
|
||||
in
|
||||
( Scopelang.Ast.EnumConstructorMap.add c_uid case_expr cases_d,
|
||||
e_uid_opt,
|
||||
@ -1022,21 +1031,23 @@ and disambiguate_match_and_build_expression
|
||||
this precondition has to be appended to the justifications of each
|
||||
definition in the subscope use. This is what this function does. *)
|
||||
let merge_conditions
|
||||
(precond : Desugared.Ast.expr Pos.marked Bindlib.box option)
|
||||
(cond : Desugared.Ast.expr Pos.marked Bindlib.box option)
|
||||
(default_pos : Pos.t) : Desugared.Ast.expr Pos.marked Bindlib.box =
|
||||
(precond : Desugared.Ast.expr Marked.pos Bindlib.box option)
|
||||
(cond : Desugared.Ast.expr Marked.pos Bindlib.box option)
|
||||
(default_pos : Pos.t) : Desugared.Ast.expr Marked.pos Bindlib.box =
|
||||
match precond, cond with
|
||||
| Some precond, Some cond ->
|
||||
let op_term =
|
||||
( Desugared.Ast.EOp (Dcalc.Ast.Binop Dcalc.Ast.And),
|
||||
Pos.get_position (Bindlib.unbox cond) )
|
||||
Marked.get_mark (Bindlib.unbox cond) )
|
||||
in
|
||||
Bindlib.box_apply2
|
||||
(fun precond cond ->
|
||||
Desugared.Ast.EApp (op_term, [precond; cond]), Pos.get_position cond)
|
||||
Desugared.Ast.EApp (op_term, [precond; cond]), Marked.get_mark cond)
|
||||
precond cond
|
||||
| Some precond, None ->
|
||||
Bindlib.box_apply (fun precond -> Pos.unmark precond, default_pos) precond
|
||||
Bindlib.box_apply
|
||||
(fun precond -> Marked.unmark precond, default_pos)
|
||||
precond
|
||||
| None, Some cond -> cond
|
||||
| None, None ->
|
||||
Bindlib.box (Desugared.Ast.ELit (Dcalc.Ast.LBool true), default_pos)
|
||||
@ -1046,47 +1057,49 @@ let merge_conditions
|
||||
let process_default
|
||||
(ctxt : Name_resolution.context)
|
||||
(scope : Scopelang.Ast.ScopeName.t)
|
||||
(def_key : Desugared.Ast.ScopeDef.t Pos.marked)
|
||||
(def_key : Desugared.Ast.ScopeDef.t Marked.pos)
|
||||
(rule_id : Desugared.Ast.RuleName.t)
|
||||
(param_uid : Desugared.Ast.Var.t Pos.marked option)
|
||||
(precond : Desugared.Ast.expr Pos.marked Bindlib.box option)
|
||||
(exception_to_rules : Desugared.Ast.RuleSet.t Pos.marked)
|
||||
(just : Ast.expression Pos.marked option)
|
||||
(cons : Ast.expression Pos.marked) : Desugared.Ast.rule =
|
||||
(param_uid : Desugared.Ast.Var.t Marked.pos option)
|
||||
(precond : Desugared.Ast.expr Marked.pos Bindlib.box option)
|
||||
(exception_situation : Desugared.Ast.exception_situation)
|
||||
(label_situation : Desugared.Ast.label_situation)
|
||||
(just : Ast.expression Marked.pos option)
|
||||
(cons : Ast.expression Marked.pos) : Desugared.Ast.rule =
|
||||
let just =
|
||||
match just with
|
||||
| Some just -> Some (translate_expr scope (Some def_key) ctxt just)
|
||||
| None -> None
|
||||
in
|
||||
let just = merge_conditions precond just (Pos.get_position def_key) in
|
||||
let just = merge_conditions precond just (Marked.get_mark def_key) in
|
||||
let cons = translate_expr scope (Some def_key) ctxt cons in
|
||||
{
|
||||
rule_just = just;
|
||||
rule_cons = cons;
|
||||
rule_parameter =
|
||||
(let def_key_typ =
|
||||
Name_resolution.get_def_typ ctxt (Pos.unmark def_key)
|
||||
Name_resolution.get_def_typ ctxt (Marked.unmark def_key)
|
||||
in
|
||||
match Pos.unmark def_key_typ, param_uid with
|
||||
match Marked.unmark def_key_typ, param_uid with
|
||||
| Scopelang.Ast.TArrow (t_in, _), Some param_uid ->
|
||||
Some (Pos.unmark param_uid, t_in)
|
||||
Some (Marked.unmark param_uid, t_in)
|
||||
| Scopelang.Ast.TArrow _, None ->
|
||||
Errors.raise_spanned_error
|
||||
(Pos.get_position (Bindlib.unbox cons))
|
||||
(Marked.get_mark (Bindlib.unbox cons))
|
||||
"This definition has a function type but the parameter is missing"
|
||||
| _, Some _ ->
|
||||
Errors.raise_spanned_error
|
||||
(Pos.get_position (Bindlib.unbox cons))
|
||||
(Marked.get_mark (Bindlib.unbox cons))
|
||||
"This definition has a parameter but its type is not a function"
|
||||
| _ -> None);
|
||||
rule_exception_to_rules = exception_to_rules;
|
||||
rule_exception = exception_situation;
|
||||
rule_id;
|
||||
rule_label = label_situation;
|
||||
}
|
||||
|
||||
(** Wrapper around {!val: process_default} that performs some name
|
||||
disambiguation *)
|
||||
let process_def
|
||||
(precond : Desugared.Ast.expr Pos.marked Bindlib.box option)
|
||||
(precond : Desugared.Ast.expr Marked.pos Bindlib.box option)
|
||||
(scope_uid : Scopelang.Ast.ScopeName.t)
|
||||
(ctxt : Name_resolution.context)
|
||||
(prgm : Desugared.Ast.program)
|
||||
@ -1097,9 +1110,9 @@ let process_def
|
||||
let scope_ctxt = Scopelang.Ast.ScopeMap.find scope_uid ctxt.scopes in
|
||||
let def_key =
|
||||
Name_resolution.get_def_key
|
||||
(Pos.unmark def.definition_name)
|
||||
(Marked.unmark def.definition_name)
|
||||
def.definition_state scope_uid ctxt
|
||||
(Pos.get_position def.definition_expr)
|
||||
(Marked.get_mark def.definition_expr)
|
||||
in
|
||||
let scope_def_ctxt =
|
||||
Desugared.Ast.ScopeDefMap.find def_key scope_ctxt.scope_defs_contexts
|
||||
@ -1109,36 +1122,45 @@ let process_def
|
||||
match def.definition_parameter with
|
||||
| None -> None, ctxt
|
||||
| Some param ->
|
||||
let ctxt, param_var = Name_resolution.add_def_local_var ctxt param in
|
||||
Some (Pos.same_pos_as param_var param), ctxt
|
||||
let ctxt, param_var =
|
||||
Name_resolution.add_def_local_var ctxt (Marked.unmark param)
|
||||
in
|
||||
Some (Marked.same_mark_as param_var param), ctxt
|
||||
in
|
||||
let scope_updated =
|
||||
let scope_def = Desugared.Ast.ScopeDefMap.find def_key scope.scope_defs in
|
||||
let rule_name = def.definition_id in
|
||||
let parent_rules =
|
||||
let label_situation =
|
||||
match def.definition_label with
|
||||
| Some (label_str, label_pos) ->
|
||||
Desugared.Ast.ExplicitlyLabeled
|
||||
( Desugared.Ast.IdentMap.find label_str scope_def_ctxt.label_idmap,
|
||||
label_pos )
|
||||
| None -> Desugared.Ast.Unlabeled
|
||||
in
|
||||
let exception_situation =
|
||||
match def.Ast.definition_exception_to with
|
||||
| NotAnException ->
|
||||
Desugared.Ast.RuleSet.empty, Pos.get_position def.Ast.definition_name
|
||||
| NotAnException -> Desugared.Ast.BaseCase
|
||||
| UnlabeledException -> (
|
||||
match scope_def_ctxt.default_exception_rulename with
|
||||
(* This should have been caught previously by
|
||||
check_unlabeled_exception *)
|
||||
| None | Some (Name_resolution.Ambiguous _) ->
|
||||
(* This should have been caught previously by
|
||||
check_unlabeled_exception *)
|
||||
assert false (* should not happen *)
|
||||
| Some (Name_resolution.Unique (name, pos)) ->
|
||||
Desugared.Ast.RuleSet.singleton name, pos)
|
||||
| ExceptionToLabel label -> (
|
||||
Desugared.Ast.ExceptionToRule (name, pos))
|
||||
| ExceptionToLabel label_str -> (
|
||||
try
|
||||
let label_id =
|
||||
Desugared.Ast.IdentMap.find (Pos.unmark label)
|
||||
Desugared.Ast.IdentMap.find (Marked.unmark label_str)
|
||||
scope_def_ctxt.label_idmap
|
||||
in
|
||||
( Desugared.Ast.LabelMap.find label_id scope_def.scope_def_label_groups,
|
||||
Pos.get_position def.Ast.definition_name )
|
||||
Desugared.Ast.ExceptionToLabel (label_id, Marked.get_mark label_str)
|
||||
with Not_found ->
|
||||
Errors.raise_spanned_error (Pos.get_position label)
|
||||
Errors.raise_spanned_error
|
||||
(Marked.get_mark label_str)
|
||||
"Unknown label for the scope variable %a: \"%s\""
|
||||
Desugared.Ast.ScopeDef.format_t def_key (Pos.unmark label))
|
||||
Desugared.Ast.ScopeDef.format_t def_key (Marked.unmark label_str))
|
||||
in
|
||||
let scope_def =
|
||||
{
|
||||
@ -1146,9 +1168,9 @@ let process_def
|
||||
scope_def_rules =
|
||||
Desugared.Ast.RuleMap.add rule_name
|
||||
(process_default new_ctxt scope_uid
|
||||
(def_key, Pos.get_position def.definition_name)
|
||||
rule_name param_uid precond parent_rules def.definition_condition
|
||||
def.definition_expr)
|
||||
(def_key, Marked.get_mark def.definition_name)
|
||||
rule_name param_uid precond exception_situation label_situation
|
||||
def.definition_condition def.definition_expr)
|
||||
scope_def.scope_def_rules;
|
||||
}
|
||||
in
|
||||
@ -1166,7 +1188,7 @@ let process_def
|
||||
|
||||
(** Translates a {!type: Surface.Ast.rule} from the surface language *)
|
||||
let process_rule
|
||||
(precond : Desugared.Ast.expr Pos.marked Bindlib.box option)
|
||||
(precond : Desugared.Ast.expr Marked.pos Bindlib.box option)
|
||||
(scope : Scopelang.Ast.ScopeName.t)
|
||||
(ctxt : Name_resolution.context)
|
||||
(prgm : Desugared.Ast.program)
|
||||
@ -1176,7 +1198,7 @@ let process_rule
|
||||
|
||||
(** Translates assertions *)
|
||||
let process_assert
|
||||
(precond : Desugared.Ast.expr Pos.marked Bindlib.box option)
|
||||
(precond : Desugared.Ast.expr Marked.pos Bindlib.box option)
|
||||
(scope_uid : Scopelang.Ast.ScopeName.t)
|
||||
(ctxt : Name_resolution.context)
|
||||
(prgm : Desugared.Ast.program)
|
||||
@ -1192,8 +1214,8 @@ let process_assert
|
||||
( Ast.IfThenElse
|
||||
( cond,
|
||||
ass.Ast.assertion_content,
|
||||
Pos.same_pos_as (Ast.Literal (Ast.LBool true)) cond ),
|
||||
Pos.get_position cond ))
|
||||
Marked.same_mark_as (Ast.Literal (Ast.LBool true)) cond ),
|
||||
Marked.get_mark cond ))
|
||||
in
|
||||
let ass =
|
||||
match precond with
|
||||
@ -1203,9 +1225,9 @@ let process_assert
|
||||
( Desugared.Ast.EIfThenElse
|
||||
( precond,
|
||||
ass,
|
||||
Pos.same_pos_as (Desugared.Ast.ELit (Dcalc.Ast.LBool true))
|
||||
Marked.same_mark_as (Desugared.Ast.ELit (Dcalc.Ast.LBool true))
|
||||
precond ),
|
||||
Pos.get_position precond ))
|
||||
Marked.get_mark precond ))
|
||||
precond ass
|
||||
| None -> ass
|
||||
in
|
||||
@ -1220,13 +1242,13 @@ let process_assert
|
||||
|
||||
(** Translates a surface definition, rule or assertion *)
|
||||
let process_scope_use_item
|
||||
(precond : Ast.expression Pos.marked option)
|
||||
(precond : Ast.expression Marked.pos option)
|
||||
(scope : Scopelang.Ast.ScopeName.t)
|
||||
(ctxt : Name_resolution.context)
|
||||
(prgm : Desugared.Ast.program)
|
||||
(item : Ast.scope_use_item Pos.marked) : Desugared.Ast.program =
|
||||
(item : Ast.scope_use_item Marked.pos) : Desugared.Ast.program =
|
||||
let precond = Option.map (translate_expr scope None ctxt) precond in
|
||||
match Pos.unmark item with
|
||||
match Marked.unmark item with
|
||||
| Ast.Rule rule -> process_rule precond scope ctxt prgm rule
|
||||
| Ast.Definition def -> process_def precond scope ctxt prgm def
|
||||
| Ast.Assertion ass -> process_assert precond scope ctxt prgm ass
|
||||
@ -1239,23 +1261,23 @@ let process_scope_use_item
|
||||
let check_unlabeled_exception
|
||||
(scope : Scopelang.Ast.ScopeName.t)
|
||||
(ctxt : Name_resolution.context)
|
||||
(item : Ast.scope_use_item Pos.marked) : unit =
|
||||
(item : Ast.scope_use_item Marked.pos) : unit =
|
||||
let scope_ctxt = Scopelang.Ast.ScopeMap.find scope ctxt.scopes in
|
||||
match Pos.unmark item with
|
||||
match Marked.unmark item with
|
||||
| Ast.Rule _ | Ast.Definition _ -> (
|
||||
let def_key, exception_to =
|
||||
match Pos.unmark item with
|
||||
match Marked.unmark item with
|
||||
| Ast.Rule rule ->
|
||||
( Name_resolution.get_def_key
|
||||
(Pos.unmark rule.rule_name)
|
||||
(Marked.unmark rule.rule_name)
|
||||
rule.rule_state scope ctxt
|
||||
(Pos.get_position rule.rule_name),
|
||||
(Marked.get_mark rule.rule_name),
|
||||
rule.rule_exception_to )
|
||||
| Ast.Definition def ->
|
||||
( Name_resolution.get_def_key
|
||||
(Pos.unmark def.definition_name)
|
||||
(Marked.unmark def.definition_name)
|
||||
def.definition_state scope ctxt
|
||||
(Pos.get_position def.definition_name),
|
||||
(Marked.get_mark def.definition_name),
|
||||
def.definition_exception_to )
|
||||
| _ -> assert false
|
||||
(* should not happen *)
|
||||
@ -1270,11 +1292,11 @@ let check_unlabeled_exception
|
||||
| Ast.UnlabeledException -> (
|
||||
match scope_def_ctxt.default_exception_rulename with
|
||||
| None ->
|
||||
Errors.raise_spanned_error (Pos.get_position item)
|
||||
Errors.raise_spanned_error (Marked.get_mark item)
|
||||
"This exception does not have a corresponding definition"
|
||||
| Some (Ambiguous pos) ->
|
||||
Errors.raise_multispanned_error
|
||||
([Some "Ambiguous exception", Pos.get_position item]
|
||||
([Some "Ambiguous exception", Marked.get_mark item]
|
||||
@ List.map (fun p -> Some "Candidate definition", p) pos)
|
||||
"This exception can refer to several definitions. Try using labels \
|
||||
to disambiguate"
|
||||
@ -1305,7 +1327,7 @@ let attribute_to_io (attr : Ast.scope_decl_context_io) : Scopelang.Ast.io =
|
||||
{
|
||||
Scopelang.Ast.io_output = attr.scope_decl_context_io_output;
|
||||
Scopelang.Ast.io_input =
|
||||
Pos.map_under_mark
|
||||
Marked.map_under_mark
|
||||
(fun io ->
|
||||
match io with
|
||||
| Ast.Input -> Scopelang.Ast.OnlyInput
|
||||
@ -1363,8 +1385,6 @@ let desugar_program (ctxt : Name_resolution.context) (prgm : Ast.program) :
|
||||
Desugared.Ast.scope_def_rules =
|
||||
Desugared.Ast.RuleMap.empty;
|
||||
Desugared.Ast.scope_def_typ = v_sig.var_sig_typ;
|
||||
Desugared.Ast.scope_def_label_groups =
|
||||
Name_resolution.label_groups ctxt s_uid def_key;
|
||||
Desugared.Ast.scope_def_is_condition =
|
||||
v_sig.var_sig_is_condition;
|
||||
Desugared.Ast.scope_def_io =
|
||||
@ -1384,9 +1404,6 @@ let desugar_program (ctxt : Name_resolution.context) (prgm : Ast.program) :
|
||||
Desugared.Ast.RuleMap.empty;
|
||||
Desugared.Ast.scope_def_typ =
|
||||
v_sig.var_sig_typ;
|
||||
Desugared.Ast.scope_def_label_groups =
|
||||
Name_resolution.label_groups ctxt s_uid
|
||||
def_key;
|
||||
Desugared.Ast.scope_def_is_condition =
|
||||
v_sig.var_sig_is_condition;
|
||||
Desugared.Ast.scope_def_io =
|
||||
@ -1403,7 +1420,7 @@ let desugar_program (ctxt : Name_resolution.context) (prgm : Ast.program) :
|
||||
if i = 0 then original_io.io_input
|
||||
else
|
||||
( Scopelang.Ast.NoInput,
|
||||
Pos.get_position
|
||||
Marked.get_mark
|
||||
(Desugared.Ast.StateName
|
||||
.get_info state) )
|
||||
in
|
||||
@ -1412,7 +1429,7 @@ let desugar_program (ctxt : Name_resolution.context) (prgm : Ast.program) :
|
||||
original_io.io_output
|
||||
else
|
||||
( false,
|
||||
Pos.get_position
|
||||
Marked.get_mark
|
||||
(Desugared.Ast.StateName
|
||||
.get_info state) )
|
||||
in
|
||||
@ -1442,9 +1459,6 @@ let desugar_program (ctxt : Name_resolution.context) (prgm : Ast.program) :
|
||||
Desugared.Ast.scope_def_rules =
|
||||
Desugared.Ast.RuleMap.empty;
|
||||
Desugared.Ast.scope_def_typ = v_sig.var_sig_typ;
|
||||
Desugared.Ast.scope_def_label_groups =
|
||||
Name_resolution.label_groups ctxt subscope_uid
|
||||
def_key;
|
||||
Desugared.Ast.scope_def_is_condition =
|
||||
v_sig.var_sig_is_condition;
|
||||
Desugared.Ast.scope_def_io =
|
||||
@ -1475,7 +1489,7 @@ let desugar_program (ctxt : Name_resolution.context) (prgm : Ast.program) :
|
||||
| CodeBlock (block, _, _) ->
|
||||
List.fold_left
|
||||
(fun prgm item ->
|
||||
match Pos.unmark item with
|
||||
match Marked.unmark item with
|
||||
| Ast.ScopeUse use -> process_scope_use ctxt prgm use
|
||||
| _ -> prgm)
|
||||
prgm block
|
||||
|
@ -10,7 +10,7 @@
|
||||
scopelang
|
||||
zarith
|
||||
zarith_stubs_js
|
||||
calendar)
|
||||
dates_calc)
|
||||
(preprocess
|
||||
(pps sedlex.ppx visitors.ppx)))
|
||||
|
||||
@ -38,6 +38,11 @@
|
||||
(merge_into parser)
|
||||
(flags --external-tokens Tokens --table --explain))
|
||||
|
||||
(rule
|
||||
(target grammar.html)
|
||||
(action
|
||||
(run obelisk html -o %{target} %{dep:parser.mly})))
|
||||
|
||||
(documentation
|
||||
(package catala)
|
||||
(mld_files surface))
|
||||
|
@ -21,14 +21,14 @@ let fill_pos_with_legislative_info (p : Ast.program) : Ast.program =
|
||||
object
|
||||
inherit [_] Ast.program_map as super
|
||||
|
||||
method! visit_marked f env x =
|
||||
f env (Pos.unmark x), Pos.overwrite_law_info (Pos.get_position x) env
|
||||
method! visit_pos f env x =
|
||||
f env (Marked.unmark x), Pos.overwrite_law_info (Marked.get_mark x) env
|
||||
|
||||
method! visit_LawHeading
|
||||
(env : string list)
|
||||
(heading : Ast.law_heading)
|
||||
(children : Ast.law_structure list) =
|
||||
let env = Pos.unmark heading.law_heading_name :: env in
|
||||
let env = Marked.unmark heading.law_heading_name :: env in
|
||||
Ast.LawHeading
|
||||
( super#visit_law_heading env heading,
|
||||
List.map (fun child -> super#visit_law_structure env child) children
|
||||
|
@ -59,6 +59,9 @@ module R = Re.Pcre
|
||||
#ifndef MR_COLLECTION
|
||||
#define MR_COLLECTION MS_COLLECTION
|
||||
#endif
|
||||
#ifndef MR_CONTAINS
|
||||
#define MR_CONTAINS MS_CONTAINS
|
||||
#endif
|
||||
#ifndef MR_ENUM
|
||||
#define MR_ENUM MS_ENUM
|
||||
#endif
|
||||
@ -221,6 +224,12 @@ module R = Re.Pcre
|
||||
#ifndef MR_IntToDec
|
||||
#define MR_IntToDec MS_IntToDec
|
||||
#endif
|
||||
#ifndef MR_MoneyToDec
|
||||
#define MR_MoneyToDec MS_MoneyToDec
|
||||
#endif
|
||||
#ifndef MR_DecToMoney
|
||||
#define MR_DecToMoney MS_DecToMoney
|
||||
#endif
|
||||
#ifndef MR_RoundMoney
|
||||
#define MR_RoundMoney MS_RoundMoney
|
||||
#endif
|
||||
@ -236,6 +245,12 @@ module R = Re.Pcre
|
||||
#ifndef MR_GetYear
|
||||
#define MR_GetYear MS_GetYear
|
||||
#endif
|
||||
#ifndef MR_FirstDayOfMonth
|
||||
#define MR_FirstDayOfMonth MS_FirstDayOfMonth
|
||||
#endif
|
||||
#ifndef MR_LastDayOfMonth
|
||||
#define MR_LastDayOfMonth MS_LastDayOfMonth
|
||||
#endif
|
||||
#ifndef MR_INPUT
|
||||
#define MR_INPUT MS_INPUT
|
||||
#endif
|
||||
@ -258,6 +273,7 @@ let token_list : (string * token) list =
|
||||
(MS_INCREASING, INCREASING);
|
||||
(MS_OF, OF);
|
||||
(MS_COLLECTION, COLLECTION);
|
||||
(MS_CONTAINS, CONTAINS);
|
||||
(MS_ENUM, ENUM);
|
||||
(MS_INTEGER, INTEGER);
|
||||
(MS_MONEY, MONEY);
|
||||
@ -322,9 +338,13 @@ let lex_builtin (s : string) : Ast.builtin_expression option =
|
||||
let lexbuf = Utf8.from_string s in
|
||||
match%sedlex lexbuf with
|
||||
| MR_IntToDec, eof -> Some IntToDec
|
||||
| MR_DecToMoney, eof -> Some DecToMoney
|
||||
| MR_MoneyToDec, eof -> Some MoneyToDec
|
||||
| MR_GetDay, eof -> Some GetDay
|
||||
| MR_GetMonth, eof -> Some GetMonth
|
||||
| MR_GetYear, eof -> Some GetYear
|
||||
| MR_FirstDayOfMonth -> Some FirstDayOfMonth
|
||||
| MR_LastDayOfMonth -> Some LastDayOfMonth
|
||||
| MR_RoundMoney, eof -> Some RoundMoney
|
||||
| MR_RoundDecimal, eof -> Some RoundDecimal
|
||||
| _ -> None
|
||||
@ -394,6 +414,9 @@ let rec lex_code (lexbuf : lexbuf) : token =
|
||||
| MR_COLLECTION ->
|
||||
L.update_acc lexbuf;
|
||||
COLLECTION
|
||||
| MR_CONTAINS ->
|
||||
L.update_acc lexbuf;
|
||||
CONTAINS
|
||||
| MR_ENUM ->
|
||||
L.update_acc lexbuf;
|
||||
ENUM
|
||||
@ -572,10 +595,26 @@ let rec lex_code (lexbuf : lexbuf) : token =
|
||||
Buffer.add_string cents (String.make (2 - Buffer.length cents) '0');
|
||||
L.update_acc lexbuf;
|
||||
MONEY_AMOUNT (Buffer.contents units, Buffer.contents cents)
|
||||
| Plus digit, MC_DECIMAL_SEPARATOR, Star digit ->
|
||||
| Rep (digit, 4), '-', Rep (digit, 2), '-', Rep (digit, 2) ->
|
||||
let rex =
|
||||
Re.(compile @@ whole_string @@ seq [
|
||||
group (rep1 digit);
|
||||
group (repn digit 4 None);
|
||||
char '-';
|
||||
group (repn digit 2 None);
|
||||
char '-';
|
||||
group (repn digit 2 None);
|
||||
])
|
||||
in
|
||||
let date_parts = R.get_substring (R.exec ~rex (Utf8.lexeme lexbuf)) in
|
||||
DATE_LITERAL (
|
||||
int_of_string (date_parts 1),
|
||||
int_of_string (date_parts 2),
|
||||
int_of_string (date_parts 3)
|
||||
)
|
||||
| Opt '-', Plus digit, MC_DECIMAL_SEPARATOR, Star digit ->
|
||||
let rex =
|
||||
Re.(compile @@ whole_string @@ seq [
|
||||
group (seq [opt (char '-') ; rep1 digit]);
|
||||
char MC_DECIMAL_SEPARATOR;
|
||||
group (rep digit)
|
||||
]) in
|
||||
@ -750,7 +789,7 @@ let rec lex_code (lexbuf : lexbuf) : token =
|
||||
(* Name of variable *)
|
||||
L.update_acc lexbuf;
|
||||
IDENT (Utf8.lexeme lexbuf)
|
||||
| Plus digit ->
|
||||
| Opt '-', Plus digit ->
|
||||
(* Integer literal*)
|
||||
L.update_acc lexbuf;
|
||||
INT_LITERAL (Utf8.lexeme lexbuf)
|
||||
|
@ -29,6 +29,7 @@
|
||||
#define MS_INCREASING "increasing"
|
||||
#define MS_OF "of"
|
||||
#define MS_COLLECTION "collection"
|
||||
#define MS_CONTAINS "contains"
|
||||
#define MS_ENUM "enumeration"
|
||||
#define MS_INTEGER "integer"
|
||||
#define MS_MONEY "money"
|
||||
@ -102,9 +103,13 @@
|
||||
#define MS_RoundMoney "round_money"
|
||||
#define MS_RoundDecimal "round_decimal"
|
||||
#define MS_IntToDec "integer_to_decimal"
|
||||
#define MS_MoneyToDec "money_to_decimal"
|
||||
#define MS_DecToMoney "decimal_to_money"
|
||||
#define MS_GetDay "get_day"
|
||||
#define MS_GetMonth "get_month"
|
||||
#define MS_GetYear "get_year"
|
||||
#define MS_FirstDayOfMonth "first_day_of_month"
|
||||
#define MS_LastDayOfMonth "last_day_of_month"
|
||||
|
||||
(* Directives *)
|
||||
|
||||
|
@ -37,6 +37,7 @@
|
||||
#define MS_INCREASING "croissant"
|
||||
#define MS_OF "de"
|
||||
#define MS_COLLECTION "collection"
|
||||
#define MS_CONTAINS "contient"
|
||||
#define MS_ENUM "énumération"
|
||||
#define MR_ENUM 0xE9, "num", 0xE9, "ration"
|
||||
#define MS_INTEGER "entier"
|
||||
@ -125,12 +126,18 @@
|
||||
#define MR_RoundDecimal "arrondi_d", 0xE9, "cimal"
|
||||
#define MS_IntToDec "entier_vers_décimal"
|
||||
#define MR_IntToDec "entier_vers_d", 0xE9, "cimal"
|
||||
#define MS_MoneyToDec "argent_vers_décimal"
|
||||
#define MR_MoneyToDec "argent_vers_d", 0xE9, "cimal"
|
||||
#define MS_DecToMoney "décimal_vers_argent"
|
||||
#define MR_DecToMoney "d", 0xE9, "cimal_vers_argent"
|
||||
#define MS_GetDay "accès_jour"
|
||||
#define MR_GetDay "acc", 0xE8, "s_jour"
|
||||
#define MS_GetMonth "accès_mois"
|
||||
#define MR_GetMonth "acc", 0xE8, "s_mois"
|
||||
#define MS_GetYear "accès_année"
|
||||
#define MR_GetYear "acc", 0xE8, "s_ann", 0xE9, "e"
|
||||
#define MS_FirstDayOfMonth "premier_jour_du_mois"
|
||||
#define MS_LastDayOfMonth "dernier_jour_du_mois"
|
||||
|
||||
(* Directives *)
|
||||
|
||||
|
@ -29,6 +29,7 @@
|
||||
#define MS_INCREASING "rosnacy"
|
||||
#define MS_OF "z"
|
||||
#define MS_COLLECTION "kolekcja"
|
||||
#define MS_CONTAINS "zawiera"
|
||||
#define MS_ENUM "enumeracja"
|
||||
#define MS_INTEGER "calkowita"
|
||||
#define MS_MONEY "pieniądze"
|
||||
@ -113,12 +114,20 @@
|
||||
#define MR_RoundMoney "zaokr",0x0105,"glony_pieni", 0x0105, "dze"
|
||||
#define MS_IntToDec "calkowita_wers_dziesiętny"
|
||||
#define MR_IntToDec "calkowita_wers_dziesi", 0x0119, "tny"
|
||||
#define MS_MoneyToDec "pieniądze_wers_dziesiętny"
|
||||
#define MR_MoneyToDec "pieni", 0x0105, "dze_wers_dziesi", 0x0119, "tny"
|
||||
#define MS_DecToMoney "dziesiętny_wers_pieniądze"
|
||||
#define MR_DecToMoney "dziesi", 0x0119, "tny_wers_pieni", 0x0105, "dze"
|
||||
#define MS_GetDay "dostęp_dzień"
|
||||
#define MR_GetDay "dost", 0x0119, "p_dzie", 0x144
|
||||
#define MS_GetMonth "dostęp_miesiąc"
|
||||
#define MR_GetMonth "dost", 0x0119, "p_miesi", 0x0105, "c"
|
||||
#define MS_GetYear "dostęp_rok"
|
||||
#define MR_GetYear "dost", 0x0119, "p_rok"
|
||||
#define MS_FirstDayOfMonth "pierwszy_dzień_miesiąca"
|
||||
#define MR_FirstDayOfMonth "pierwszy_dzie", 0x144, "_miesi", 0x0105, "ca"
|
||||
#define MS_LastDayOfMonth "ostatni_dzień_miesiąca"
|
||||
#define MR_LastDayOfMonth "ostatni_dzie", 0x144, "_miesi", 0x0105, "ca"
|
||||
|
||||
(* Directives *)
|
||||
|
||||
|
@ -27,12 +27,11 @@ type typ = Scopelang.Ast.typ
|
||||
|
||||
type unique_rulename =
|
||||
| Ambiguous of Pos.t list
|
||||
| Unique of Desugared.Ast.RuleName.t Pos.marked
|
||||
| Unique of Desugared.Ast.RuleName.t Marked.pos
|
||||
|
||||
type scope_def_context = {
|
||||
default_exception_rulename : unique_rulename option;
|
||||
label_idmap : Desugared.Ast.LabelName.t Desugared.Ast.IdentMap.t;
|
||||
label_groups : Desugared.Ast.RuleSet.t Desugared.Ast.LabelMap.t;
|
||||
}
|
||||
|
||||
type scope_context = {
|
||||
@ -47,14 +46,14 @@ type scope_context = {
|
||||
}
|
||||
(** Inside a scope, we distinguish between the variables and the subscopes. *)
|
||||
|
||||
type struct_context = typ Pos.marked Scopelang.Ast.StructFieldMap.t
|
||||
type struct_context = typ Marked.pos Scopelang.Ast.StructFieldMap.t
|
||||
(** Types of the fields of a struct *)
|
||||
|
||||
type enum_context = typ Pos.marked Scopelang.Ast.EnumConstructorMap.t
|
||||
type enum_context = typ Marked.pos Scopelang.Ast.EnumConstructorMap.t
|
||||
(** Types of the payloads of the cases of an enum *)
|
||||
|
||||
type var_sig = {
|
||||
var_sig_typ : typ Pos.marked;
|
||||
var_sig_typ : typ Marked.pos;
|
||||
var_sig_is_condition : bool;
|
||||
var_sig_io : Ast.scope_decl_context_io;
|
||||
var_sig_states_idmap : Desugared.Ast.StateName.t Desugared.Ast.IdentMap.t;
|
||||
@ -101,15 +100,15 @@ let raise_unsupported_feature (msg : string) (pos : Pos.t) =
|
||||
|
||||
(** Function to call whenever an identifier used somewhere has not been declared
|
||||
in the program previously *)
|
||||
let raise_unknown_identifier (msg : string) (ident : ident Pos.marked) =
|
||||
Errors.raise_spanned_error (Pos.get_position ident)
|
||||
let raise_unknown_identifier (msg : string) (ident : ident Marked.pos) =
|
||||
Errors.raise_spanned_error (Marked.get_mark ident)
|
||||
"\"%s\": unknown identifier %s"
|
||||
(Utils.Cli.with_style [ANSITerminal.yellow] "%s" (Pos.unmark ident))
|
||||
(Utils.Cli.with_style [ANSITerminal.yellow] "%s" (Marked.unmark ident))
|
||||
msg
|
||||
|
||||
(** Gets the type associated to an uid *)
|
||||
let get_var_typ (ctxt : context) (uid : Desugared.Ast.ScopeVar.t) :
|
||||
typ Pos.marked =
|
||||
typ Marked.pos =
|
||||
(Desugared.Ast.ScopeVarMap.find uid ctxt.var_typs).var_sig_typ
|
||||
|
||||
let is_var_cond (ctxt : context) (uid : Desugared.Ast.ScopeVar.t) : bool =
|
||||
@ -123,7 +122,7 @@ let get_var_io (ctxt : context) (uid : Desugared.Ast.ScopeVar.t) :
|
||||
let get_var_uid
|
||||
(scope_uid : Scopelang.Ast.ScopeName.t)
|
||||
(ctxt : context)
|
||||
((x, pos) : ident Pos.marked) : Desugared.Ast.ScopeVar.t =
|
||||
((x, pos) : ident Marked.pos) : Desugared.Ast.ScopeVar.t =
|
||||
let scope = Scopelang.Ast.ScopeMap.find scope_uid ctxt.scopes in
|
||||
match Desugared.Ast.IdentMap.find_opt x scope.var_idmap with
|
||||
| None ->
|
||||
@ -137,7 +136,7 @@ let get_var_uid
|
||||
let get_subscope_uid
|
||||
(scope_uid : Scopelang.Ast.ScopeName.t)
|
||||
(ctxt : context)
|
||||
((y, pos) : ident Pos.marked) : Scopelang.Ast.SubScopeName.t =
|
||||
((y, pos) : ident Marked.pos) : Scopelang.Ast.SubScopeName.t =
|
||||
let scope = Scopelang.Ast.ScopeMap.find scope_uid ctxt.scopes in
|
||||
match Desugared.Ast.IdentMap.find_opt y scope.sub_scopes_idmap with
|
||||
| None -> raise_unknown_identifier "for a subscope of this scope" (y, pos)
|
||||
@ -164,7 +163,7 @@ let belongs_to
|
||||
|
||||
(** Retrieves the type of a scope definition from the context *)
|
||||
let get_def_typ (ctxt : context) (def : Desugared.Ast.ScopeDef.t) :
|
||||
typ Pos.marked =
|
||||
typ Marked.pos =
|
||||
match def with
|
||||
| Desugared.Ast.ScopeDef.SubScopeVar (_, x)
|
||||
(* we don't need to look at the subscope prefix because [x] is already the uid
|
||||
@ -180,17 +179,6 @@ let is_def_cond (ctxt : context) (def : Desugared.Ast.ScopeDef.t) : bool =
|
||||
| Desugared.Ast.ScopeDef.Var (x, _) ->
|
||||
is_var_cond ctxt x
|
||||
|
||||
let label_groups
|
||||
(ctxt : context)
|
||||
(s_uid : Scopelang.Ast.ScopeName.t)
|
||||
(def : Desugared.Ast.ScopeDef.t) :
|
||||
Desugared.Ast.RuleSet.t Desugared.Ast.LabelMap.t =
|
||||
try
|
||||
(Desugared.Ast.ScopeDefMap.find def
|
||||
(Scopelang.Ast.ScopeMap.find s_uid ctxt.scopes).scope_defs_contexts)
|
||||
.label_groups
|
||||
with Not_found -> Desugared.Ast.LabelMap.empty
|
||||
|
||||
(** {1 Declarations pass} *)
|
||||
|
||||
(** Process a subscope declaration *)
|
||||
@ -208,7 +196,7 @@ let process_subscope_decl
|
||||
Errors.raise_multispanned_error
|
||||
[
|
||||
( Some "first use",
|
||||
Pos.get_position (Scopelang.Ast.SubScopeName.get_info use) );
|
||||
Marked.get_mark (Scopelang.Ast.SubScopeName.get_info use) );
|
||||
Some "second use", s_pos;
|
||||
]
|
||||
"Subscope name \"%a\" already used"
|
||||
@ -237,7 +225,7 @@ let process_subscope_decl
|
||||
scopes = Scopelang.Ast.ScopeMap.add scope scope_ctxt ctxt.scopes;
|
||||
}
|
||||
|
||||
let is_type_cond ((typ, _) : Ast.typ Pos.marked) =
|
||||
let is_type_cond ((typ, _) : Ast.typ Marked.pos) =
|
||||
match typ with
|
||||
| Ast.Base Ast.Condition
|
||||
| Ast.Func { arg_typ = _; return_typ = Ast.Condition, _ } ->
|
||||
@ -247,13 +235,14 @@ let is_type_cond ((typ, _) : Ast.typ Pos.marked) =
|
||||
(** Process a basic type (all types except function types) *)
|
||||
let rec process_base_typ
|
||||
(ctxt : context)
|
||||
((typ, typ_pos) : Ast.base_typ Pos.marked) : Scopelang.Ast.typ Pos.marked =
|
||||
((typ, typ_pos) : Ast.base_typ Marked.pos) : Scopelang.Ast.typ Marked.pos =
|
||||
match typ with
|
||||
| Ast.Condition -> Scopelang.Ast.TLit TBool, typ_pos
|
||||
| Ast.Data (Ast.Collection t) ->
|
||||
( Scopelang.Ast.TArray
|
||||
(Pos.unmark
|
||||
(process_base_typ ctxt (Ast.Data (Pos.unmark t), Pos.get_position t))),
|
||||
(Marked.unmark
|
||||
(process_base_typ ctxt
|
||||
(Ast.Data (Marked.unmark t), Marked.get_mark t))),
|
||||
typ_pos )
|
||||
| Ast.Data (Ast.Primitive prim) -> (
|
||||
match prim with
|
||||
@ -277,8 +266,8 @@ let rec process_base_typ
|
||||
ident)))
|
||||
|
||||
(** Process a type (function or not) *)
|
||||
let process_type (ctxt : context) ((typ, typ_pos) : Ast.typ Pos.marked) :
|
||||
Scopelang.Ast.typ Pos.marked =
|
||||
let process_type (ctxt : context) ((typ, typ_pos) : Ast.typ Marked.pos) :
|
||||
Scopelang.Ast.typ Marked.pos =
|
||||
match typ with
|
||||
| Ast.Base base_typ -> process_base_typ ctxt (base_typ, typ_pos)
|
||||
| Ast.Func { arg_typ; return_typ } ->
|
||||
@ -300,7 +289,7 @@ let process_data_decl
|
||||
| Some use ->
|
||||
Errors.raise_multispanned_error
|
||||
[
|
||||
Some "First use:", Pos.get_position (Desugared.Ast.ScopeVar.get_info use);
|
||||
Some "First use:", Marked.get_mark (Desugared.Ast.ScopeVar.get_info use);
|
||||
Some "Second use:", pos;
|
||||
]
|
||||
"Variable name \"%a\" already used"
|
||||
@ -318,7 +307,7 @@ let process_data_decl
|
||||
List.fold_right
|
||||
(fun state_id (states_idmap, states_list) ->
|
||||
let state_uid = Desugared.Ast.StateName.fresh state_id in
|
||||
( Desugared.Ast.IdentMap.add (Pos.unmark state_id) state_uid
|
||||
( Desugared.Ast.IdentMap.add (Marked.unmark state_id) state_uid
|
||||
states_idmap,
|
||||
state_uid :: states_list ))
|
||||
decl.scope_decl_context_item_states
|
||||
@ -349,15 +338,14 @@ let process_item_decl
|
||||
| Ast.ContextScope sub_decl -> process_subscope_decl scope ctxt sub_decl
|
||||
|
||||
(** Adds a binding to the context *)
|
||||
let add_def_local_var (ctxt : context) (name : ident Pos.marked) :
|
||||
let add_def_local_var (ctxt : context) (name : ident) :
|
||||
context * Desugared.Ast.Var.t =
|
||||
let local_var_uid = Desugared.Ast.Var.make name in
|
||||
let ctxt =
|
||||
{
|
||||
ctxt with
|
||||
local_var_idmap =
|
||||
Desugared.Ast.IdentMap.add (Pos.unmark name) local_var_uid
|
||||
ctxt.local_var_idmap;
|
||||
Desugared.Ast.IdentMap.add name local_var_uid ctxt.local_var_idmap;
|
||||
}
|
||||
in
|
||||
ctxt, local_var_uid
|
||||
@ -367,7 +355,7 @@ let process_scope_decl (ctxt : context) (decl : Ast.scope_decl) : context =
|
||||
let name, _ = decl.scope_decl_name in
|
||||
let scope_uid = Desugared.Ast.IdentMap.find name ctxt.scope_idmap in
|
||||
List.fold_left
|
||||
(fun ctxt item -> process_item_decl scope_uid ctxt (Pos.unmark item))
|
||||
(fun ctxt item -> process_item_decl scope_uid ctxt (Marked.unmark item))
|
||||
ctxt decl.scope_decl_context
|
||||
|
||||
(** Process a struct declaration *)
|
||||
@ -377,10 +365,10 @@ let process_struct_decl (ctxt : context) (sdecl : Ast.struct_decl) : context =
|
||||
in
|
||||
if List.length sdecl.struct_decl_fields = 0 then
|
||||
Errors.raise_spanned_error
|
||||
(Pos.get_position sdecl.struct_decl_name)
|
||||
(Marked.get_mark sdecl.struct_decl_name)
|
||||
"The struct %s does not have any fields; give it some for Catala to be \
|
||||
able to accept it."
|
||||
(Pos.unmark sdecl.struct_decl_name);
|
||||
(Marked.unmark sdecl.struct_decl_name);
|
||||
List.fold_left
|
||||
(fun ctxt (fdecl, _) ->
|
||||
let f_uid =
|
||||
@ -391,7 +379,7 @@ let process_struct_decl (ctxt : context) (sdecl : Ast.struct_decl) : context =
|
||||
ctxt with
|
||||
field_idmap =
|
||||
Desugared.Ast.IdentMap.update
|
||||
(Pos.unmark fdecl.Ast.struct_decl_field_name)
|
||||
(Marked.unmark fdecl.Ast.struct_decl_field_name)
|
||||
(fun uids ->
|
||||
match uids with
|
||||
| None -> Some (Scopelang.Ast.StructMap.singleton s_uid f_uid)
|
||||
@ -426,10 +414,10 @@ let process_enum_decl (ctxt : context) (edecl : Ast.enum_decl) : context =
|
||||
in
|
||||
if List.length edecl.enum_decl_cases = 0 then
|
||||
Errors.raise_spanned_error
|
||||
(Pos.get_position edecl.enum_decl_name)
|
||||
(Marked.get_mark edecl.enum_decl_name)
|
||||
"The enum %s does not have any cases; give it some for Catala to be able \
|
||||
to accept it."
|
||||
(Pos.unmark edecl.enum_decl_name);
|
||||
(Marked.unmark edecl.enum_decl_name);
|
||||
List.fold_left
|
||||
(fun ctxt (cdecl, cdecl_pos) ->
|
||||
let c_uid =
|
||||
@ -440,7 +428,7 @@ let process_enum_decl (ctxt : context) (edecl : Ast.enum_decl) : context =
|
||||
ctxt with
|
||||
constructor_idmap =
|
||||
Desugared.Ast.IdentMap.update
|
||||
(Pos.unmark cdecl.Ast.enum_decl_case_name)
|
||||
(Marked.unmark cdecl.Ast.enum_decl_case_name)
|
||||
(fun uids ->
|
||||
match uids with
|
||||
| None -> Some (Scopelang.Ast.EnumMap.singleton e_uid c_uid)
|
||||
@ -468,19 +456,19 @@ let process_enum_decl (ctxt : context) (edecl : Ast.enum_decl) : context =
|
||||
ctxt edecl.enum_decl_cases
|
||||
|
||||
(** Process the names of all declaration items *)
|
||||
let process_name_item (ctxt : context) (item : Ast.code_item Pos.marked) :
|
||||
let process_name_item (ctxt : context) (item : Ast.code_item Marked.pos) :
|
||||
context =
|
||||
let raise_already_defined_error (use : Uid.MarkedString.info) name pos msg =
|
||||
Errors.raise_multispanned_error
|
||||
[
|
||||
Some "First definition:", Pos.get_position use;
|
||||
Some "First definition:", Marked.get_mark use;
|
||||
Some "Second definition:", pos;
|
||||
]
|
||||
"%s name \"%a\" already defined" msg
|
||||
(Utils.Cli.format_with_style [ANSITerminal.yellow])
|
||||
name
|
||||
in
|
||||
match Pos.unmark item with
|
||||
match Marked.unmark item with
|
||||
| ScopeDecl decl -> (
|
||||
let name, pos = decl.scope_decl_name in
|
||||
(* Checks if the name is already used *)
|
||||
@ -517,7 +505,7 @@ let process_name_item (ctxt : context) (item : Ast.code_item Pos.marked) :
|
||||
ctxt with
|
||||
struct_idmap =
|
||||
Desugared.Ast.IdentMap.add
|
||||
(Pos.unmark sdecl.struct_decl_name)
|
||||
(Marked.unmark sdecl.struct_decl_name)
|
||||
s_uid ctxt.struct_idmap;
|
||||
})
|
||||
| EnumDecl edecl -> (
|
||||
@ -534,15 +522,15 @@ let process_name_item (ctxt : context) (item : Ast.code_item Pos.marked) :
|
||||
ctxt with
|
||||
enum_idmap =
|
||||
Desugared.Ast.IdentMap.add
|
||||
(Pos.unmark edecl.enum_decl_name)
|
||||
(Marked.unmark edecl.enum_decl_name)
|
||||
e_uid ctxt.enum_idmap;
|
||||
})
|
||||
| ScopeUse _ -> ctxt
|
||||
|
||||
(** Process a code item that is a declaration *)
|
||||
let process_decl_item (ctxt : context) (item : Ast.code_item Pos.marked) :
|
||||
let process_decl_item (ctxt : context) (item : Ast.code_item Marked.pos) :
|
||||
context =
|
||||
match Pos.unmark item with
|
||||
match Marked.unmark item with
|
||||
| ScopeDecl decl -> process_scope_decl ctxt decl
|
||||
| StructDecl sdecl -> process_struct_decl ctxt sdecl
|
||||
| EnumDecl edecl -> process_enum_decl ctxt edecl
|
||||
@ -552,14 +540,14 @@ let process_decl_item (ctxt : context) (item : Ast.code_item Pos.marked) :
|
||||
let process_code_block
|
||||
(ctxt : context)
|
||||
(block : Ast.code_block)
|
||||
(process_item : context -> Ast.code_item Pos.marked -> context) : context =
|
||||
(process_item : context -> Ast.code_item Marked.pos -> context) : context =
|
||||
List.fold_left (fun ctxt decl -> process_item ctxt decl) ctxt block
|
||||
|
||||
(** Process a law structure, only considering the code blocks *)
|
||||
let rec process_law_structure
|
||||
(ctxt : context)
|
||||
(s : Ast.law_structure)
|
||||
(process_item : context -> Ast.code_item Pos.marked -> context) : context =
|
||||
(process_item : context -> Ast.code_item Marked.pos -> context) : context =
|
||||
match s with
|
||||
| Ast.LawHeading (_, children) ->
|
||||
List.fold_left
|
||||
@ -572,7 +560,7 @@ let rec process_law_structure
|
||||
|
||||
let get_def_key
|
||||
(name : Ast.qident)
|
||||
(state : Ast.ident Pos.marked option)
|
||||
(state : Ast.ident Marked.pos option)
|
||||
(scope_uid : Scopelang.Ast.ScopeName.t)
|
||||
(ctxt : context)
|
||||
(default_pos : Pos.t) : Desugared.Ast.ScopeDef.t =
|
||||
@ -587,14 +575,14 @@ let get_def_key
|
||||
| Some state -> (
|
||||
try
|
||||
Some
|
||||
(Desugared.Ast.IdentMap.find (Pos.unmark state)
|
||||
(Desugared.Ast.IdentMap.find (Marked.unmark state)
|
||||
var_sig.var_sig_states_idmap)
|
||||
with Not_found ->
|
||||
Errors.raise_multispanned_error
|
||||
[
|
||||
None, Pos.get_position state;
|
||||
None, Marked.get_mark state;
|
||||
( Some "Variable declaration:",
|
||||
Pos.get_position (Desugared.Ast.ScopeVar.get_info x_uid) );
|
||||
Marked.get_mark (Desugared.Ast.ScopeVar.get_info x_uid) );
|
||||
]
|
||||
"This identifier is not a state declared for variable %a."
|
||||
Desugared.Ast.ScopeVar.format_t x_uid)
|
||||
@ -603,9 +591,9 @@ let get_def_key
|
||||
then
|
||||
Errors.raise_multispanned_error
|
||||
[
|
||||
None, Pos.get_position x;
|
||||
None, Marked.get_mark x;
|
||||
( Some "Variable declaration:",
|
||||
Pos.get_position (Desugared.Ast.ScopeVar.get_info x_uid) );
|
||||
Marked.get_mark (Desugared.Ast.ScopeVar.get_info x_uid) );
|
||||
]
|
||||
"This definition does not indicate which state has to be \
|
||||
considered for variable %a."
|
||||
@ -638,9 +626,9 @@ let process_definition
|
||||
(fun (s_ctxt : scope_context option) ->
|
||||
let def_key =
|
||||
get_def_key
|
||||
(Pos.unmark d.definition_name)
|
||||
(Marked.unmark d.definition_name)
|
||||
d.definition_state s_name ctxt
|
||||
(Pos.get_position d.definition_expr)
|
||||
(Marked.get_mark d.definition_expr)
|
||||
in
|
||||
match s_ctxt with
|
||||
| None -> assert false (* should not happen *)
|
||||
@ -659,7 +647,6 @@ let process_definition
|
||||
definition for this definition key *)
|
||||
default_exception_rulename = None;
|
||||
label_idmap = Desugared.Ast.IdentMap.empty;
|
||||
label_groups = Desugared.Ast.LabelMap.empty;
|
||||
}
|
||||
~some:(fun x -> x)
|
||||
def_key_ctx
|
||||
@ -671,7 +658,7 @@ let process_definition
|
||||
| None -> def_key_ctx
|
||||
| Some label ->
|
||||
let new_label_idmap =
|
||||
Desugared.Ast.IdentMap.update (Pos.unmark label)
|
||||
Desugared.Ast.IdentMap.update (Marked.unmark label)
|
||||
(fun existing_label ->
|
||||
match existing_label with
|
||||
| Some existing_label -> Some existing_label
|
||||
@ -679,27 +666,7 @@ let process_definition
|
||||
Some (Desugared.Ast.LabelName.fresh label))
|
||||
def_key_ctx.label_idmap
|
||||
in
|
||||
let label_id =
|
||||
Desugared.Ast.IdentMap.find (Pos.unmark label)
|
||||
new_label_idmap
|
||||
in
|
||||
{
|
||||
def_key_ctx with
|
||||
label_idmap = new_label_idmap;
|
||||
label_groups =
|
||||
Desugared.Ast.LabelMap.update label_id
|
||||
(fun group ->
|
||||
match group with
|
||||
| None ->
|
||||
Some
|
||||
(Desugared.Ast.RuleSet.singleton
|
||||
d.definition_id)
|
||||
| Some existing_group ->
|
||||
Some
|
||||
(Desugared.Ast.RuleSet.add d.definition_id
|
||||
existing_group))
|
||||
def_key_ctx.label_groups;
|
||||
}
|
||||
{ def_key_ctx with label_idmap = new_label_idmap }
|
||||
in
|
||||
(* And second, we update the map of default rulenames for
|
||||
unlabeled exceptions *)
|
||||
@ -720,7 +687,7 @@ let process_definition
|
||||
default_exception_rulename =
|
||||
Some
|
||||
(Ambiguous
|
||||
([Pos.get_position d.definition_name]
|
||||
([Marked.get_mark d.definition_name]
|
||||
@
|
||||
match old with
|
||||
| Ambiguous old -> old
|
||||
@ -737,7 +704,7 @@ let process_definition
|
||||
default_exception_rulename =
|
||||
Some
|
||||
(Ambiguous
|
||||
[Pos.get_position d.definition_name]);
|
||||
[Marked.get_mark d.definition_name]);
|
||||
}
|
||||
(* This is a possible default definition for this
|
||||
key. We create and store a fresh rulename *)
|
||||
@ -748,7 +715,7 @@ let process_definition
|
||||
Some
|
||||
(Unique
|
||||
( d.definition_id,
|
||||
Pos.get_position d.definition_name ));
|
||||
Marked.get_mark d.definition_name ));
|
||||
}))
|
||||
in
|
||||
Some def_key_ctx)
|
||||
@ -760,8 +727,8 @@ let process_definition
|
||||
let process_scope_use_item
|
||||
(s_name : Scopelang.Ast.ScopeName.t)
|
||||
(ctxt : context)
|
||||
(sitem : Ast.scope_use_item Pos.marked) : context =
|
||||
match Pos.unmark sitem with
|
||||
(sitem : Ast.scope_use_item Marked.pos) : context =
|
||||
match Marked.unmark sitem with
|
||||
| Rule r -> process_definition ctxt s_name (Ast.rule_to_def r)
|
||||
| Definition d -> process_definition ctxt s_name d
|
||||
| _ -> ctxt
|
||||
@ -770,20 +737,20 @@ let process_scope_use (ctxt : context) (suse : Ast.scope_use) : context =
|
||||
let s_name =
|
||||
try
|
||||
Desugared.Ast.IdentMap.find
|
||||
(Pos.unmark suse.Ast.scope_use_name)
|
||||
(Marked.unmark suse.Ast.scope_use_name)
|
||||
ctxt.scope_idmap
|
||||
with Not_found ->
|
||||
Errors.raise_spanned_error
|
||||
(Pos.get_position suse.Ast.scope_use_name)
|
||||
(Marked.get_mark suse.Ast.scope_use_name)
|
||||
"\"%a\": this scope has not been declared anywhere, is it a typo?"
|
||||
(Utils.Cli.format_with_style [ANSITerminal.yellow])
|
||||
(Pos.unmark suse.Ast.scope_use_name)
|
||||
(Marked.unmark suse.Ast.scope_use_name)
|
||||
in
|
||||
List.fold_left (process_scope_use_item s_name) ctxt suse.Ast.scope_use_items
|
||||
|
||||
let process_use_item (ctxt : context) (item : Ast.code_item Pos.marked) :
|
||||
let process_use_item (ctxt : context) (item : Ast.code_item Marked.pos) :
|
||||
context =
|
||||
match Pos.unmark item with
|
||||
match Marked.unmark item with
|
||||
| ScopeDecl _ | StructDecl _ | EnumDecl _ -> ctxt
|
||||
| ScopeUse suse -> process_scope_use ctxt suse
|
||||
|
||||
|
@ -27,12 +27,11 @@ type typ = Scopelang.Ast.typ
|
||||
|
||||
type unique_rulename =
|
||||
| Ambiguous of Pos.t list
|
||||
| Unique of Desugared.Ast.RuleName.t Pos.marked
|
||||
| Unique of Desugared.Ast.RuleName.t Marked.pos
|
||||
|
||||
type scope_def_context = {
|
||||
default_exception_rulename : unique_rulename option;
|
||||
label_idmap : Desugared.Ast.LabelName.t Desugared.Ast.IdentMap.t;
|
||||
label_groups : Desugared.Ast.RuleSet.t Desugared.Ast.LabelMap.t;
|
||||
}
|
||||
|
||||
type scope_context = {
|
||||
@ -47,14 +46,14 @@ type scope_context = {
|
||||
}
|
||||
(** Inside a scope, we distinguish between the variables and the subscopes. *)
|
||||
|
||||
type struct_context = typ Pos.marked Scopelang.Ast.StructFieldMap.t
|
||||
type struct_context = typ Marked.pos Scopelang.Ast.StructFieldMap.t
|
||||
(** Types of the fields of a struct *)
|
||||
|
||||
type enum_context = typ Pos.marked Scopelang.Ast.EnumConstructorMap.t
|
||||
type enum_context = typ Marked.pos Scopelang.Ast.EnumConstructorMap.t
|
||||
(** Types of the payloads of the cases of an enum *)
|
||||
|
||||
type var_sig = {
|
||||
var_sig_typ : typ Pos.marked;
|
||||
var_sig_typ : typ Marked.pos;
|
||||
var_sig_is_condition : bool;
|
||||
var_sig_io : Ast.scope_decl_context_io;
|
||||
var_sig_states_idmap : Desugared.Ast.StateName.t Desugared.Ast.IdentMap.t;
|
||||
@ -98,11 +97,11 @@ val raise_unsupported_feature : string -> Pos.t -> 'a
|
||||
(** Temporary function raising an error message saying that a feature is not
|
||||
supported yet *)
|
||||
|
||||
val raise_unknown_identifier : string -> ident Pos.marked -> 'a
|
||||
val raise_unknown_identifier : string -> ident Marked.pos -> 'a
|
||||
(** Function to call whenever an identifier used somewhere has not been declared
|
||||
in the program previously *)
|
||||
|
||||
val get_var_typ : context -> Desugared.Ast.ScopeVar.t -> typ Pos.marked
|
||||
val get_var_typ : context -> Desugared.Ast.ScopeVar.t -> typ Marked.pos
|
||||
(** Gets the type associated to an uid *)
|
||||
|
||||
val is_var_cond : context -> Desugared.Ast.ScopeVar.t -> bool
|
||||
@ -113,14 +112,14 @@ val get_var_io :
|
||||
val get_var_uid :
|
||||
Scopelang.Ast.ScopeName.t ->
|
||||
context ->
|
||||
ident Pos.marked ->
|
||||
ident Marked.pos ->
|
||||
Desugared.Ast.ScopeVar.t
|
||||
(** Get the variable uid inside the scope given in argument *)
|
||||
|
||||
val get_subscope_uid :
|
||||
Scopelang.Ast.ScopeName.t ->
|
||||
context ->
|
||||
ident Pos.marked ->
|
||||
ident Marked.pos ->
|
||||
Scopelang.Ast.SubScopeName.t
|
||||
(** Get the subscope uid inside the scope given in argument *)
|
||||
|
||||
@ -132,26 +131,18 @@ val belongs_to :
|
||||
context -> Desugared.Ast.ScopeVar.t -> Scopelang.Ast.ScopeName.t -> bool
|
||||
(** Checks if the var_uid belongs to the scope scope_uid *)
|
||||
|
||||
val get_def_typ : context -> Desugared.Ast.ScopeDef.t -> typ Pos.marked
|
||||
val get_def_typ : context -> Desugared.Ast.ScopeDef.t -> typ Marked.pos
|
||||
(** Retrieves the type of a scope definition from the context *)
|
||||
|
||||
val is_def_cond : context -> Desugared.Ast.ScopeDef.t -> bool
|
||||
val is_type_cond : Ast.typ Marked.pos -> bool
|
||||
|
||||
val label_groups :
|
||||
context ->
|
||||
Scopelang.Ast.ScopeName.t ->
|
||||
Desugared.Ast.ScopeDef.t ->
|
||||
Desugared.Ast.RuleSet.t Desugared.Ast.LabelMap.t
|
||||
|
||||
val is_type_cond : Ast.typ Pos.marked -> bool
|
||||
|
||||
val add_def_local_var :
|
||||
context -> ident Pos.marked -> context * Desugared.Ast.Var.t
|
||||
val add_def_local_var : context -> ident -> context * Desugared.Ast.Var.t
|
||||
(** Adds a binding to the context *)
|
||||
|
||||
val get_def_key :
|
||||
Ast.qident ->
|
||||
Ast.ident Pos.marked option ->
|
||||
Ast.ident Marked.pos option ->
|
||||
Scopelang.Ast.ScopeName.t ->
|
||||
context ->
|
||||
Pos.t ->
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -126,9 +126,6 @@ unit_literal:
|
||||
| MONTH { (Month, Pos.from_lpos $sloc) }
|
||||
| DAY { (Day, Pos.from_lpos $sloc) }
|
||||
|
||||
date_int:
|
||||
| d = INT_LITERAL { (int_of_string d, Pos.from_lpos $sloc) }
|
||||
|
||||
literal:
|
||||
| l = num_literal u = option(unit_literal) {
|
||||
(LNumber (l, u), Pos.from_lpos $sloc)
|
||||
@ -140,7 +137,8 @@ literal:
|
||||
money_amount_cents = cents;
|
||||
}, Pos.from_lpos $sloc)
|
||||
}
|
||||
| VERTICAL y = date_int MINUS m = date_int MINUS d = date_int VERTICAL {
|
||||
| VERTICAL d = DATE_LITERAL VERTICAL {
|
||||
let (y,m,d) = d in
|
||||
(LDate {
|
||||
literal_date_year = y;
|
||||
literal_date_month = m;
|
||||
@ -176,18 +174,18 @@ compare_op:
|
||||
|
||||
aggregate_func:
|
||||
| CONTENT MAXIMUM t = typ_base INIT init = primitive_expression {
|
||||
(Aggregate (AggregateArgExtremum (true, Pos.unmark t, init)), Pos.from_lpos $sloc)
|
||||
(Aggregate (AggregateArgExtremum (true, Marked.unmark t, init)), Pos.from_lpos $sloc)
|
||||
}
|
||||
| CONTENT MINIMUM t = typ_base INIT init = primitive_expression {
|
||||
(Aggregate (AggregateArgExtremum (false, Pos.unmark t, init)), Pos.from_lpos $sloc)
|
||||
(Aggregate (AggregateArgExtremum (false, Marked.unmark t, init)), Pos.from_lpos $sloc)
|
||||
}
|
||||
| MAXIMUM t = typ_base INIT init = primitive_expression {
|
||||
(Aggregate (AggregateExtremum (true, Pos.unmark t, init)), Pos.from_lpos $sloc)
|
||||
(Aggregate (AggregateExtremum (true, Marked.unmark t, init)), Pos.from_lpos $sloc)
|
||||
}
|
||||
| MINIMUM t = typ_base INIT init = primitive_expression {
|
||||
(Aggregate (AggregateExtremum (false, Pos.unmark t, init)), Pos.from_lpos $sloc)
|
||||
(Aggregate (AggregateExtremum (false, Marked.unmark t, init)), Pos.from_lpos $sloc)
|
||||
}
|
||||
| SUM t = typ_base { (Aggregate (AggregateSum (Pos.unmark t)), Pos.from_lpos $sloc) }
|
||||
| SUM t = typ_base { (Aggregate (AggregateSum (Marked.unmark t)), Pos.from_lpos $sloc) }
|
||||
| CARDINAL { (Aggregate AggregateCount, Pos.from_lpos $sloc) }
|
||||
| FILTER { (Filter, Pos.from_lpos $sloc ) }
|
||||
| MAP { (Map, Pos.from_lpos $sloc) }
|
||||
@ -207,8 +205,8 @@ base_expression:
|
||||
| e = primitive_expression WITH c = constructor_binding {
|
||||
(TestMatchCase (e, (c, Pos.from_lpos $sloc)), Pos.from_lpos $sloc)
|
||||
}
|
||||
| e1 = primitive_expression IN e2 = base_expression {
|
||||
(MemCollection (e1, e2), Pos.from_lpos $sloc)
|
||||
| e1 = primitive_expression CONTAINS e2 = base_expression {
|
||||
(MemCollection (e2, e1), Pos.from_lpos $sloc)
|
||||
}
|
||||
|
||||
unop:
|
||||
@ -379,7 +377,7 @@ rule:
|
||||
state = option(state)
|
||||
consequence = rule_consequence {
|
||||
let (name, param_applied) = name_and_param in
|
||||
let cons : bool Pos.marked = consequence in
|
||||
let cons : bool Marked.pos = consequence in
|
||||
let rule_exception = match except with | None -> NotAnException | Some x -> x in
|
||||
({
|
||||
rule_label = label;
|
||||
@ -388,7 +386,7 @@ rule:
|
||||
rule_condition = cond;
|
||||
rule_name = name;
|
||||
rule_id = Desugared.Ast.RuleName.fresh
|
||||
(String.concat "." (List.map (fun i -> Pos.unmark i) (Pos.unmark name)),
|
||||
(String.concat "." (List.map (fun i -> Marked.unmark i) (Marked.unmark name)),
|
||||
Pos.from_lpos $sloc);
|
||||
rule_consequence = cons;
|
||||
rule_state = state;
|
||||
@ -425,7 +423,7 @@ definition:
|
||||
definition_condition = cond;
|
||||
definition_id =
|
||||
Desugared.Ast.RuleName.fresh
|
||||
(String.concat "." (List.map (fun i -> Pos.unmark i) (Pos.unmark name)),
|
||||
(String.concat "." (List.map (fun i -> Marked.unmark i) (Marked.unmark name)),
|
||||
Pos.from_lpos $sloc);
|
||||
definition_expr = e;
|
||||
definition_state = state;
|
||||
|
@ -305,7 +305,9 @@ and expand_includes
|
||||
match command with
|
||||
| Ast.LawInclude (Ast.CatalaFile sub_source) ->
|
||||
let source_dir = Filename.dirname source_file in
|
||||
let sub_source = Filename.concat source_dir (Pos.unmark sub_source) in
|
||||
let sub_source =
|
||||
Filename.concat source_dir (Marked.unmark sub_source)
|
||||
in
|
||||
let includ_program = parse_source_file (FileName sub_source) language in
|
||||
{
|
||||
Ast.program_source_files =
|
||||
|
@ -32,12 +32,13 @@
|
||||
%token<string> CONSTRUCTOR IDENT
|
||||
%token<string> END_CODE
|
||||
%token<string> INT_LITERAL
|
||||
%token<int * int * int> DATE_LITERAL
|
||||
%token TRUE FALSE
|
||||
%token<string * string> DECIMAL_LITERAL
|
||||
%token<string * string> MONEY_AMOUNT
|
||||
%token BEGIN_CODE TEXT
|
||||
%token COLON ALT DATA VERTICAL
|
||||
%token OF INTEGER COLLECTION
|
||||
%token OF INTEGER COLLECTION CONTAINS
|
||||
%token RULE CONDITION DEFINED_AS
|
||||
%token LESSER GREATER LESSER_EQUAL GREATER_EQUAL
|
||||
%token LESSER_DEC GREATER_DEC LESSER_EQUAL_DEC GREATER_EQUAL_DEC
|
||||
|
@ -94,18 +94,35 @@ let file =
|
||||
let debug =
|
||||
Arg.(value & flag & info ["debug"; "d"] ~doc:"Prints debug information.")
|
||||
|
||||
type when_enum = Auto | Always | Never
|
||||
|
||||
let when_opt = Arg.enum ["auto", Auto; "always", Always; "never", Never]
|
||||
|
||||
let color =
|
||||
Arg.(
|
||||
value
|
||||
& opt ~vopt:Always when_opt Auto
|
||||
& info ["color"]
|
||||
~doc:
|
||||
"Allow output of colored and styled text. If set to $(i,auto), \
|
||||
enabled when the standard output is to a terminal.")
|
||||
|
||||
let unstyled =
|
||||
Arg.(
|
||||
value & flag
|
||||
value
|
||||
& flag
|
||||
& info ["unstyled"; "u"]
|
||||
~doc:"Removes styling (colors, etc.) from terminal output.")
|
||||
~doc:
|
||||
"Removes styling (colors, etc.) from terminal output. Equivalent to \
|
||||
$(b,--color=never)")
|
||||
|
||||
let optimize =
|
||||
Arg.(value & flag & info ["optimize"; "O"] ~doc:"Run compiler optimizations.")
|
||||
|
||||
let trace_opt =
|
||||
Arg.(
|
||||
value & flag
|
||||
value
|
||||
& flag
|
||||
& info ["trace"; "t"]
|
||||
~doc:
|
||||
"Displays a trace of the interpreter's computation or generates \
|
||||
@ -113,25 +130,29 @@ let trace_opt =
|
||||
|
||||
let avoid_exceptions =
|
||||
Arg.(
|
||||
value & flag
|
||||
value
|
||||
& flag
|
||||
& info ["avoid_exceptions"]
|
||||
~doc:"Compiles the default calculus without exceptions")
|
||||
|
||||
let closure_conversion =
|
||||
Arg.(
|
||||
value & flag
|
||||
value
|
||||
& flag
|
||||
& info ["closure_conversion"]
|
||||
~doc:"Performs closure conversion on the lambda calculus")
|
||||
|
||||
let wrap_weaved_output =
|
||||
Arg.(
|
||||
value & flag
|
||||
value
|
||||
& flag
|
||||
& info ["wrap"; "w"]
|
||||
~doc:"Wraps literate programming output with a minimal preamble.")
|
||||
|
||||
let print_only_law =
|
||||
Arg.(
|
||||
value & flag
|
||||
value
|
||||
& flag
|
||||
& info ["print_only_law"]
|
||||
~doc:
|
||||
"In literate programming output, skip all code and metadata sections \
|
||||
@ -174,7 +195,8 @@ let max_prec_digits_opt =
|
||||
|
||||
let disable_counterexamples_opt =
|
||||
Arg.(
|
||||
value & flag
|
||||
value
|
||||
& flag
|
||||
& info
|
||||
["disable_counterexamples"]
|
||||
~doc:
|
||||
@ -200,7 +222,7 @@ let output =
|
||||
|
||||
type options = {
|
||||
debug : bool;
|
||||
unstyled : bool;
|
||||
color : when_enum;
|
||||
wrap_weaved_output : bool;
|
||||
avoid_exceptions : bool;
|
||||
backend : string;
|
||||
@ -219,6 +241,7 @@ type options = {
|
||||
let options =
|
||||
let make
|
||||
debug
|
||||
color
|
||||
unstyled
|
||||
wrap_weaved_output
|
||||
avoid_exceptions
|
||||
@ -235,7 +258,7 @@ let options =
|
||||
print_only_law : options =
|
||||
{
|
||||
debug;
|
||||
unstyled;
|
||||
color = (if unstyled then Never else color);
|
||||
wrap_weaved_output;
|
||||
avoid_exceptions;
|
||||
backend;
|
||||
@ -252,16 +275,33 @@ let options =
|
||||
}
|
||||
in
|
||||
Term.(
|
||||
const make $ debug $ unstyled $ wrap_weaved_output $ avoid_exceptions
|
||||
$ closure_conversion $ backend $ plugins_dirs $ language
|
||||
$ max_prec_digits_opt $ trace_opt $ disable_counterexamples_opt $ optimize
|
||||
$ ex_scope $ output $ print_only_law)
|
||||
const make
|
||||
$ debug
|
||||
$ color
|
||||
$ unstyled
|
||||
$ wrap_weaved_output
|
||||
$ avoid_exceptions
|
||||
$ closure_conversion
|
||||
$ backend
|
||||
$ plugins_dirs
|
||||
$ language
|
||||
$ max_prec_digits_opt
|
||||
$ trace_opt
|
||||
$ disable_counterexamples_opt
|
||||
$ optimize
|
||||
$ ex_scope
|
||||
$ output
|
||||
$ print_only_law)
|
||||
|
||||
let catala_t f = Term.(const f $ file $ options)
|
||||
|
||||
let set_option_globals options : unit =
|
||||
debug_flag := options.debug;
|
||||
style_flag := not options.unstyled;
|
||||
(style_flag :=
|
||||
match options.color with
|
||||
| Always -> true
|
||||
| Never -> false
|
||||
| Auto -> Unix.isatty Unix.stdout);
|
||||
trace_flag := options.trace;
|
||||
optimize_flag := options.optimize;
|
||||
disable_counterexamples := options.disable_counterexamples;
|
||||
@ -361,6 +401,13 @@ let format_with_style (styles : ANSITerminal.style list) fmt (str : string) =
|
||||
(ANSITerminal.sprintf styles "%s" str)
|
||||
else Format.pp_print_string fmt str
|
||||
|
||||
let call_unstyled f =
|
||||
let prev = !style_flag in
|
||||
style_flag := false;
|
||||
let res = f () in
|
||||
style_flag := prev;
|
||||
res
|
||||
|
||||
let time_marker () =
|
||||
let new_time = Unix.gettimeofday () in
|
||||
let old_time = !time in
|
||||
@ -405,7 +452,9 @@ let concat_with_line_depending_prefix_and_suffix
|
||||
let out, _ =
|
||||
List.fold_left
|
||||
(fun (acc, i) s ->
|
||||
( (acc ^ prefix i ^ s
|
||||
( (acc
|
||||
^ prefix i
|
||||
^ s
|
||||
^ if i = List.length ss - 1 then "" else suffix i),
|
||||
i + 1 ))
|
||||
((prefix 0 ^ hd ^ if 0 = List.length ss - 1 then "" else suffix 0), 1)
|
||||
|
@ -81,9 +81,12 @@ val max_prec_digits_opt : int option Cmdliner.Term.t
|
||||
val ex_scope : string option Cmdliner.Term.t
|
||||
val output : string option Cmdliner.Term.t
|
||||
|
||||
(** The usual auto/always/never option argument *)
|
||||
type when_enum = Auto | Always | Never
|
||||
|
||||
type options = {
|
||||
debug : bool;
|
||||
unstyled : bool;
|
||||
color : when_enum;
|
||||
wrap_weaved_output : bool;
|
||||
avoid_exceptions : bool;
|
||||
backend : string;
|
||||
@ -118,6 +121,10 @@ val with_style : ANSITerminal.style list -> ('a, unit, string) format -> 'a
|
||||
val format_with_style :
|
||||
ANSITerminal.style list -> Format.formatter -> string -> unit
|
||||
|
||||
val call_unstyled : (unit -> 'a) -> 'a
|
||||
(** [call_unstyled f] calls the function [f] with the [style_flag] set to false
|
||||
during the execution. *)
|
||||
|
||||
val debug_marker : unit -> string
|
||||
val error_marker : unit -> string
|
||||
val warning_marker : unit -> string
|
||||
|
@ -1,7 +1,7 @@
|
||||
(library
|
||||
(name utils)
|
||||
(public_name catala.utils)
|
||||
(libraries cmdliner ANSITerminal re))
|
||||
(libraries cmdliner ubase ANSITerminal re))
|
||||
|
||||
(documentation
|
||||
(package catala)
|
||||
|
@ -45,3 +45,18 @@ let with_formatter_of_opt_file filename_opt f =
|
||||
match filename_opt with
|
||||
| None -> finally (fun () -> flush stdout) (fun () -> f Format.std_formatter)
|
||||
| Some filename -> with_formatter_of_file filename f
|
||||
|
||||
let get_out_channel ~source_file ~output_file ?ext () =
|
||||
match output_file, ext with
|
||||
| Some "-", _ | None, None -> None, fun f -> f stdout
|
||||
| Some f, _ -> Some f, with_out_channel f
|
||||
| None, Some ext ->
|
||||
let src =
|
||||
match source_file with Pos.FileName f -> f | Pos.Contents _ -> "a"
|
||||
in
|
||||
let f = Filename.remove_extension src ^ ext in
|
||||
Some f, with_out_channel f
|
||||
|
||||
let get_formatter_of_out_channel ~source_file ~output_file ?ext () =
|
||||
let f, with_ = get_out_channel ~source_file ~output_file ?ext () in
|
||||
f, fun fmt -> with_ (fun oc -> with_formatter_of_out_channel oc fmt)
|
||||
|
@ -40,3 +40,23 @@ val with_formatter_of_opt_file : string option -> (Format.formatter -> 'a) -> 'a
|
||||
(** [with_formatter_of_opt_file filename_opt f] manages the formatter created
|
||||
from the file [filename_opt] if there is some (see
|
||||
{!with_formatter_of_file}), otherwise, uses the [Format.std_formatter]. *)
|
||||
|
||||
val get_out_channel :
|
||||
source_file:Pos.input_file ->
|
||||
output_file:string option ->
|
||||
?ext:string ->
|
||||
unit ->
|
||||
string option * ((out_channel -> 'a) -> 'a)
|
||||
(** [get_output ~source_file ~output_file ?ext ()] returns the infered filename
|
||||
and its corresponding [with_out_channel] function. If the [output_file] is
|
||||
equal to [Some "-"] returns a wrapper around [stdout]. *)
|
||||
|
||||
val get_formatter_of_out_channel :
|
||||
source_file:Pos.input_file ->
|
||||
output_file:string option ->
|
||||
?ext:string ->
|
||||
unit ->
|
||||
string option * ((Format.formatter -> 'a) -> 'a)
|
||||
(** [get_output_format ~source_file ~output_file ?ext ()] returns the infered
|
||||
filename and its corresponding [with_formatter_of_out_channel] function. If
|
||||
the [output_file] is equal to [Some "-"] returns a wrapper around [stdout]. *)
|
||||
|
78
compiler/utils/marked.ml
Normal file
78
compiler/utils/marked.ml
Normal file
@ -0,0 +1,78 @@
|
||||
(* This file is part of the Catala compiler, a specification language for tax
|
||||
and social benefits computation rules. Copyright (C) 2020 Inria,
|
||||
contributors: Denis Merigoux <denis.merigoux@inria.fr>, Louis Gesbert
|
||||
<louis.gesbert@inria.fr>
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
use this file except in compliance with the License. You may obtain a copy of
|
||||
the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
License for the specific language governing permissions and limitations under
|
||||
the License. *)
|
||||
|
||||
type ('a, 'm) t = 'a * 'm
|
||||
type 'a pos = ('a, Pos.t) t
|
||||
|
||||
let mark m e : ('a, 'm) t = e, m
|
||||
let unmark ((x, _) : ('a, 'm) t) : 'a = x
|
||||
let get_mark ((_, x) : ('a, 'm) t) : 'm = x
|
||||
let map_under_mark (f : 'a -> 'b) ((x, y) : ('a, 'm) t) : ('b, 'c) t = f x, y
|
||||
let same_mark_as (x : 'a) ((_, y) : ('b, 'm) t) : ('a, 'm) t = x, y
|
||||
|
||||
let unmark_option (x : ('a, 'm) t option) : 'a option =
|
||||
match x with Some x -> Some (unmark x) | None -> None
|
||||
|
||||
let compare (cmp : 'a -> 'a -> int) ((x, _) : ('a, 'm) t) ((y, _) : ('a, 'm) t)
|
||||
: int =
|
||||
cmp x y
|
||||
|
||||
class ['self] marked_map =
|
||||
object (_self : 'self)
|
||||
constraint
|
||||
'self = < visit_marked :
|
||||
'a. ('env -> 'a -> 'a) -> 'env -> ('a, 'm) t -> ('a, 'm) t
|
||||
; .. >
|
||||
|
||||
method visit_marked
|
||||
: 'a. ('env -> 'a -> 'a) -> 'env -> ('a, 'm) t -> ('a, 'm) t =
|
||||
fun f env x -> same_mark_as (f env (unmark x)) x
|
||||
end
|
||||
|
||||
class ['self] marked_iter =
|
||||
object (_self : 'self)
|
||||
constraint
|
||||
'self = < visit_marked :
|
||||
'a. ('env -> 'a -> unit) -> 'env -> ('a, 'm) t -> unit
|
||||
; .. >
|
||||
|
||||
method visit_marked : 'a. ('env -> 'a -> unit) -> 'env -> ('a, 'm) t -> unit
|
||||
=
|
||||
fun f env x -> f env (unmark x)
|
||||
end
|
||||
|
||||
class ['self] pos_map =
|
||||
object (_self : 'self)
|
||||
constraint
|
||||
'self = < visit_pos :
|
||||
'a. ('env -> 'a -> 'a) -> 'env -> ('a, 'm) t -> ('a, 'm) t
|
||||
; .. >
|
||||
|
||||
method visit_pos
|
||||
: 'a. ('env -> 'a -> 'a) -> 'env -> ('a, 'm) t -> ('a, 'm) t =
|
||||
fun f env x -> same_mark_as (f env (unmark x)) x
|
||||
end
|
||||
|
||||
class ['self] pos_iter =
|
||||
object (_self : 'self)
|
||||
constraint
|
||||
'self = < visit_pos : 'a. ('env -> 'a -> unit) -> 'env -> ('a, 'm) t -> unit
|
||||
; .. >
|
||||
|
||||
method visit_pos : 'a. ('env -> 'a -> unit) -> 'env -> ('a, 'm) t -> unit =
|
||||
fun f env x -> f env (unmark x)
|
||||
end
|
78
compiler/utils/marked.mli
Normal file
78
compiler/utils/marked.mli
Normal file
@ -0,0 +1,78 @@
|
||||
(* This file is part of the Catala compiler, a specification language for tax
|
||||
and social benefits computation rules. Copyright (C) 2020 Inria,
|
||||
contributors: Denis Merigoux <denis.merigoux@inria.fr>, Louis Gesbert
|
||||
<louis.gesbert@inria.fr>
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
use this file except in compliance with the License. You may obtain a copy of
|
||||
the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
License for the specific language governing permissions and limitations under
|
||||
the License. *)
|
||||
|
||||
(** AST node annotations (used for position, type, etc.) *)
|
||||
|
||||
type ('a, 'm) t = 'a * 'm
|
||||
(** Everything related to the source code should keep at least its position
|
||||
stored, to improve error messages *)
|
||||
|
||||
type 'a pos = ('a, Pos.t) t
|
||||
(** The type of marks containing only position information *)
|
||||
|
||||
val mark : 'm -> 'a -> ('a, 'm) t
|
||||
val unmark : ('a, 'm) t -> 'a
|
||||
val get_mark : ('a, 'm) t -> 'm
|
||||
val map_under_mark : ('a -> 'b) -> ('a, 'm) t -> ('b, 'm) t
|
||||
val same_mark_as : 'a -> ('b, 'm) t -> ('a, 'm) t
|
||||
val unmark_option : ('a, 'm) t option -> 'a option
|
||||
|
||||
val compare : ('a -> 'a -> int) -> ('a, 'm) t -> ('a, 'm) t -> int
|
||||
(** Compares two marked values {b ignoring positions} *)
|
||||
|
||||
(** Visitors *)
|
||||
|
||||
class ['self] marked_map :
|
||||
object ('self)
|
||||
constraint
|
||||
'self = < visit_marked :
|
||||
'a. ('env -> 'a -> 'a) -> 'env -> ('a, 'm) t -> ('a, 'm) t
|
||||
; .. >
|
||||
|
||||
method visit_marked :
|
||||
'a. ('env -> 'a -> 'a) -> 'env -> ('a, 'm) t -> ('a, 'm) t
|
||||
end
|
||||
|
||||
class ['self] marked_iter :
|
||||
object ('self)
|
||||
constraint
|
||||
'self = < visit_marked :
|
||||
'a. ('env -> 'a -> unit) -> 'env -> ('a, 'm) t -> unit
|
||||
; .. >
|
||||
|
||||
method visit_marked : 'a. ('env -> 'a -> unit) -> 'env -> ('a, 'm) t -> unit
|
||||
end
|
||||
|
||||
class ['self] pos_map :
|
||||
object ('self)
|
||||
constraint
|
||||
'self = < visit_pos :
|
||||
'a. ('env -> 'a -> 'a) -> 'env -> ('a, 'm) t -> ('a, 'm) t
|
||||
; .. >
|
||||
|
||||
method visit_pos :
|
||||
'a. ('env -> 'a -> 'a) -> 'env -> ('a, 'm) t -> ('a, 'm) t
|
||||
end
|
||||
|
||||
class ['self] pos_iter :
|
||||
object ('self)
|
||||
constraint
|
||||
'self = < visit_pos : 'a. ('env -> 'a -> unit) -> 'env -> ('a, 'm) t -> unit
|
||||
; .. >
|
||||
|
||||
method visit_pos : 'a. ('env -> 'a -> unit) -> 'env -> ('a, 'm) t -> unit
|
||||
end
|
@ -203,8 +203,6 @@ let retrieve_loc_text (pos : t) : string =
|
||||
else Cli.with_style blue_style "%*s+-+ " (spaces + (2 * i) - 1) ""))
|
||||
with Sys_error _ -> "Location:" ^ to_string pos
|
||||
|
||||
type 'a marked = 'a * t
|
||||
|
||||
let no_pos : t =
|
||||
let zero_pos =
|
||||
{
|
||||
@ -215,42 +213,3 @@ let no_pos : t =
|
||||
}
|
||||
in
|
||||
{ code_pos = zero_pos, zero_pos; law_pos = [] }
|
||||
|
||||
let mark pos e : 'a marked = e, pos
|
||||
let unmark ((x, _) : 'a marked) : 'a = x
|
||||
let get_position ((_, x) : 'a marked) : t = x
|
||||
let map_under_mark (f : 'a -> 'b) ((x, y) : 'a marked) : 'b marked = f x, y
|
||||
let same_pos_as (x : 'a) ((_, y) : 'b marked) : 'a marked = x, y
|
||||
|
||||
let compare_marked
|
||||
(cmp : 'a -> 'a -> int)
|
||||
((x, _) : 'a marked)
|
||||
((y, _) : 'a marked) : int =
|
||||
cmp x y
|
||||
|
||||
let unmark_option (x : 'a marked option) : 'a option =
|
||||
match x with Some x -> Some (unmark x) | None -> None
|
||||
|
||||
class ['self] marked_map =
|
||||
object (_self : 'self)
|
||||
constraint
|
||||
'self = < visit_marked :
|
||||
'a. ('env -> 'a -> 'a) -> 'env -> 'a marked -> 'a marked
|
||||
; .. >
|
||||
|
||||
method visit_marked
|
||||
: 'a. ('env -> 'a -> 'a) -> 'env -> 'a marked -> 'a marked =
|
||||
fun f env x -> same_pos_as (f env (unmark x)) x
|
||||
end
|
||||
|
||||
class ['self] marked_iter =
|
||||
object (_self : 'self)
|
||||
constraint
|
||||
'self = < visit_marked :
|
||||
'a. ('env -> 'a -> unit) -> 'env -> 'a marked -> unit
|
||||
; .. >
|
||||
|
||||
method visit_marked : 'a. ('env -> 'a -> unit) -> 'env -> 'a marked -> unit
|
||||
=
|
||||
fun f env x -> f env (unmark x)
|
||||
end
|
||||
|
@ -20,8 +20,6 @@ type t
|
||||
(** A position in the source code is a file, as well as begin and end location
|
||||
of the form col:line *)
|
||||
|
||||
(** Custom visitor for the [Pos.marked] type *)
|
||||
|
||||
(**{2 Constructor and getters}*)
|
||||
|
||||
val from_lpos : Lexing.position * Lexing.position -> t
|
||||
@ -52,44 +50,5 @@ val retrieve_loc_text : t -> string
|
||||
(** Open the file corresponding to the position and retrieves the text concerned
|
||||
by the position *)
|
||||
|
||||
(**{2 AST markings}*)
|
||||
|
||||
type 'a marked = 'a * t
|
||||
(** Everything related to the source code should keep its position stored, to
|
||||
improve error messages *)
|
||||
|
||||
val no_pos : t
|
||||
(** Placeholder position *)
|
||||
|
||||
val mark : t -> 'a -> 'a marked
|
||||
val unmark : 'a marked -> 'a
|
||||
val get_position : 'a marked -> t
|
||||
val map_under_mark : ('a -> 'b) -> 'a marked -> 'b marked
|
||||
val same_pos_as : 'a -> 'b marked -> 'a marked
|
||||
val unmark_option : 'a marked option -> 'a option
|
||||
|
||||
val compare_marked : ('a -> 'a -> int) -> 'a marked -> 'a marked -> int
|
||||
(** Compares two marked values {b ignoring positions} *)
|
||||
|
||||
(** Visitors *)
|
||||
|
||||
class ['self] marked_map :
|
||||
object ('self)
|
||||
constraint
|
||||
'self = < visit_marked :
|
||||
'a. ('env -> 'a -> 'a) -> 'env -> 'a marked -> 'a marked
|
||||
; .. >
|
||||
|
||||
method visit_marked :
|
||||
'a. ('env -> 'a -> 'a) -> 'env -> 'a marked -> 'a marked
|
||||
end
|
||||
|
||||
class ['self] marked_iter :
|
||||
object ('self)
|
||||
constraint
|
||||
'self = < visit_marked :
|
||||
'a. ('env -> 'a -> unit) -> 'env -> 'a marked -> unit
|
||||
; .. >
|
||||
|
||||
method visit_marked : 'a. ('env -> 'a -> unit) -> 'env -> 'a marked -> unit
|
||||
end
|
||||
|
52
compiler/utils/string_common.ml
Normal file
52
compiler/utils/string_common.ml
Normal file
@ -0,0 +1,52 @@
|
||||
(* This file is part of the Catala compiler, a specification language for tax
|
||||
and social benefits computation rules. Copyright (C) 2020 Inria, contributor:
|
||||
Denis Merigoux <denis.merigoux@inria.fr>, Emile Rolley <emile.rolley@tuta.io>
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
use this file except in compliance with the License. You may obtain a copy of
|
||||
the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
License for the specific language governing permissions and limitations under
|
||||
the License. *)
|
||||
|
||||
let to_ascii : string -> string = Ubase.from_utf8
|
||||
|
||||
let is_uppercase_ascii (c : char) : bool =
|
||||
let c = Char.code c in
|
||||
(* 'A' <= c && c <= 'Z' *)
|
||||
0x41 <= c && c <= 0x5b
|
||||
|
||||
let begins_with_uppercase (s : string) : bool =
|
||||
if "" = s then false else is_uppercase_ascii (to_ascii s).[0]
|
||||
|
||||
let to_snake_case (s : string) : string =
|
||||
let out = ref "" in
|
||||
to_ascii s
|
||||
|> String.iteri (fun i c ->
|
||||
out :=
|
||||
!out
|
||||
^ (if is_uppercase_ascii c && 0 <> i then "_" else "")
|
||||
^ String.lowercase_ascii (String.make 1 c));
|
||||
!out
|
||||
|
||||
let to_camel_case (s : string) : string =
|
||||
let last_was_underscore = ref false in
|
||||
let out = ref "" in
|
||||
to_ascii s
|
||||
|> String.iteri (fun i c ->
|
||||
let is_underscore = c = '_' in
|
||||
let c_string = String.make 1 c in
|
||||
out :=
|
||||
!out
|
||||
^
|
||||
if is_underscore then ""
|
||||
else if !last_was_underscore || 0 = i then
|
||||
String.uppercase_ascii c_string
|
||||
else c_string;
|
||||
last_was_underscore := is_underscore);
|
||||
!out
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user