forked from GitHub/gf-core
Compare commits
91 Commits
c-runtime
...
lpgf-strin
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c058457337 | ||
|
|
8f5033e4ce | ||
|
|
126b61ea03 | ||
|
|
99abb9b2a5 | ||
|
|
3e9d12854a | ||
|
|
fd07946a50 | ||
|
|
c76efcf916 | ||
|
|
785d6069e2 | ||
|
|
0f4b349b0b | ||
|
|
dbf369aae5 | ||
|
|
0d4659fe8c | ||
|
|
575a746a3e | ||
|
|
70581c2d8c | ||
|
|
bca1e2286d | ||
|
|
94f76b9e36 | ||
|
|
f5886bf447 | ||
|
|
0ba0438dc7 | ||
|
|
30b016032d | ||
|
|
4082c006c3 | ||
|
|
adc162b374 | ||
|
|
3beed2c49e | ||
|
|
a8e3dc8855 | ||
|
|
997d7c1694 | ||
|
|
4c09e4a340 | ||
|
|
33e0e98aec | ||
|
|
83bc3c9c6e | ||
|
|
f42b5ec9ef | ||
|
|
4771d9c356 | ||
|
|
9785f8351d | ||
|
|
6a5d735904 | ||
|
|
8324ad8801 | ||
|
|
20290be616 | ||
|
|
b4a393ac09 | ||
|
|
9942908df9 | ||
|
|
dca2ebaf72 | ||
|
|
5ad5789b31 | ||
|
|
9f3f4139b1 | ||
|
|
505c12c528 | ||
|
|
023b50557e | ||
|
|
2b0493eece | ||
|
|
51e543878b | ||
|
|
625386a14f | ||
|
|
5240749fad | ||
|
|
e6079523f1 | ||
|
|
866a2101e1 | ||
|
|
d8557e8433 | ||
|
|
7a5bc2dab3 | ||
|
|
9a263450f5 | ||
|
|
8e1fa4981f | ||
|
|
b4fce5db59 | ||
|
|
6a7ead0f84 | ||
|
|
d3988f93d5 | ||
|
|
236dbdbba3 | ||
|
|
768c3d9b2d | ||
|
|
29114ce606 | ||
|
|
5be21dba1c | ||
|
|
d5cf00f711 | ||
|
|
312cfeb69d | ||
|
|
2d03b9ee0c | ||
|
|
4c06c3f825 | ||
|
|
7227ede24b | ||
|
|
398b294734 | ||
|
|
d394cacddf | ||
|
|
21f14c2aa1 | ||
|
|
23e49cddb7 | ||
|
|
4d1217b06d | ||
|
|
4f0abe5540 | ||
|
|
109822675b | ||
|
|
d563abb928 | ||
|
|
a58a6c8a59 | ||
|
|
98f6136ebd | ||
|
|
8cfaa69b6e | ||
|
|
a12f58e7b0 | ||
|
|
d5f68970b9 | ||
|
|
9c2d8eb0b2 | ||
|
|
34f0fc0ba7 | ||
|
|
42b9e7036e | ||
|
|
132f693713 | ||
|
|
153bffdad7 | ||
|
|
d09838e97e | ||
|
|
c94bffe435 | ||
|
|
2a5850023b | ||
|
|
fe15aa0c00 | ||
|
|
cead0cc4c1 | ||
|
|
6f622b496b | ||
|
|
270e7f021f | ||
|
|
32b0860925 | ||
|
|
f24c50339b | ||
|
|
cd5881d83a | ||
|
|
93b81b9f13 | ||
|
|
8ad9cf1e09 |
19
.github/workflows/build-all-versions.yml
vendored
19
.github/workflows/build-all-versions.yml
vendored
@@ -14,7 +14,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||||
cabal: ["latest"]
|
cabal: ["3.2"]
|
||||||
ghc:
|
ghc:
|
||||||
- "8.6.5"
|
- "8.6.5"
|
||||||
- "8.8.3"
|
- "8.8.3"
|
||||||
@@ -33,7 +33,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
if: github.event.action == 'opened' || github.event.action == 'synchronize' || github.event.ref == 'refs/heads/master'
|
if: github.event.action == 'opened' || github.event.action == 'synchronize' || github.event.ref == 'refs/heads/master'
|
||||||
|
|
||||||
- uses: haskell/actions/setup@v1
|
- uses: actions/setup-haskell@v1.1.4
|
||||||
id: setup-haskell-cabal
|
id: setup-haskell-cabal
|
||||||
name: Setup Haskell
|
name: Setup Haskell
|
||||||
with:
|
with:
|
||||||
@@ -65,7 +65,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
stack: ["latest"]
|
stack: ["2.3.3"]
|
||||||
ghc: ["7.10.3","8.0.2", "8.2.2", "8.4.4", "8.6.5", "8.8.4"]
|
ghc: ["7.10.3","8.0.2", "8.2.2", "8.4.4", "8.6.5", "8.8.4"]
|
||||||
# ghc: ["8.8.3"]
|
# ghc: ["8.8.3"]
|
||||||
|
|
||||||
@@ -73,12 +73,11 @@ jobs:
|
|||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
if: github.event.action == 'opened' || github.event.action == 'synchronize' || github.event.ref == 'refs/heads/master'
|
if: github.event.action == 'opened' || github.event.action == 'synchronize' || github.event.ref == 'refs/heads/master'
|
||||||
|
|
||||||
- uses: haskell/actions/setup@v1
|
- uses: actions/setup-haskell@v1.1.4
|
||||||
name: Setup Haskell Stack
|
name: Setup Haskell Stack
|
||||||
with:
|
with:
|
||||||
ghc-version: ${{ matrix.ghc }}
|
# ghc-version: ${{ matrix.ghc }}
|
||||||
stack-version: 'latest'
|
stack-version: ${{ matrix.stack }}
|
||||||
enable-stack: true
|
|
||||||
|
|
||||||
- uses: actions/cache@v1
|
- uses: actions/cache@v1
|
||||||
name: Cache ~/.stack
|
name: Cache ~/.stack
|
||||||
@@ -91,6 +90,6 @@ jobs:
|
|||||||
stack build --system-ghc --stack-yaml stack-ghc${{ matrix.ghc }}.yaml
|
stack build --system-ghc --stack-yaml stack-ghc${{ matrix.ghc }}.yaml
|
||||||
# stack build --system-ghc --test --bench --no-run-tests --no-run-benchmarks
|
# stack build --system-ghc --test --bench --no-run-tests --no-run-benchmarks
|
||||||
|
|
||||||
- name: Test
|
# - name: Test
|
||||||
run: |
|
# run: |
|
||||||
stack test --system-ghc --stack-yaml stack-ghc${{ matrix.ghc }}.yaml
|
# stack test --system-ghc
|
||||||
|
|||||||
75
.github/workflows/build-binary-packages.yml
vendored
75
.github/workflows/build-binary-packages.yml
vendored
@@ -2,8 +2,7 @@ name: Build Binary Packages
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
release:
|
release:
|
||||||
types: ["created"]
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|
||||||
@@ -11,13 +10,11 @@ jobs:
|
|||||||
|
|
||||||
ubuntu:
|
ubuntu:
|
||||||
name: Build Ubuntu package
|
name: Build Ubuntu package
|
||||||
strategy:
|
runs-on: ubuntu-18.04
|
||||||
matrix:
|
# strategy:
|
||||||
os:
|
# matrix:
|
||||||
- ubuntu-18.04
|
# ghc: ["8.6.5"]
|
||||||
- ubuntu-20.04
|
# cabal: ["2.4"]
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
@@ -56,33 +53,19 @@ jobs:
|
|||||||
- name: Upload artifact
|
- name: Upload artifact
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: gf-${{ github.event.release.tag_name }}-${{ matrix.os }}.deb
|
name: gf-${{ github.sha }}-ubuntu
|
||||||
path: dist/gf_*.deb
|
path: dist/gf_*.deb
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
|
|
||||||
- name: Rename package for specific ubuntu version
|
|
||||||
run: |
|
|
||||||
mv dist/gf_*.deb dist/gf-${{ github.event.release.tag_name }}-${{ matrix.os }}.deb
|
|
||||||
|
|
||||||
- uses: actions/upload-release-asset@v1.0.2
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
with:
|
|
||||||
upload_url: ${{ github.event.release.upload_url }}
|
|
||||||
asset_path: dist/gf-${{ github.event.release.tag_name }}-${{ matrix.os }}.deb
|
|
||||||
asset_name: gf-${{ github.event.release.tag_name }}-${{ matrix.os }}.deb
|
|
||||||
asset_content_type: application/octet-stream
|
|
||||||
|
|
||||||
# ---
|
# ---
|
||||||
|
|
||||||
macos:
|
macos:
|
||||||
name: Build macOS package
|
name: Build macOS package
|
||||||
|
runs-on: macos-10.15
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
ghc: ["8.6.5"]
|
ghc: ["8.6.5"]
|
||||||
cabal: ["2.4"]
|
cabal: ["2.4"]
|
||||||
os: ["macos-10.15"]
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
@@ -109,33 +92,19 @@ jobs:
|
|||||||
- name: Upload artifact
|
- name: Upload artifact
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: gf-${{ github.event.release.tag_name }}-macos
|
name: gf-${{ github.sha }}-macos
|
||||||
path: dist/gf-*.pkg
|
path: dist/gf-*.pkg
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
|
|
||||||
- name: Rename package
|
|
||||||
run: |
|
|
||||||
mv dist/gf-*.pkg dist/gf-${{ github.event.release.tag_name }}-macos.pkg
|
|
||||||
|
|
||||||
- uses: actions/upload-release-asset@v1.0.2
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
with:
|
|
||||||
upload_url: ${{ github.event.release.upload_url }}
|
|
||||||
asset_path: dist/gf-${{ github.event.release.tag_name }}-macos.pkg
|
|
||||||
asset_name: gf-${{ github.event.release.tag_name }}-macos.pkg
|
|
||||||
asset_content_type: application/octet-stream
|
|
||||||
|
|
||||||
# ---
|
# ---
|
||||||
|
|
||||||
windows:
|
windows:
|
||||||
name: Build Windows package
|
name: Build Windows package
|
||||||
|
runs-on: windows-2019
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
ghc: ["8.6.5"]
|
ghc: ["8.6.5"]
|
||||||
cabal: ["2.4"]
|
cabal: ["2.4"]
|
||||||
os: ["windows-2019"]
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
@@ -167,18 +136,16 @@ jobs:
|
|||||||
cp /mingw64/bin/libpgf-0.dll /c/tmp-dist/c
|
cp /mingw64/bin/libpgf-0.dll /c/tmp-dist/c
|
||||||
cp /mingw64/bin/libgu-0.dll /c/tmp-dist/c
|
cp /mingw64/bin/libgu-0.dll /c/tmp-dist/c
|
||||||
|
|
||||||
# JAVA_HOME_8_X64 = C:\hostedtoolcache\windows\Java_Adopt_jdk\8.0.292-10\x64
|
|
||||||
- name: Build Java bindings
|
- name: Build Java bindings
|
||||||
shell: msys2 {0}
|
shell: msys2 {0}
|
||||||
run: |
|
run: |
|
||||||
export JDKPATH=/c/hostedtoolcache/windows/Java_Adopt_jdk/8.0.292-10/x64
|
export PATH="${PATH}:/c/Program Files/Java/jdk8u275-b01/bin"
|
||||||
export PATH="${PATH}:${JDKPATH}/bin"
|
|
||||||
cd src/runtime/java
|
cd src/runtime/java
|
||||||
make \
|
make \
|
||||||
JNI_INCLUDES="-I \"${JDKPATH}/include\" -I \"${JDKPATH}/include/win32\" -I \"/mingw64/include\" -D__int64=int64_t" \
|
JNI_INCLUDES="-I \"/c/Program Files/Java/jdk8u275-b01/include\" -I \"/c/Program Files/Java/jdk8u275-b01/include/win32\" -I \"/mingw64/include\" -D__int64=int64_t" \
|
||||||
WINDOWS_LDFLAGS="-L\"/mingw64/lib\" -no-undefined"
|
WINDOWS_LDFLAGS="-L\"/mingw64/lib\" -no-undefined"
|
||||||
make install
|
make install
|
||||||
cp .libs/msys-jpgf-0.dll /c/tmp-dist/java/jpgf.dll
|
cp .libs//msys-jpgf-0.dll /c/tmp-dist/java/jpgf.dll
|
||||||
cp jpgf.jar /c/tmp-dist/java
|
cp jpgf.jar /c/tmp-dist/java
|
||||||
|
|
||||||
- name: Build Python bindings
|
- name: Build Python bindings
|
||||||
@@ -190,7 +157,7 @@ jobs:
|
|||||||
cd src/runtime/python
|
cd src/runtime/python
|
||||||
python setup.py build
|
python setup.py build
|
||||||
python setup.py install
|
python setup.py install
|
||||||
cp /usr/lib/python3.9/site-packages/pgf* /c/tmp-dist/python
|
cp /usr/lib/python3.8/site-packages/pgf* /c/tmp-dist/python
|
||||||
|
|
||||||
- name: Setup Haskell
|
- name: Setup Haskell
|
||||||
uses: actions/setup-haskell@v1
|
uses: actions/setup-haskell@v1
|
||||||
@@ -213,18 +180,6 @@ jobs:
|
|||||||
- name: Upload artifact
|
- name: Upload artifact
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: gf-${{ github.event.release.tag_name }}-windows
|
name: gf-${{ github.sha }}-windows
|
||||||
path: C:\tmp-dist\*
|
path: C:\tmp-dist\*
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
|
|
||||||
- name: Create archive
|
|
||||||
run: |
|
|
||||||
Compress-Archive C:\tmp-dist C:\gf-${{ github.event.release.tag_name }}-windows.zip
|
|
||||||
- uses: actions/upload-release-asset@v1.0.2
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
with:
|
|
||||||
upload_url: ${{ github.event.release.upload_url }}
|
|
||||||
asset_path: C:\gf-${{ github.event.release.tag_name }}-windows.zip
|
|
||||||
asset_name: gf-${{ github.event.release.tag_name }}-windows.zip
|
|
||||||
asset_content_type: application/zip
|
|
||||||
|
|||||||
2
.github/workflows/build-python-package.yml
vendored
2
.github/workflows/build-python-package.yml
vendored
@@ -25,7 +25,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Install cibuildwheel
|
- name: Install cibuildwheel
|
||||||
run: |
|
run: |
|
||||||
python -m pip install git+https://github.com/joerick/cibuildwheel.git@main
|
python -m pip install git+https://github.com/joerick/cibuildwheel.git@master
|
||||||
|
|
||||||
- name: Install build tools for OSX
|
- name: Install build tools for OSX
|
||||||
if: startsWith(matrix.os, 'macos')
|
if: startsWith(matrix.os, 'macos')
|
||||||
|
|||||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -5,6 +5,7 @@
|
|||||||
*.jar
|
*.jar
|
||||||
*.gfo
|
*.gfo
|
||||||
*.pgf
|
*.pgf
|
||||||
|
*.lpgf
|
||||||
debian/.debhelper
|
debian/.debhelper
|
||||||
debian/debhelper-build-stamp
|
debian/debhelper-build-stamp
|
||||||
debian/gf
|
debian/gf
|
||||||
@@ -53,10 +54,6 @@ DATA_DIR
|
|||||||
|
|
||||||
stack*.yaml.lock
|
stack*.yaml.lock
|
||||||
|
|
||||||
# Output files for test suite
|
|
||||||
*.out
|
|
||||||
gf-tests.html
|
|
||||||
|
|
||||||
# Generated documentation (not exhaustive)
|
# Generated documentation (not exhaustive)
|
||||||
demos/index-numbers.html
|
demos/index-numbers.html
|
||||||
demos/resourcegrammars.html
|
demos/resourcegrammars.html
|
||||||
|
|||||||
41
Makefile
41
Makefile
@@ -1,48 +1,31 @@
|
|||||||
.PHONY: all build install doc clean html deb pkg bintar sdist
|
.PHONY: all build install doc clean gf html deb pkg bintar sdist
|
||||||
|
|
||||||
# This gets the numeric part of the version from the cabal file
|
# This gets the numeric part of the version from the cabal file
|
||||||
VERSION=$(shell sed -ne "s/^version: *\([0-9.]*\).*/\1/p" gf.cabal)
|
VERSION=$(shell sed -ne "s/^version: *\([0-9.]*\).*/\1/p" gf.cabal)
|
||||||
|
|
||||||
# Check if stack is installed
|
|
||||||
STACK=$(shell if hash stack 2>/dev/null; then echo "1"; else echo "0"; fi)
|
|
||||||
|
|
||||||
# Check if cabal >= 2.4 is installed (with v1- and v2- commands)
|
|
||||||
CABAL_NEW=$(shell if cabal v1-repl --help >/dev/null 2>&1 ; then echo "1"; else echo "0"; fi)
|
|
||||||
|
|
||||||
ifeq ($(STACK),1)
|
|
||||||
CMD=stack
|
|
||||||
else
|
|
||||||
CMD=cabal
|
|
||||||
ifeq ($(CABAL_NEW),1)
|
|
||||||
CMD_PFX=v1-
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
all: build
|
all: build
|
||||||
|
|
||||||
dist/setup-config: gf.cabal Setup.hs WebSetup.hs
|
dist/setup-config: gf.cabal Setup.hs WebSetup.hs
|
||||||
ifneq ($(STACK),1)
|
cabal configure
|
||||||
cabal ${CMD_PFX}configure
|
|
||||||
endif
|
|
||||||
|
|
||||||
build: dist/setup-config
|
build: dist/setup-config
|
||||||
${CMD} ${CMD_PFX}build
|
cabal build
|
||||||
|
|
||||||
install:
|
install:
|
||||||
ifeq ($(STACK),1)
|
cabal copy
|
||||||
stack install
|
cabal register
|
||||||
else
|
|
||||||
cabal ${CMD_PFX}copy
|
|
||||||
cabal ${CMD_PFX}register
|
|
||||||
endif
|
|
||||||
|
|
||||||
doc:
|
doc:
|
||||||
${CMD} ${CMD_PFX}haddock
|
cabal haddock
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
${CMD} ${CMD_PFX}clean
|
cabal clean
|
||||||
bash bin/clean_html
|
bash bin/clean_html
|
||||||
|
|
||||||
|
gf:
|
||||||
|
cabal build rgl-none
|
||||||
|
strip dist/build/gf/gf
|
||||||
|
|
||||||
html::
|
html::
|
||||||
bash bin/update_html
|
bash bin/update_html
|
||||||
|
|
||||||
@@ -52,7 +35,7 @@ html::
|
|||||||
deb:
|
deb:
|
||||||
dpkg-buildpackage -b -uc
|
dpkg-buildpackage -b -uc
|
||||||
|
|
||||||
# Make a macOS installer package
|
# Make an OS X Installer package
|
||||||
pkg:
|
pkg:
|
||||||
FMT=pkg bash bin/build-binary-dist.sh
|
FMT=pkg bash bin/build-binary-dist.sh
|
||||||
|
|
||||||
|
|||||||
@@ -30,16 +30,13 @@ GF particularly addresses four aspects of grammars:
|
|||||||
|
|
||||||
## Compilation and installation
|
## Compilation and installation
|
||||||
|
|
||||||
The simplest way of installing GF from source is with the command:
|
The simplest way of installing GF is with the command:
|
||||||
```
|
```
|
||||||
cabal install
|
cabal install
|
||||||
```
|
```
|
||||||
or:
|
|
||||||
```
|
|
||||||
stack install
|
|
||||||
```
|
|
||||||
|
|
||||||
For more information, including links to precompiled binaries, see the [download page](http://www.grammaticalframework.org/download/index.html).
|
For more details, see the [download page](http://www.grammaticalframework.org/download/index.html)
|
||||||
|
and [developers manual](http://www.grammaticalframework.org/doc/gf-developers.html).
|
||||||
|
|
||||||
## About this repository
|
## About this repository
|
||||||
|
|
||||||
|
|||||||
@@ -45,8 +45,6 @@ but the generated _artifacts_ must be manually attached to the release as _asset
|
|||||||
|
|
||||||
### 4. Upload to Hackage
|
### 4. Upload to Hackage
|
||||||
|
|
||||||
In order to do this you will need to be added the [GF maintainers](https://hackage.haskell.org/package/gf/maintainers/) on Hackage.
|
|
||||||
|
|
||||||
1. Run `make sdist`
|
1. Run `make sdist`
|
||||||
2. Upload the package, either:
|
2. Upload the package, either:
|
||||||
1. **Manually**: visit <https://hackage.haskell.org/upload> and upload the file `dist/gf-X.Y.tar.gz`
|
1. **Manually**: visit <https://hackage.haskell.org/upload> and upload the file `dist/gf-X.Y.tar.gz`
|
||||||
|
|||||||
15
WebSetup.hs
15
WebSetup.hs
@@ -26,14 +26,6 @@ import Distribution.PackageDescription(PackageDescription(..))
|
|||||||
so users won't see this message unless they check the log.)
|
so users won't see this message unless they check the log.)
|
||||||
-}
|
-}
|
||||||
|
|
||||||
-- | Notice about contrib grammars
|
|
||||||
noContribMsg :: IO ()
|
|
||||||
noContribMsg = putStr $ unlines
|
|
||||||
[ "Example grammars are no longer included in the main GF repository, but have moved to gf-contrib."
|
|
||||||
, "If you want them to be built, clone the following repository in the same directory as gf-core:"
|
|
||||||
, "https://github.com/GrammaticalFramework/gf-contrib.git"
|
|
||||||
]
|
|
||||||
|
|
||||||
example_grammars :: [(String, String, [String])] -- [(pgf, subdir, source modules)]
|
example_grammars :: [(String, String, [String])] -- [(pgf, subdir, source modules)]
|
||||||
example_grammars =
|
example_grammars =
|
||||||
[("Letter.pgf","letter",letterSrc)
|
[("Letter.pgf","letter",letterSrc)
|
||||||
@@ -58,8 +50,11 @@ buildWeb gf flags (pkg,lbi) = do
|
|||||||
contrib_exists <- doesDirectoryExist contrib_dir
|
contrib_exists <- doesDirectoryExist contrib_dir
|
||||||
if contrib_exists
|
if contrib_exists
|
||||||
then mapM_ build_pgf example_grammars
|
then mapM_ build_pgf example_grammars
|
||||||
-- else noContribMsg
|
else putStr $ unlines
|
||||||
else return ()
|
[ "Example grammars are no longer included in the main GF repository, but have moved to gf-contrib."
|
||||||
|
, "If you want these example grammars to be built, clone this repository in the same top-level directory as GF:"
|
||||||
|
, "https://github.com/GrammaticalFramework/gf-contrib.git"
|
||||||
|
]
|
||||||
where
|
where
|
||||||
gfo_dir = buildDir lbi </> "examples"
|
gfo_dir = buildDir lbi </> "examples"
|
||||||
|
|
||||||
|
|||||||
6
debian/changelog
vendored
6
debian/changelog
vendored
@@ -1,9 +1,3 @@
|
|||||||
gf (3.11) bionic focal; urgency=low
|
|
||||||
|
|
||||||
* GF 3.11
|
|
||||||
|
|
||||||
-- Inari Listenmaa <inari@digitalgrammars.com> Sun, 25 Jul 2021 10:27:40 +0800
|
|
||||||
|
|
||||||
gf (3.10.4-1) xenial bionic cosmic; urgency=low
|
gf (3.10.4-1) xenial bionic cosmic; urgency=low
|
||||||
|
|
||||||
* GF 3.10.4
|
* GF 3.10.4
|
||||||
|
|||||||
10
debian/rules
vendored
10
debian/rules
vendored
@@ -16,9 +16,9 @@ override_dh_shlibdeps:
|
|||||||
override_dh_auto_configure:
|
override_dh_auto_configure:
|
||||||
cd src/runtime/c && bash setup.sh configure --prefix=/usr
|
cd src/runtime/c && bash setup.sh configure --prefix=/usr
|
||||||
cd src/runtime/c && bash setup.sh build
|
cd src/runtime/c && bash setup.sh build
|
||||||
cabal v1-update
|
cabal update
|
||||||
cabal v1-install --only-dependencies
|
cabal install --only-dependencies
|
||||||
cabal v1-configure --prefix=/usr -fserver -fc-runtime --extra-lib-dirs=$(CURDIR)/src/runtime/c/.libs --extra-include-dirs=$(CURDIR)/src/runtime/c
|
cabal configure --prefix=/usr -fserver -fc-runtime --extra-lib-dirs=$(CURDIR)/src/runtime/c/.libs --extra-include-dirs=$(CURDIR)/src/runtime/c
|
||||||
|
|
||||||
SET_LDL=LD_LIBRARY_PATH=$$LD_LIBRARY_PATH:$(CURDIR)/src/runtime/c/.libs
|
SET_LDL=LD_LIBRARY_PATH=$$LD_LIBRARY_PATH:$(CURDIR)/src/runtime/c/.libs
|
||||||
|
|
||||||
@@ -26,10 +26,10 @@ override_dh_auto_build:
|
|||||||
cd src/runtime/python && EXTRA_INCLUDE_DIRS=$(CURDIR)/src/runtime/c EXTRA_LIB_DIRS=$(CURDIR)/src/runtime/c/.libs python setup.py build
|
cd src/runtime/python && EXTRA_INCLUDE_DIRS=$(CURDIR)/src/runtime/c EXTRA_LIB_DIRS=$(CURDIR)/src/runtime/c/.libs python setup.py build
|
||||||
cd src/runtime/java && make CFLAGS="-I$(CURDIR)/src/runtime/c -L$(CURDIR)/src/runtime/c/.libs" INSTALL_PATH=/usr
|
cd src/runtime/java && make CFLAGS="-I$(CURDIR)/src/runtime/c -L$(CURDIR)/src/runtime/c/.libs" INSTALL_PATH=/usr
|
||||||
echo $(SET_LDL)
|
echo $(SET_LDL)
|
||||||
-$(SET_LDL) cabal v1-build
|
-$(SET_LDL) cabal build
|
||||||
|
|
||||||
override_dh_auto_install:
|
override_dh_auto_install:
|
||||||
$(SET_LDL) cabal v1-copy --destdir=$(CURDIR)/debian/gf
|
$(SET_LDL) cabal copy --destdir=$(CURDIR)/debian/gf
|
||||||
cd src/runtime/c && bash setup.sh copy prefix=$(CURDIR)/debian/gf/usr
|
cd src/runtime/c && bash setup.sh copy prefix=$(CURDIR)/debian/gf/usr
|
||||||
cd src/runtime/python && python setup.py install --prefix=$(CURDIR)/debian/gf/usr
|
cd src/runtime/python && python setup.py install --prefix=$(CURDIR)/debian/gf/usr
|
||||||
cd src/runtime/java && make INSTALL_PATH=$(CURDIR)/debian/gf/usr install
|
cd src/runtime/java && make INSTALL_PATH=$(CURDIR)/debian/gf/usr install
|
||||||
|
|||||||
@@ -1,201 +0,0 @@
|
|||||||
GF Developer's Guide: Old installation instructions with Cabal
|
|
||||||
|
|
||||||
|
|
||||||
This page contains the old installation instructions from the [Developer's Guide ../doc/gf-developers.html].
|
|
||||||
We recommend Stack as a primary installation method, because it's easier for a Haskell beginner, and we want to keep the main instructions short.
|
|
||||||
But if you are an experienced Haskeller and want to keep using Cabal, here are the old instructions using ``cabal install``.
|
|
||||||
|
|
||||||
Note that some of these instructions may be outdated. Other parts may still be useful.
|
|
||||||
|
|
||||||
== Compilation from source with Cabal ==
|
|
||||||
|
|
||||||
The build system of GF is based on //Cabal//, which is part of the
|
|
||||||
Haskell Platform, so no extra steps are needed to install it. In the simplest
|
|
||||||
case, all you need to do to compile and install GF, after downloading the
|
|
||||||
source code as described above, is
|
|
||||||
|
|
||||||
```
|
|
||||||
$ cabal install
|
|
||||||
```
|
|
||||||
|
|
||||||
This will automatically download any additional Haskell libraries needed to
|
|
||||||
build GF. If this is the first time you use Cabal, you might need to run
|
|
||||||
``cabal update`` first, to update the list of available libraries.
|
|
||||||
|
|
||||||
If you want more control, the process can also be split up into the usual
|
|
||||||
//configure//, //build// and //install// steps.
|
|
||||||
|
|
||||||
=== Configure ===
|
|
||||||
|
|
||||||
During the configuration phase Cabal will check that you have all
|
|
||||||
necessary tools and libraries needed for GF. The configuration is
|
|
||||||
started by the command:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ cabal configure
|
|
||||||
```
|
|
||||||
|
|
||||||
If you don't see any error message from the above command then you
|
|
||||||
have everything that is needed for GF. You can also add the option
|
|
||||||
``-v`` to see more details about the configuration.
|
|
||||||
|
|
||||||
You can use ``cabal configure --help`` to get a list of configuration options.
|
|
||||||
|
|
||||||
=== Build ===
|
|
||||||
|
|
||||||
The build phase does two things. First it builds the GF compiler from
|
|
||||||
the Haskell source code and after that it builds the GF Resource Grammar
|
|
||||||
Library using the already build compiler. The simplest command is:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ cabal build
|
|
||||||
```
|
|
||||||
|
|
||||||
Again you can add the option ``-v`` if you want to see more details.
|
|
||||||
|
|
||||||
==== Parallel builds ====
|
|
||||||
|
|
||||||
If you have Cabal>=1.20 you can enable parallel compilation by using
|
|
||||||
|
|
||||||
```
|
|
||||||
$ cabal build -j
|
|
||||||
```
|
|
||||||
|
|
||||||
or by putting a line
|
|
||||||
```
|
|
||||||
jobs: $ncpus
|
|
||||||
```
|
|
||||||
in your ``.cabal/config`` file. Cabal
|
|
||||||
will pass this option to GHC when building the GF compiler, if you
|
|
||||||
have GHC>=7.8.
|
|
||||||
|
|
||||||
Cabal also passes ``-j`` to GF to enable parallel compilation of the
|
|
||||||
Resource Grammar Library. This is done unconditionally to avoid
|
|
||||||
causing problems for developers with Cabal<1.20. You can disable this
|
|
||||||
by editing the last few lines in ``WebSetup.hs``.
|
|
||||||
|
|
||||||
=== Install ===
|
|
||||||
|
|
||||||
After you have compiled GF you need to install the executable and libraries
|
|
||||||
to make the system usable.
|
|
||||||
|
|
||||||
```
|
|
||||||
$ cabal copy
|
|
||||||
$ cabal register
|
|
||||||
```
|
|
||||||
|
|
||||||
This command installs the GF compiler for a single user, in the standard
|
|
||||||
place used by Cabal.
|
|
||||||
On Linux and Mac this could be ``$HOME/.cabal/bin``.
|
|
||||||
On Mac it could also be ``$HOME/Library/Haskell/bin``.
|
|
||||||
On Windows this is ``C:\Program Files\Haskell\bin``.
|
|
||||||
|
|
||||||
The compiled GF Resource Grammar Library will be installed
|
|
||||||
under the same prefix, e.g. in
|
|
||||||
``$HOME/.cabal/share/gf-3.3.3/lib`` on Linux and
|
|
||||||
in ``C:\Program Files\Haskell\gf-3.3.3\lib`` on Windows.
|
|
||||||
|
|
||||||
If you want to install in some other place then use the ``--prefix``
|
|
||||||
option during the configuration phase.
|
|
||||||
|
|
||||||
=== Clean ===
|
|
||||||
|
|
||||||
Sometimes you want to clean up the compilation and start again from clean
|
|
||||||
sources. Use the clean command for this purpose:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ cabal clean
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
%=== SDist ===
|
|
||||||
%
|
|
||||||
%You can use the command:
|
|
||||||
%
|
|
||||||
%% This does *NOT* include everything that is needed // TH 2012-08-06
|
|
||||||
%```
|
|
||||||
%$ cabal sdist
|
|
||||||
%```
|
|
||||||
%
|
|
||||||
%to prepare archive with all source codes needed to compile GF.
|
|
||||||
|
|
||||||
=== Known problems with Cabal ===
|
|
||||||
|
|
||||||
Some versions of Cabal (at least version 1.16) seem to have a bug that can
|
|
||||||
cause the following error:
|
|
||||||
|
|
||||||
```
|
|
||||||
Configuring gf-3.x...
|
|
||||||
setup: Distribution/Simple/PackageIndex.hs:124:8-13: Assertion failed
|
|
||||||
```
|
|
||||||
|
|
||||||
The exact cause of this problem is unclear, but it seems to happen
|
|
||||||
during the configure phase if the same version of GF is already installed,
|
|
||||||
so a workaround is to remove the existing installation with
|
|
||||||
|
|
||||||
```
|
|
||||||
ghc-pkg unregister gf
|
|
||||||
```
|
|
||||||
|
|
||||||
You can check with ``ghc-pkg list gf`` that it is gone.
|
|
||||||
|
|
||||||
== Compilation with make ==
|
|
||||||
|
|
||||||
If you feel more comfortable with Makefiles then there is a thin Makefile
|
|
||||||
wrapper arround Cabal for you. If you just type:
|
|
||||||
```
|
|
||||||
$ make
|
|
||||||
```
|
|
||||||
the configuration phase will be run automatically if needed and after that
|
|
||||||
the sources will be compiled.
|
|
||||||
|
|
||||||
%% cabal build rgl-none does not work with recent versions of Cabal
|
|
||||||
%If you don't want to compile the resource library
|
|
||||||
%every time then you can use:
|
|
||||||
%```
|
|
||||||
%$ make gf
|
|
||||||
%```
|
|
||||||
|
|
||||||
For installation use:
|
|
||||||
```
|
|
||||||
$ make install
|
|
||||||
```
|
|
||||||
For cleaning:
|
|
||||||
```
|
|
||||||
$ make clean
|
|
||||||
```
|
|
||||||
%and to build source distribution archive run:
|
|
||||||
%```
|
|
||||||
%$ make sdist
|
|
||||||
%```
|
|
||||||
|
|
||||||
|
|
||||||
== Partial builds of RGL ==
|
|
||||||
|
|
||||||
**NOTE**: The following doesn't work with recent versions of ``cabal``. //(This comment was left in 2015, so make your own conclusions.)//
|
|
||||||
%% // TH 2015-06-22
|
|
||||||
|
|
||||||
%Sometimes you just want to work on the GF compiler and don't want to
|
|
||||||
%recompile the resource library after each change. In this case use
|
|
||||||
%this extended command:
|
|
||||||
|
|
||||||
%```
|
|
||||||
%$ cabal build rgl-none
|
|
||||||
%```
|
|
||||||
|
|
||||||
The resource grammar library can be compiled in two modes: with present
|
|
||||||
tense only and with all tenses. By default it is compiled with all
|
|
||||||
tenses. If you want to use the library with only present tense you can
|
|
||||||
compile it in this special mode with the command:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ cabal build present
|
|
||||||
```
|
|
||||||
|
|
||||||
You could also control which languages you want to be recompiled by
|
|
||||||
adding the option ``langs=list``. For example the following command
|
|
||||||
will compile only the English and the Swedish language:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ cabal build langs=Eng,Swe
|
|
||||||
```
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
GF Developers Guide
|
GF Developers Guide
|
||||||
|
|
||||||
2021-07-15
|
2018-07-26
|
||||||
|
|
||||||
%!options(html): --toc
|
%!options(html): --toc
|
||||||
|
|
||||||
@@ -15,287 +15,388 @@ you are a GF user who just wants to download and install GF
|
|||||||
== Setting up your system for building GF ==
|
== Setting up your system for building GF ==
|
||||||
|
|
||||||
To build GF from source you need to install some tools on your
|
To build GF from source you need to install some tools on your
|
||||||
system: the Haskell build tool //Stack//, the version control software //Git// and the //Haskeline// library.
|
system: the //Haskell Platform//, //Git// and the //Haskeline library//.
|
||||||
|
|
||||||
%**On Linux** the best option is to install the tools via the standard
|
**On Linux** the best option is to install the tools via the standard
|
||||||
%software distribution channels, i.e. by using the //Software Center//
|
software distribution channels, i.e. by using the //Software Center//
|
||||||
%in Ubuntu or the corresponding tool in other popular Linux distributions.
|
in Ubuntu or the corresponding tool in other popular Linux distributions.
|
||||||
|
Or, from a Terminal window, the following command should be enough:
|
||||||
|
|
||||||
%**On Mac OS and Windows**, the tools can be downloaded from their respective
|
- On Ubuntu: ``sudo apt-get install haskell-platform git libghc6-haskeline-dev``
|
||||||
%web sites, as described below.
|
- On Fedora: ``sudo dnf install haskell-platform git ghc-haskeline-devel``
|
||||||
|
|
||||||
=== Stack ===
|
|
||||||
The primary installation method is via //Stack//.
|
|
||||||
(You can also use Cabal, but we recommend Stack to those who are new to Haskell.)
|
|
||||||
|
|
||||||
To install Stack:
|
|
||||||
|
|
||||||
- **On Linux and Mac OS**, do either
|
|
||||||
|
|
||||||
``$ curl -sSL https://get.haskellstack.org/ | sh``
|
|
||||||
|
|
||||||
or
|
|
||||||
|
|
||||||
``$ wget -qO- https://get.haskellstack.org/ | sh``
|
|
||||||
|
|
||||||
|
|
||||||
- **On other operating systems**, see the [installation guide https://docs.haskellstack.org/en/stable/install_and_upgrade].
|
**On Mac OS and Windows**, the tools can be downloaded from their respective
|
||||||
|
web sites, as described below.
|
||||||
|
|
||||||
|
=== The Haskell Platform ===
|
||||||
|
|
||||||
%If you already have Stack installed, upgrade it to the latest version by running: ``stack upgrade``
|
GF is written in Haskell, so first of all you need
|
||||||
|
the //Haskell Platform//, e.g. version 8.0.2 or 7.10.3. Downloads
|
||||||
|
and installation instructions are available from here:
|
||||||
|
|
||||||
|
http://hackage.haskell.org/platform/
|
||||||
|
|
||||||
|
Once you have installed the Haskell Platform, open a terminal
|
||||||
|
(Command Prompt on Windows) and try to execute the following command:
|
||||||
|
```
|
||||||
|
$ ghc --version
|
||||||
|
```
|
||||||
|
This command should show you which version of GHC you have. If the installation
|
||||||
|
of the Haskell Platform was successful you should see a message like:
|
||||||
|
|
||||||
|
```
|
||||||
|
The Glorious Glasgow Haskell Compilation System, version 8.0.2
|
||||||
|
```
|
||||||
|
|
||||||
|
Other required tools included in the Haskell Platform are
|
||||||
|
[Cabal http://www.haskell.org/cabal/],
|
||||||
|
[Alex http://www.haskell.org/alex/]
|
||||||
|
and
|
||||||
|
[Happy http://www.haskell.org/happy/].
|
||||||
|
|
||||||
=== Git ===
|
=== Git ===
|
||||||
|
|
||||||
To get the GF source code, you also need //Git//, a distributed version control system.
|
To get the GF source code, you also need //Git//.
|
||||||
|
//Git// is a distributed version control system, see
|
||||||
|
https://git-scm.com/downloads for more information.
|
||||||
|
|
||||||
- **On Linux**, the best option is to install the tools via the standard
|
=== The haskeline library ===
|
||||||
software distribution channels:
|
|
||||||
|
|
||||||
- On Ubuntu: ``sudo apt-get install git-all``
|
|
||||||
- On Fedora: ``sudo dnf install git-all``
|
|
||||||
|
|
||||||
|
|
||||||
- **On other operating systems**, see
|
|
||||||
https://git-scm.com/book/en/v2/Getting-Started-Installing-Git for installation.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
=== Haskeline ===
|
|
||||||
|
|
||||||
GF uses //haskeline// to enable command line editing in the GF shell.
|
GF uses //haskeline// to enable command line editing in the GF shell.
|
||||||
|
This should work automatically on Mac OS and Windows, but on Linux one
|
||||||
|
extra step is needed to make sure the C libraries (terminfo)
|
||||||
|
required by //haskeline// are installed. Here is one way to do this:
|
||||||
|
|
||||||
- **On Mac OS and Windows**, this should work automatically.
|
- On Ubuntu: ``sudo apt-get install libghc-haskeline-dev``
|
||||||
|
- On Fedora: ``sudo dnf install ghc-haskeline-devel``
|
||||||
- **On Linux**, an extra step is needed to make sure the C libraries (terminfo)
|
|
||||||
required by //haskeline// are installed:
|
|
||||||
|
|
||||||
- On Ubuntu: ``sudo apt-get install libghc-haskeline-dev``
|
|
||||||
- On Fedora: ``sudo dnf install ghc-haskeline-devel``
|
|
||||||
|
|
||||||
|
|
||||||
== Getting the source ==[getting-source]
|
== Getting the source ==
|
||||||
|
|
||||||
Once you have all tools in place you can get the GF source code from
|
Once you have all tools in place you can get the GF source code. If you
|
||||||
[GitHub https://github.com/GrammaticalFramework/]:
|
just want to compile and use GF then it is enough to have read-only
|
||||||
|
access. It is also possible to make changes in the source code but if you
|
||||||
|
want these changes to be applied back to the main source repository you will
|
||||||
|
have to send the changes to us. If you plan to work continuously on
|
||||||
|
GF then you should consider getting read-write access.
|
||||||
|
|
||||||
- https://github.com/GrammaticalFramework/gf-core for the GF compiler
|
=== Read-only access ===
|
||||||
- https://github.com/GrammaticalFramework/gf-rgl for the Resource Grammar Library
|
|
||||||
|
|
||||||
|
==== Getting a fresh copy for read-only access ====
|
||||||
|
|
||||||
=== Read-only access: clone the main repository ===
|
Anyone can get the latest development version of GF by running:
|
||||||
|
|
||||||
If you only want to compile and use GF, you can just clone the repositories as follows:
|
|
||||||
|
|
||||||
```
|
```
|
||||||
$ git clone https://github.com/GrammaticalFramework/gf-core.git
|
$ git clone https://github.com/GrammaticalFramework/gf-core.git
|
||||||
$ git clone https://github.com/GrammaticalFramework/gf-rgl.git
|
$ git clone https://github.com/GrammaticalFramework/gf-rgl.git
|
||||||
```
|
```
|
||||||
|
|
||||||
To get new updates, run the following anywhere in your local copy of the repository:
|
This will create directories ``gf-core`` and ``gf-rgl`` in the current directory.
|
||||||
|
|
||||||
|
|
||||||
|
==== Updating your copy ====
|
||||||
|
|
||||||
|
To get all new patches from each repo:
|
||||||
|
```
|
||||||
|
$ git pull
|
||||||
|
```
|
||||||
|
This can be done anywhere in your local repository.
|
||||||
|
|
||||||
|
|
||||||
|
==== Recording local changes ====[record]
|
||||||
|
|
||||||
|
Since every copy is a repository, you can have local version control
|
||||||
|
of your changes.
|
||||||
|
|
||||||
|
If you have added files, you first need to tell your local repository to
|
||||||
|
keep them under revision control:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ git pull
|
$ git add file1 file2 ...
|
||||||
```
|
```
|
||||||
|
|
||||||
=== Contribute your changes: fork the main repository ===
|
To record changes, use:
|
||||||
|
|
||||||
If you want the possibility to contribute your changes,
|
|
||||||
you should create your own fork, do your changes there,
|
|
||||||
and then send a pull request to the main repository.
|
|
||||||
|
|
||||||
+ **Creating and cloning a fork —**
|
|
||||||
See GitHub documentation for instructions how to [create your own fork https://docs.github.com/en/get-started/quickstart/fork-a-repo]
|
|
||||||
of the repository. Once you've done it, clone the fork to your local computer.
|
|
||||||
|
|
||||||
```
|
```
|
||||||
$ git clone https://github.com/<YOUR_USERNAME>/gf-core.git
|
$ git commit file1 file2 ...
|
||||||
```
|
```
|
||||||
|
|
||||||
+ **Updating your copy —**
|
This creates a patch against the previous version and stores it in your
|
||||||
Once you have cloned your fork, you need to set up the main repository as a remote:
|
local repository. You can record any number of changes before
|
||||||
|
pushing them to the main repo. In fact, you don't have to push them at
|
||||||
|
all if you want to keep the changes only in your local repo.
|
||||||
|
|
||||||
|
Instead of enumerating all modified files on the command line,
|
||||||
|
you can use the flag ``-a`` to automatically record //all// modified
|
||||||
|
files. You still need to use ``git add`` to add new files.
|
||||||
|
|
||||||
|
|
||||||
|
=== Read-write access ===
|
||||||
|
|
||||||
|
If you are a member of the GF project on GitHub, you can push your
|
||||||
|
changes directly to the GF git repository on GitHub.
|
||||||
|
|
||||||
```
|
```
|
||||||
$ git remote add upstream https://github.com/GrammaticalFramework/gf-core.git
|
$ git push
|
||||||
```
|
```
|
||||||
|
|
||||||
Then you can get the latest updates by running the following:
|
It is also possible for anyone else to contribute by
|
||||||
|
|
||||||
```
|
- creating a fork of the GF repository on GitHub,
|
||||||
$ git pull upstream master
|
- working with local clone of the fork (obtained with ``git clone``),
|
||||||
```
|
- pushing changes to the fork,
|
||||||
|
- and finally sending a pull request.
|
||||||
+ **Recording local changes —**
|
|
||||||
See Git tutorial on how to [record and push your changes https://git-scm.com/book/en/v2/Git-Basics-Recording-Changes-to-the-Repository] to your fork.
|
|
||||||
|
|
||||||
+ **Pull request —**
|
|
||||||
When you want to contribute your changes to the main gf-core repository,
|
|
||||||
[create a pull request https://docs.github.com/en/github/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request]
|
|
||||||
from your fork.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
If you want to contribute to the RGL as well, do the same process for the RGL repository.
|
== Compilation from source with Cabal ==
|
||||||
|
|
||||||
|
The build system of GF is based on //Cabal//, which is part of the
|
||||||
== Compilation from source ==
|
Haskell Platform, so no extra steps are needed to install it. In the simplest
|
||||||
|
case, all you need to do to compile and install GF, after downloading the
|
||||||
By now you should have installed Stack and Haskeline, and cloned the Git repository on your own computer, in a directory called ``gf-core``.
|
source code as described above, is
|
||||||
|
|
||||||
=== Primary recommendation: use Stack ===
|
|
||||||
|
|
||||||
Open a terminal, go to the top directory (``gf-core``), and type the following command.
|
|
||||||
|
|
||||||
```
|
|
||||||
$ stack install
|
|
||||||
```
|
|
||||||
|
|
||||||
It will install GF and all necessary tools and libraries to do that.
|
|
||||||
|
|
||||||
|
|
||||||
=== Alternative: use Cabal ===
|
|
||||||
You can also install GF using Cabal, if you prefer Cabal to Stack. In that case, you may need to install some prerequisites yourself.
|
|
||||||
|
|
||||||
The actual installation process is similar to Stack: open a terminal, go to the top directory (``gf-core``), and type the following command.
|
|
||||||
|
|
||||||
```
|
```
|
||||||
$ cabal install
|
$ cabal install
|
||||||
```
|
```
|
||||||
|
|
||||||
//The old (potentially outdated) instructions for Cabal are moved to a [separate page ../doc/gf-developers-old-cabal.html]. If you run into trouble with ``cabal install``, you may want to take a look.//
|
This will automatically download any additional Haskell libraries needed to
|
||||||
|
build GF. If this is the first time you use Cabal, you might need to run
|
||||||
|
``cabal update`` first, to update the list of available libraries.
|
||||||
|
|
||||||
== Compiling GF with C runtime system support ==
|
If you want more control, the process can also be split up into the usual
|
||||||
|
//configure//, //build// and //install// steps.
|
||||||
|
|
||||||
The C runtime system is a separate implementation of the PGF runtime services.
|
=== Configure ===
|
||||||
|
|
||||||
|
During the configuration phase Cabal will check that you have all
|
||||||
|
necessary tools and libraries needed for GF. The configuration is
|
||||||
|
started by the command:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ cabal configure
|
||||||
|
```
|
||||||
|
|
||||||
|
If you don't see any error message from the above command then you
|
||||||
|
have everything that is needed for GF. You can also add the option
|
||||||
|
``-v`` to see more details about the configuration.
|
||||||
|
|
||||||
|
You can use ``cabal configure --help`` to get a list of configuration options.
|
||||||
|
|
||||||
|
=== Build ===
|
||||||
|
|
||||||
|
The build phase does two things. First it builds the GF compiler from
|
||||||
|
the Haskell source code and after that it builds the GF Resource Grammar
|
||||||
|
Library using the already build compiler. The simplest command is:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ cabal build
|
||||||
|
```
|
||||||
|
|
||||||
|
Again you can add the option ``-v`` if you want to see more details.
|
||||||
|
|
||||||
|
==== Parallel builds ====
|
||||||
|
|
||||||
|
If you have Cabal>=1.20 you can enable parallel compilation by using
|
||||||
|
|
||||||
|
```
|
||||||
|
$ cabal build -j
|
||||||
|
```
|
||||||
|
|
||||||
|
or by putting a line
|
||||||
|
```
|
||||||
|
jobs: $ncpus
|
||||||
|
```
|
||||||
|
in your ``.cabal/config`` file. Cabal
|
||||||
|
will pass this option to GHC when building the GF compiler, if you
|
||||||
|
have GHC>=7.8.
|
||||||
|
|
||||||
|
Cabal also passes ``-j`` to GF to enable parallel compilation of the
|
||||||
|
Resource Grammar Library. This is done unconditionally to avoid
|
||||||
|
causing problems for developers with Cabal<1.20. You can disable this
|
||||||
|
by editing the last few lines in ``WebSetup.hs``.
|
||||||
|
|
||||||
|
|
||||||
|
==== Partial builds ====
|
||||||
|
|
||||||
|
**NOTE**: The following doesn't work with recent versions of ``cabal``.
|
||||||
|
%% // TH 2015-06-22
|
||||||
|
|
||||||
|
Sometimes you just want to work on the GF compiler and don't want to
|
||||||
|
recompile the resource library after each change. In this case use
|
||||||
|
this extended command:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ cabal build rgl-none
|
||||||
|
```
|
||||||
|
|
||||||
|
The resource library could also be compiled in two modes: with present
|
||||||
|
tense only and with all tenses. By default it is compiled with all
|
||||||
|
tenses. If you want to use the library with only present tense you can
|
||||||
|
compile it in this special mode with the command:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ cabal build present
|
||||||
|
```
|
||||||
|
|
||||||
|
You could also control which languages you want to be recompiled by
|
||||||
|
adding the option ``langs=list``. For example the following command
|
||||||
|
will compile only the English and the Swedish language:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ cabal build langs=Eng,Swe
|
||||||
|
```
|
||||||
|
|
||||||
|
=== Install ===
|
||||||
|
|
||||||
|
After you have compiled GF you need to install the executable and libraries
|
||||||
|
to make the system usable.
|
||||||
|
|
||||||
|
```
|
||||||
|
$ cabal copy
|
||||||
|
$ cabal register
|
||||||
|
```
|
||||||
|
|
||||||
|
This command installs the GF compiler for a single user, in the standard
|
||||||
|
place used by Cabal.
|
||||||
|
On Linux and Mac this could be ``$HOME/.cabal/bin``.
|
||||||
|
On Mac it could also be ``$HOME/Library/Haskell/bin``.
|
||||||
|
On Windows this is ``C:\Program Files\Haskell\bin``.
|
||||||
|
|
||||||
|
The compiled GF Resource Grammar Library will be installed
|
||||||
|
under the same prefix, e.g. in
|
||||||
|
``$HOME/.cabal/share/gf-3.3.3/lib`` on Linux and
|
||||||
|
in ``C:\Program Files\Haskell\gf-3.3.3\lib`` on Windows.
|
||||||
|
|
||||||
|
If you want to install in some other place then use the ``--prefix``
|
||||||
|
option during the configuration phase.
|
||||||
|
|
||||||
|
=== Clean ===
|
||||||
|
|
||||||
|
Sometimes you want to clean up the compilation and start again from clean
|
||||||
|
sources. Use the clean command for this purpose:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ cabal clean
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
%=== SDist ===
|
||||||
|
%
|
||||||
|
%You can use the command:
|
||||||
|
%
|
||||||
|
%% This does *NOT* include everything that is needed // TH 2012-08-06
|
||||||
|
%```
|
||||||
|
%$ cabal sdist
|
||||||
|
%```
|
||||||
|
%
|
||||||
|
%to prepare archive with all source codes needed to compile GF.
|
||||||
|
|
||||||
|
=== Known problems with Cabal ===
|
||||||
|
|
||||||
|
Some versions of Cabal (at least version 1.16) seem to have a bug that can
|
||||||
|
cause the following error:
|
||||||
|
|
||||||
|
```
|
||||||
|
Configuring gf-3.x...
|
||||||
|
setup: Distribution/Simple/PackageIndex.hs:124:8-13: Assertion failed
|
||||||
|
```
|
||||||
|
|
||||||
|
The exact cause of this problem is unclear, but it seems to happen
|
||||||
|
during the configure phase if the same version of GF is already installed,
|
||||||
|
so a workaround is to remove the existing installation with
|
||||||
|
|
||||||
|
```
|
||||||
|
ghc-pkg unregister gf
|
||||||
|
```
|
||||||
|
|
||||||
|
You can check with ``ghc-pkg list gf`` that it is gone.
|
||||||
|
|
||||||
|
== Compilation with make ==
|
||||||
|
|
||||||
|
If you feel more comfortable with Makefiles then there is a thin Makefile
|
||||||
|
wrapper arround Cabal for you. If you just type:
|
||||||
|
```
|
||||||
|
$ make
|
||||||
|
```
|
||||||
|
the configuration phase will be run automatically if needed and after that
|
||||||
|
the sources will be compiled.
|
||||||
|
|
||||||
|
%% cabal build rgl-none does not work with recent versions of Cabal
|
||||||
|
%If you don't want to compile the resource library
|
||||||
|
%every time then you can use:
|
||||||
|
%```
|
||||||
|
%$ make gf
|
||||||
|
%```
|
||||||
|
|
||||||
|
For installation use:
|
||||||
|
```
|
||||||
|
$ make install
|
||||||
|
```
|
||||||
|
For cleaning:
|
||||||
|
```
|
||||||
|
$ make clean
|
||||||
|
```
|
||||||
|
%and to build source distribution archive run:
|
||||||
|
%```
|
||||||
|
%$ make sdist
|
||||||
|
%```
|
||||||
|
|
||||||
|
== Compiling GF with C run-time system support ==
|
||||||
|
|
||||||
|
The C run-time system is a separate implementation of the PGF run-time services.
|
||||||
It makes it possible to work with very large, ambiguous grammars, using
|
It makes it possible to work with very large, ambiguous grammars, using
|
||||||
probabilistic models to obtain probable parses. The C runtime system might
|
probabilistic models to obtain probable parses. The C run-time system might
|
||||||
also be easier to use than the Haskell runtime system on certain platforms,
|
also be easier to use than the Haskell run-time system on certain platforms,
|
||||||
e.g. Android and iOS.
|
e.g. Android and iOS.
|
||||||
|
|
||||||
To install the C runtime system, go to the ``src/runtime/c`` directory.
|
To install the C run-time system, go to the ``src/runtime/c`` directory
|
||||||
|
%and follow the instructions in the ``INSTALL`` file.
|
||||||
|
and use the ``install.sh`` script:
|
||||||
|
```
|
||||||
|
bash setup.sh configure
|
||||||
|
bash setup.sh build
|
||||||
|
bash setup.sh install
|
||||||
|
```
|
||||||
|
This will install
|
||||||
|
the C header files and libraries need to write C programs that use PGF grammars.
|
||||||
|
Some example C programs are included in the ``utils`` subdirectory, e.g.
|
||||||
|
``pgf-translate.c``.
|
||||||
|
|
||||||
- **On Linux and Mac OS —**
|
When the C run-time system is installed, you can install GF with C run-time
|
||||||
You should have autoconf, automake, libtool and make.
|
support by doing
|
||||||
If you are missing some of them, follow the
|
|
||||||
instructions in the [INSTALL https://github.com/GrammaticalFramework/gf-core/blob/master/src/runtime/c/INSTALL] file.
|
|
||||||
|
|
||||||
Once you have the required libraries, the easiest way to install the C runtime is to use the ``install.sh`` script. Just type
|
|
||||||
|
|
||||||
``$ bash install.sh``
|
|
||||||
|
|
||||||
This will install the C header files and libraries need to write C programs
|
|
||||||
that use PGF grammars.
|
|
||||||
|
|
||||||
% If this doesn't work for you, follow the manual instructions in the [INSTALL https://github.com/GrammaticalFramework/gf-core/blob/master/src/runtime/c/INSTALL] file under your operating system.
|
|
||||||
|
|
||||||
- **On other operating systems —** Follow the instructions in the
|
|
||||||
[INSTALL https://github.com/GrammaticalFramework/gf-core/blob/master/src/runtime/c/INSTALL] file under your operating system.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Depending on what you want to do with the C runtime, you can follow one or more of the following steps.
|
|
||||||
|
|
||||||
=== Use the C runtime from another programming language ===[bindings]
|
|
||||||
|
|
||||||
% **If you just want to use the C runtime from Python, Java, or Haskell, you don't need to change your GF installation.**
|
|
||||||
|
|
||||||
- **What —**
|
|
||||||
This is the most common use case for the C runtime: compile
|
|
||||||
your GF grammars into PGF with the standard GF executable,
|
|
||||||
and manipulate the PGFs from another programming language,
|
|
||||||
using the bindings to the C runtime.
|
|
||||||
|
|
||||||
|
|
||||||
- **How —**
|
|
||||||
The Python, Java and Haskell bindings are found in the
|
|
||||||
``src/runtime/{python,java,haskell-bind}`` directories,
|
|
||||||
respecively. Compile them by following the instructions
|
|
||||||
in the ``INSTALL`` or ``README`` files in those directories.
|
|
||||||
|
|
||||||
The Python library can also be installed from PyPI using ``pip install pgf``.
|
|
||||||
|
|
||||||
|
|
||||||
//If you are on Mac and get an error about ``clang`` version, you can try some of [these solutions https://stackoverflow.com/questions/63972113/big-sur-clang-invalid-version-error-due-to-macosx-deployment-target]—but be careful before removing any existing installations.//
|
|
||||||
|
|
||||||
|
|
||||||
=== Use GF shell with C runtime support ===
|
|
||||||
|
|
||||||
- **What —**
|
|
||||||
If you want to use the GF shell with C runtime functionalities, then you need to (re)compile GF with special flags.
|
|
||||||
|
|
||||||
The GF shell can be started with ``gf -cshell`` or ``gf -crun`` to use
|
|
||||||
the C run-time system instead of the Haskell run-time system.
|
|
||||||
Only limited functionality is available when running the shell in these
|
|
||||||
modes (use the ``help`` command in the shell for details).
|
|
||||||
|
|
||||||
(Re)compiling your GF with these flags will also give you
|
|
||||||
Haskell bindings to the C runtime, as a library called ``PGF2``,
|
|
||||||
but if you want Python or Java bindings, you need to do [the previous step #bindings].
|
|
||||||
|
|
||||||
% ``PGF2``: a module to import in Haskell programs, providing a binding to the C run-time system.
|
|
||||||
|
|
||||||
- **How —**
|
|
||||||
If you use cabal, run the following command:
|
|
||||||
|
|
||||||
```
|
```
|
||||||
cabal install -fc-runtime
|
cabal install -fserver -fc-runtime
|
||||||
```
|
```
|
||||||
|
from the top directory. This give you three new things:
|
||||||
|
|
||||||
from the top directory (``gf-core``).
|
- ``PGF2``: a module to import in Haskell programs, providing a binding to
|
||||||
|
the C run-time system.
|
||||||
|
|
||||||
If you use stack, uncomment the following lines in the ``stack.yaml`` file:
|
- The GF shell can be started with ``gf -cshell`` or ``gf -crun`` to use
|
||||||
|
the C run-time system instead of the Haskell run-time system.
|
||||||
|
Only limited functionality is available when running the shell in these
|
||||||
|
modes (use the ``help`` command in the shell for details).
|
||||||
|
|
||||||
```
|
- ``gf -server`` mode is extended with new requests to call the C run-time
|
||||||
flags:
|
system, e.g. ``c-parse``, ``c-linearize`` and ``c-translate``.
|
||||||
gf:
|
|
||||||
c-runtime: true
|
|
||||||
extra-lib-dirs:
|
|
||||||
- /usr/local/lib
|
|
||||||
```
|
|
||||||
and then run ``stack install`` from the top directory (``gf-core``).
|
|
||||||
|
|
||||||
|
|
||||||
//If you get an "``error while loading shared libraries``" when trying to run GF with C runtime, remember to declare your ``LD_LIBRARY_PATH``.//
|
=== Python and Java bindings ===
|
||||||
//Add ``export LD_LIBRARY_PATH="/usr/local/lib"`` to either your ``.bashrc`` or ``.profile``. You should now be able to start GF with C runtime.//
|
|
||||||
|
|
||||||
|
|
||||||
=== Use GF server mode with C runtime ===
|
|
||||||
|
|
||||||
- **What —**
|
|
||||||
With this feature, ``gf -server`` mode is extended with new requests to call the C run-time
|
|
||||||
system, e.g. ``c-parse``, ``c-linearize`` and ``c-translate``.
|
|
||||||
|
|
||||||
- **How —**
|
|
||||||
If you use cabal, run the following command:
|
|
||||||
|
|
||||||
```
|
|
||||||
cabal install -fc-runtime -fserver
|
|
||||||
```
|
|
||||||
from the top directory.
|
|
||||||
|
|
||||||
If you use stack, add the following lines in the ``stack.yaml`` file:
|
|
||||||
|
|
||||||
```
|
|
||||||
flags:
|
|
||||||
gf:
|
|
||||||
c-runtime: true
|
|
||||||
server: true
|
|
||||||
extra-lib-dirs:
|
|
||||||
- /usr/local/lib
|
|
||||||
```
|
|
||||||
|
|
||||||
and then run ``stack install``, also from the top directory.
|
|
||||||
|
|
||||||
|
The C run-time system can also be used from Python and Java. Python and Java
|
||||||
|
bindings are found in the ``src/runtime/python`` and ``src/runtime/java``
|
||||||
|
directories, respecively. Compile them by following the instructions in
|
||||||
|
the ``INSTALL`` files in those directories.
|
||||||
|
|
||||||
|
The Python library can also be installed from PyPI using `pip install pgf`.
|
||||||
|
|
||||||
== Compilation of RGL ==
|
== Compilation of RGL ==
|
||||||
|
|
||||||
As of 2018-07-26, the RGL is distributed separately from the GF compiler and runtimes.
|
As of 2018-07-26, the RGL is distributed separately from the GF compiler and runtimes.
|
||||||
|
|
||||||
To get the source, follow the previous instructions on [how to clone a repository with Git #getting-source].
|
|
||||||
|
|
||||||
After cloning the RGL, you should have a directory named ``gf-rgl`` on your computer.
|
|
||||||
|
|
||||||
=== Simple ===
|
=== Simple ===
|
||||||
To install the RGL, you can use the following commands from within the ``gf-rgl`` repository:
|
To install the RGL, you can use the following commands from within the ``gf-rgl`` repository:
|
||||||
```
|
```
|
||||||
@@ -317,68 +418,103 @@ If you do not have Haskell installed, you can use the simple build script ``Setu
|
|||||||
|
|
||||||
== Creating binary distribution packages ==
|
== Creating binary distribution packages ==
|
||||||
|
|
||||||
The binaries are generated with Github Actions. More details can be viewed here:
|
=== Creating .deb packages for Ubuntu ===
|
||||||
|
|
||||||
https://github.com/GrammaticalFramework/gf-core/actions/workflows/build-binary-packages.yml
|
This was tested on Ubuntu 14.04 for the release of GF 3.6, and the
|
||||||
|
resulting ``.deb`` packages appears to work on Ubuntu 12.04, 13.10 and 14.04.
|
||||||
|
For the release of GF 3.7, we generated ``.deb`` packages on Ubuntu 15.04 and
|
||||||
|
tested them on Ubuntu 12.04 and 14.04.
|
||||||
|
|
||||||
|
Under Ubuntu, Haskell executables are statically linked against other Haskell
|
||||||
|
libraries, so the .deb packages are fairly self-contained.
|
||||||
|
|
||||||
== Running the test suite ==
|
==== Preparations ====
|
||||||
|
|
||||||
The GF test suite is run with one of the following commands from the top directory:
|
|
||||||
|
|
||||||
```
|
```
|
||||||
$ cabal test
|
sudo apt-get install dpkg-dev debhelper
|
||||||
```
|
```
|
||||||
|
|
||||||
or
|
==== Creating the package ====
|
||||||
|
|
||||||
|
Make sure the ``debian/changelog`` starts with an entry that describes the
|
||||||
|
version you are building. Then run
|
||||||
|
|
||||||
```
|
```
|
||||||
$ stack test
|
make deb
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If get error messages about missing dependencies
|
||||||
|
(e.g. ``autoconf``, ``automake``, ``libtool-bin``, ``python-dev``,
|
||||||
|
``java-sdk``, ``txt2tags``)
|
||||||
|
use ``apt-get intall`` to install them, then try again.
|
||||||
|
|
||||||
|
|
||||||
|
=== Creating OS X Installer packages ===
|
||||||
|
|
||||||
|
Run
|
||||||
|
|
||||||
|
```
|
||||||
|
make pkg
|
||||||
|
```
|
||||||
|
|
||||||
|
=== Creating binary tar distributions ===
|
||||||
|
|
||||||
|
Run
|
||||||
|
|
||||||
|
```
|
||||||
|
make bintar
|
||||||
|
```
|
||||||
|
|
||||||
|
=== Creating .rpm packages for Fedora ===
|
||||||
|
|
||||||
|
This is possible, but the procedure has not been automated.
|
||||||
|
It involves using the cabal-rpm tool,
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo dnf install cabal-rpm
|
||||||
|
```
|
||||||
|
|
||||||
|
and following the Fedora guide
|
||||||
|
[How to create an RPM package http://fedoraproject.org/wiki/How_to_create_an_RPM_package].
|
||||||
|
|
||||||
|
Under Fedora, Haskell executables are dynamically linked against other Haskell
|
||||||
|
libraries, so ``.rpm`` packages for all Haskell libraries that GF depends on
|
||||||
|
are required. Most of them are already available in the Fedora distribution,
|
||||||
|
but a few of them might have to be built and distributed along with
|
||||||
|
the GF ``.rpm`` package.
|
||||||
|
When building ``.rpm`` packages for GF 3.4, we also had to build ``.rpm``s for
|
||||||
|
``fst`` and ``httpd-shed``.
|
||||||
|
|
||||||
|
== Running the testsuite ==
|
||||||
|
|
||||||
|
**NOTE:** The test suite has not been maintained recently, so expect many
|
||||||
|
tests to fail.
|
||||||
|
%% // TH 2012-08-06
|
||||||
|
|
||||||
|
GF has testsuite. It is run with the following command:
|
||||||
|
```
|
||||||
|
$ cabal test
|
||||||
|
```
|
||||||
The testsuite architecture for GF is very simple but still very flexible.
|
The testsuite architecture for GF is very simple but still very flexible.
|
||||||
GF by itself is an interpreter and could execute commands in batch mode.
|
GF by itself is an interpreter and could execute commands in batch mode.
|
||||||
This is everything that we need to organize a testsuite. The root of the
|
This is everything that we need to organize a testsuite. The root of the
|
||||||
testsuite is the ``testsuite/`` directory. It contains subdirectories
|
testsuite is the testsuite/ directory. It contains subdirectories which
|
||||||
which themselves contain GF batch files (with extension ``.gfs``).
|
themself contain GF batch files (with extension .gfs). The above command
|
||||||
The above command searches the subdirectories of the ``testsuite/`` directory
|
searches the subdirectories of the testsuite/ directory for files with extension
|
||||||
for files with extension ``.gfs`` and when it finds one, it is executed with
|
.gfs and when it finds one it is executed with the GF interpreter.
|
||||||
the GF interpreter. The output of the script is stored in file with extension ``.out``
|
The output of the script is stored in file with extension .out and is compared
|
||||||
and is compared with the content of the corresponding file with extension ``.gold``, if there is one.
|
with the content of the corresponding file with extension .gold, if there is one.
|
||||||
|
If the contents are identical the command reports that the test was passed successfully.
|
||||||
|
Otherwise the test had failed.
|
||||||
|
|
||||||
Every time when you make some changes to GF that have to be tested,
|
Every time when you make some changes to GF that have to be tested, instead of
|
||||||
instead of writing the commands by hand in the GF shell, add them to one ``.gfs``
|
writing the commands by hand in the GF shell, add them to one .gfs file in the testsuite
|
||||||
file in the testsuite subdirectory where its ``.gf`` file resides and run the test.
|
and run the test. In this way you can use the same test later and we will be sure
|
||||||
In this way you can use the same test later and we will be sure that we will not
|
that we will not incidentaly break your code later.
|
||||||
accidentally break your code later.
|
|
||||||
|
|
||||||
**Test Outcome - Passed:** If the contents of the files with the ``.out`` extension
|
|
||||||
are identical to their correspondingly-named files with the extension ``.gold``,
|
|
||||||
the command will report that the tests passed successfully, e.g.
|
|
||||||
|
|
||||||
|
If you don't want to run the whole testsuite you can write the path to the subdirectory
|
||||||
|
in which you are interested. For example:
|
||||||
```
|
```
|
||||||
Running 1 test suites...
|
$ cabal test testsuite/compiler
|
||||||
Test suite gf-tests: RUNNING...
|
|
||||||
Test suite gf-tests: PASS
|
|
||||||
1 of 1 test suites (1 of 1 test cases) passed.
|
|
||||||
```
|
```
|
||||||
|
will run only the testsuite for the compiler.
|
||||||
**Test Outcome - Failed:** If there is a contents mismatch between the files
|
|
||||||
with the ``.out`` extension and their corresponding files with the extension ``.gold``,
|
|
||||||
the test diagnostics will show a fail and the areas that failed. e.g.
|
|
||||||
|
|
||||||
```
|
|
||||||
testsuite/compiler/compute/Records.gfs: OK
|
|
||||||
testsuite/compiler/compute/Variants.gfs: FAIL
|
|
||||||
testsuite/compiler/params/params.gfs: OK
|
|
||||||
Test suite gf-tests: FAIL
|
|
||||||
0 of 1 test suites (0 of 1 test cases) passed.
|
|
||||||
```
|
|
||||||
|
|
||||||
The fail results overview is available in gf-tests.html which shows 4 columns:
|
|
||||||
|
|
||||||
+ __Results__ - only areas that fail will appear. (Note: There are 3 failures in the gf-tests.html which are labelled as (expected). These failures should be ignored.)
|
|
||||||
+ __Input__ - which is the test written in the .gfs file
|
|
||||||
+ __Gold__ - the expected output from running the test set out in the .gfs file. This column refers to the contents from the .gold extension files.
|
|
||||||
+ __Output__ - This column refers to the contents from the .out extension files which are generated as test output.
|
|
||||||
After fixing the areas which fail, rerun the test command. Repeat the entire process of fix-and-test until the test suite passes before submitting a pull request to include your changes.
|
|
||||||
|
|||||||
@@ -15,12 +15,6 @@ instructions inside.
|
|||||||
==Atom==
|
==Atom==
|
||||||
[language-gf https://atom.io/packages/language-gf], by John J. Camilleri
|
[language-gf https://atom.io/packages/language-gf], by John J. Camilleri
|
||||||
|
|
||||||
==Visual Studio Code==
|
|
||||||
|
|
||||||
[Grammatical Framework Language Server https://marketplace.visualstudio.com/items?itemName=anka-213.gf-vscode] by Andreas Källberg.
|
|
||||||
|
|
||||||
This provides syntax highlighting and a client for the Grammatical Framework language server. Follow the installation instructions in the link.
|
|
||||||
|
|
||||||
==Eclipse==
|
==Eclipse==
|
||||||
|
|
||||||
[GF Eclipse Plugin https://github.com/GrammaticalFramework/gf-eclipse-plugin/], by John J. Camilleri
|
[GF Eclipse Plugin https://github.com/GrammaticalFramework/gf-eclipse-plugin/], by John J. Camilleri
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
---
|
---
|
||||||
title: Grammatical Framework Download and Installation
|
title: Grammatical Framework Download and Installation
|
||||||
date: 25 July 2021
|
...
|
||||||
---
|
|
||||||
|
|
||||||
**GF 3.11** was released on 25 July 2021.
|
**GF 3.11** was released on ... December 2020.
|
||||||
|
|
||||||
What's new? See the [release notes](release-3.11.html).
|
What's new? See the [release notes](release-3.11.html).
|
||||||
|
|
||||||
@@ -25,25 +24,22 @@ Binary packages are available for Debian/Ubuntu, macOS, and Windows and include:
|
|||||||
|
|
||||||
Unlike in previous versions, the binaries **do not** include the RGL.
|
Unlike in previous versions, the binaries **do not** include the RGL.
|
||||||
|
|
||||||
[Binary packages on GitHub](https://github.com/GrammaticalFramework/gf-core/releases/tag/3.11)
|
[Binary packages on GitHub](https://github.com/GrammaticalFramework/gf-core/releases/tag/RELEASE-3.11)
|
||||||
|
|
||||||
#### Debian/Ubuntu
|
#### Debian/Ubuntu
|
||||||
|
|
||||||
There are two versions: `gf-3.11-ubuntu-18.04.deb` for Ubuntu 18.04 (Cosmic), and `gf-3.11-ubuntu-20.04.deb` for Ubuntu 20.04 (Focal).
|
|
||||||
|
|
||||||
To install the package use:
|
To install the package use:
|
||||||
|
|
||||||
```
|
```
|
||||||
sudo apt-get install ./gf-3.11-ubuntu-*.deb
|
sudo dpkg -i gf_3.11.deb
|
||||||
```
|
```
|
||||||
|
|
||||||
<!-- The Ubuntu `.deb` packages should work on Ubuntu 16.04, 18.04 and similar Linux distributions. -->
|
The Ubuntu `.deb` packages should work on Ubuntu 16.04, 18.04 and similar Linux distributions.
|
||||||
|
|
||||||
#### macOS
|
#### macOS
|
||||||
|
|
||||||
To install the package, just double-click it and follow the installer instructions.
|
To install the package, just double-click it and follow the installer instructions.
|
||||||
|
|
||||||
The packages should work on at least Catalina and Big Sur.
|
The packages should work on at least 10.13 (High Sierra) and 10.14 (Mojave).
|
||||||
|
|
||||||
#### Windows
|
#### Windows
|
||||||
|
|
||||||
@@ -53,17 +49,15 @@ You will probably need to update the `PATH` environment variable to include your
|
|||||||
|
|
||||||
For more information, see [Using GF on Windows](https://www.grammaticalframework.org/~inari/gf-windows.html) (latest updated for Windows 10).
|
For more information, see [Using GF on Windows](https://www.grammaticalframework.org/~inari/gf-windows.html) (latest updated for Windows 10).
|
||||||
|
|
||||||
<!--## Installing the latest Hackage release (macOS, Linux, and WSL2 on Windows)
|
## Installing the latest release from source
|
||||||
|
|
||||||
[GF is on Hackage](http://hackage.haskell.org/package/gf), so under
|
[GF is on Hackage](http://hackage.haskell.org/package/gf), so under
|
||||||
normal circumstances the procedure is fairly simple:
|
normal circumstances the procedure is fairly simple:
|
||||||
|
|
||||||
1. Install ghcup https://www.haskell.org/ghcup/
|
1. Install a recent version of the [Haskell Platform](http://hackage.haskell.org/platform) (see note below)
|
||||||
2. `ghcup install ghc 8.10.4`
|
2. `cabal update`
|
||||||
3. `ghcup set ghc 8.10.4`
|
3. On Linux: install some C libraries from your Linux distribution (see note below)
|
||||||
4. `cabal update`
|
4. `cabal install gf`
|
||||||
5. On Linux: install some C libraries from your Linux distribution (see note below)
|
|
||||||
6. `cabal install gf-3.11`
|
|
||||||
|
|
||||||
You can also download the source code release from [GitHub](https://github.com/GrammaticalFramework/gf-core/releases),
|
You can also download the source code release from [GitHub](https://github.com/GrammaticalFramework/gf-core/releases),
|
||||||
and follow the instructions below under **Installing from the latest developer source code**.
|
and follow the instructions below under **Installing from the latest developer source code**.
|
||||||
@@ -80,6 +74,17 @@ so you might want to add this directory to your path (in `.bash_profile` or simi
|
|||||||
PATH=$HOME/.cabal/bin:$PATH
|
PATH=$HOME/.cabal/bin:$PATH
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Build tools**
|
||||||
|
|
||||||
|
In order to compile GF you need the build tools **Alex** and **Happy**.
|
||||||
|
These can be installed via Cabal, e.g.:
|
||||||
|
|
||||||
|
```
|
||||||
|
cabal install alex happy
|
||||||
|
```
|
||||||
|
|
||||||
|
or obtained by other means, depending on your OS.
|
||||||
|
|
||||||
**Haskeline**
|
**Haskeline**
|
||||||
|
|
||||||
GF uses [`haskeline`](http://hackage.haskell.org/package/haskeline), which
|
GF uses [`haskeline`](http://hackage.haskell.org/package/haskeline), which
|
||||||
@@ -93,7 +98,7 @@ Here is one way to do this:
|
|||||||
**GHC version**
|
**GHC version**
|
||||||
|
|
||||||
The GF source code has been updated to compile with GHC versions 7.10 through to 8.8.
|
The GF source code has been updated to compile with GHC versions 7.10 through to 8.8.
|
||||||
-->
|
|
||||||
## Installing from the latest developer source code
|
## Installing from the latest developer source code
|
||||||
|
|
||||||
If you haven't already, clone the repository with:
|
If you haven't already, clone the repository with:
|
||||||
@@ -120,7 +125,7 @@ or, if you're a Stack user:
|
|||||||
stack install
|
stack install
|
||||||
```
|
```
|
||||||
|
|
||||||
<!--The above notes for installing from source apply also in these cases.-->
|
The above notes for installing from source apply also in these cases.
|
||||||
For more info on working with the GF source code, see the
|
For more info on working with the GF source code, see the
|
||||||
[GF Developers Guide](../doc/gf-developers.html).
|
[GF Developers Guide](../doc/gf-developers.html).
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta http-equiv="refresh" content="0; URL=/download/index-3.11.html" />
|
<meta http-equiv="refresh" content="0; URL=/download/index-3.10.html" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
You are being redirected to <a href="index-3.11.html">the current version</a> of this page.
|
You are being redirected to <a href="index-3.10.html">the current version</a> of this page.
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
title: GF 3.11 Release Notes
|
title: GF 3.11 Release Notes
|
||||||
date: 25 July 2021
|
date: ... December 2020
|
||||||
---
|
...
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
@@ -12,27 +12,24 @@ See the [download page](index-3.11.html).
|
|||||||
From this release, the binary GF core packages do not contain the RGL.
|
From this release, the binary GF core packages do not contain the RGL.
|
||||||
The RGL's release cycle is now completely separate from GF's. See [RGL releases](https://github.com/GrammaticalFramework/gf-rgl/releases).
|
The RGL's release cycle is now completely separate from GF's. See [RGL releases](https://github.com/GrammaticalFramework/gf-rgl/releases).
|
||||||
|
|
||||||
Over 500 changes have been pushed to GF core
|
Over 400 changes have been pushed to GF core
|
||||||
since the release of GF 3.10 in December 2018.
|
since the release of GF 3.10 in December 2018.
|
||||||
|
|
||||||
## General
|
## General
|
||||||
|
|
||||||
- Make the test suite work again.
|
- Make the test suite work again.
|
||||||
- Compatibility with new versions of GHC, including multiple Stack files for the different versions.
|
- Compatibility with new versions of GHC, including multiple Stack files for the different versions.
|
||||||
- Support for newer version of Ubuntu 20.04 in the precompiled binaries.
|
- Updates to build scripts and CI.
|
||||||
- Updates to build scripts and CI workflows.
|
- Bug fixes.
|
||||||
- Bug fixes and code cleanup.
|
|
||||||
|
|
||||||
## GF compiler and run-time library
|
## GF compiler and run-time library
|
||||||
|
|
||||||
|
- Huge improvements in time & space requirements for grammar compilation (pending [#87](https://github.com/GrammaticalFramework/gf-core/pull/87)).
|
||||||
- Add CoNLL output to `visualize_tree` shell command.
|
- Add CoNLL output to `visualize_tree` shell command.
|
||||||
- Add canonical GF as output format in the compiler.
|
- Add canonical GF as output format in the compiler.
|
||||||
- Add PGF JSON as output format in the compiler.
|
- Add PGF JSON as output format in the compiler.
|
||||||
- Deprecate JavaScript runtime in favour of updated [TypeScript runtime](https://github.com/GrammaticalFramework/gf-typescript).
|
- Deprecate JavaScript runtime in favour of updated [TypeScript runtime](https://github.com/GrammaticalFramework/gf-typescript).
|
||||||
- Improvements in time & space requirements when compiling certain grammars.
|
|
||||||
- Improvements to Haskell export.
|
- Improvements to Haskell export.
|
||||||
- Improvements to the GF shell.
|
|
||||||
- Improvements to canonical GF compilation.
|
|
||||||
- Improvements to the C runtime.
|
- Improvements to the C runtime.
|
||||||
- Improvements to `gf -server` mode.
|
- Improvements to `gf -server` mode.
|
||||||
- Clearer compiler error messages.
|
- Clearer compiler error messages.
|
||||||
|
|||||||
630
gf.cabal
630
gf.cabal
@@ -1,19 +1,19 @@
|
|||||||
name: gf
|
name: gf
|
||||||
version: 3.11.0-git
|
version: 3.10.4-git
|
||||||
|
|
||||||
cabal-version: 1.22
|
cabal-version: >= 1.22
|
||||||
build-type: Custom
|
build-type: Custom
|
||||||
license: OtherLicense
|
license: OtherLicense
|
||||||
license-file: LICENSE
|
license-file: LICENSE
|
||||||
category: Natural Language Processing, Compiler
|
category: Natural Language Processing, Compiler
|
||||||
synopsis: Grammatical Framework
|
synopsis: Grammatical Framework
|
||||||
description: GF, Grammatical Framework, is a programming language for multilingual grammar applications
|
description: GF, Grammatical Framework, is a programming language for multilingual grammar applications
|
||||||
homepage: https://www.grammaticalframework.org/
|
homepage: http://www.grammaticalframework.org/
|
||||||
bug-reports: https://github.com/GrammaticalFramework/gf-core/issues
|
bug-reports: https://github.com/GrammaticalFramework/gf-core/issues
|
||||||
tested-with: GHC==7.10.3, GHC==8.0.2, GHC==8.10.4
|
maintainer: Thomas Hallgren
|
||||||
|
tested-with: GHC==7.10.3, GHC==8.0.2, GHC==8.2.2, GHC==8.4.3
|
||||||
|
|
||||||
data-dir: src
|
data-dir: src
|
||||||
extra-source-files: WebSetup.hs
|
|
||||||
data-files:
|
data-files:
|
||||||
www/*.html
|
www/*.html
|
||||||
www/*.css
|
www/*.css
|
||||||
@@ -41,34 +41,39 @@ data-files:
|
|||||||
|
|
||||||
custom-setup
|
custom-setup
|
||||||
setup-depends:
|
setup-depends:
|
||||||
base >= 4.9.1 && < 4.15,
|
base,
|
||||||
Cabal >= 1.22.0.0,
|
Cabal >=1.22.0.0,
|
||||||
directory >= 1.3.0 && < 1.4,
|
directory,
|
||||||
filepath >= 1.4.1 && < 1.5,
|
filepath,
|
||||||
process >= 1.0.1.1 && < 1.7
|
process >=1.0.1.1
|
||||||
|
|
||||||
source-repository head
|
source-repository head
|
||||||
type: git
|
type: git
|
||||||
location: https://github.com/GrammaticalFramework/gf-core.git
|
location: https://github.com/GrammaticalFramework/gf-core.git
|
||||||
|
|
||||||
flag interrupt
|
flag interrupt
|
||||||
Description: Enable Ctrl+Break in the shell
|
Description: Enable Ctrl+Break in the shell
|
||||||
Default: True
|
Default: True
|
||||||
|
|
||||||
flag server
|
flag server
|
||||||
Description: Include --server mode
|
Description: Include --server mode
|
||||||
Default: True
|
Default: True
|
||||||
|
|
||||||
flag network-uri
|
flag network-uri
|
||||||
description: Get Network.URI from the network-uri package
|
description: Get Network.URI from the network-uri package
|
||||||
default: True
|
default: True
|
||||||
|
|
||||||
executable gf
|
--flag new-comp
|
||||||
hs-source-dirs: src/programs, src/compiler
|
-- Description: Make -new-comp the default
|
||||||
main-is: gf-main.hs
|
-- Default: True
|
||||||
|
|
||||||
|
flag c-runtime
|
||||||
|
Description: Include functionality from the C run-time library (which must be installed already)
|
||||||
|
Default: False
|
||||||
|
|
||||||
|
Library
|
||||||
default-language: Haskell2010
|
default-language: Haskell2010
|
||||||
build-depends: pgf2,
|
build-depends: base >= 4.6 && <5,
|
||||||
base >= 4.6 && <5,
|
|
||||||
array,
|
array,
|
||||||
containers,
|
containers,
|
||||||
bytestring,
|
bytestring,
|
||||||
@@ -77,18 +82,85 @@ executable gf
|
|||||||
pretty,
|
pretty,
|
||||||
mtl,
|
mtl,
|
||||||
exceptions,
|
exceptions,
|
||||||
|
fail,
|
||||||
|
-- For compatability with ghc < 8
|
||||||
|
-- We need transformers-compat >= 0.6.3, but that is only in newer snapshots where it is redundant.
|
||||||
|
transformers-compat,
|
||||||
ghc-prim,
|
ghc-prim,
|
||||||
filepath, directory>=1.2, time,
|
text,
|
||||||
process, haskeline, parallel>=3, json
|
hashable,
|
||||||
ghc-options: -threaded
|
unordered-containers
|
||||||
|
hs-source-dirs: src/runtime/haskell
|
||||||
|
|
||||||
other-modules:
|
other-modules:
|
||||||
|
-- not really part of GF but I have changed the original binary library
|
||||||
|
-- and we have to keep the copy for now.
|
||||||
|
Data.Binary
|
||||||
|
Data.Binary.Put
|
||||||
|
Data.Binary.Get
|
||||||
|
Data.Binary.Builder
|
||||||
|
Data.Binary.IEEE754
|
||||||
|
|
||||||
|
--ghc-options: -fwarn-unused-imports
|
||||||
|
--if impl(ghc>=7.8)
|
||||||
|
-- ghc-options: +RTS -A20M -RTS
|
||||||
|
ghc-prof-options: -fprof-auto
|
||||||
|
|
||||||
|
exposed-modules:
|
||||||
|
PGF
|
||||||
|
PGF.Internal
|
||||||
|
PGF.Haskell
|
||||||
|
LPGF
|
||||||
|
|
||||||
|
other-modules:
|
||||||
|
PGF.Data
|
||||||
|
PGF.Macros
|
||||||
|
PGF.Binary
|
||||||
|
PGF.Optimize
|
||||||
|
PGF.Printer
|
||||||
|
PGF.CId
|
||||||
|
PGF.Expr
|
||||||
|
PGF.Generate
|
||||||
|
PGF.Linearize
|
||||||
|
PGF.Morphology
|
||||||
|
PGF.Paraphrase
|
||||||
|
PGF.Parse
|
||||||
|
PGF.Probabilistic
|
||||||
|
PGF.SortTop
|
||||||
|
PGF.Tree
|
||||||
|
PGF.Type
|
||||||
|
PGF.TypeCheck
|
||||||
|
PGF.Forest
|
||||||
|
PGF.TrieMap
|
||||||
|
PGF.VisualizeTree
|
||||||
|
PGF.ByteCode
|
||||||
|
PGF.OldBinary
|
||||||
|
PGF.Utilities
|
||||||
|
|
||||||
|
if flag(c-runtime)
|
||||||
|
exposed-modules: PGF2
|
||||||
|
other-modules: PGF2.FFI PGF2.Expr PGF2.Type
|
||||||
|
GF.Interactive2 GF.Command.Commands2
|
||||||
|
hs-source-dirs: src/runtime/haskell-bind
|
||||||
|
build-tools: hsc2hs
|
||||||
|
extra-libraries: pgf gu
|
||||||
|
c-sources: src/runtime/haskell-bind/utils.c
|
||||||
|
cc-options: -std=c99
|
||||||
|
|
||||||
|
---- GF compiler as a library:
|
||||||
|
|
||||||
|
build-depends: filepath, directory>=1.2, time,
|
||||||
|
process, haskeline, parallel>=3, json
|
||||||
|
|
||||||
|
hs-source-dirs: src/compiler
|
||||||
|
exposed-modules:
|
||||||
GF
|
GF
|
||||||
GF.Support
|
GF.Support
|
||||||
GF.Text.Pretty
|
GF.Text.Pretty
|
||||||
GF.Text.Lexing
|
GF.Text.Lexing
|
||||||
GF.Grammar.Canonical
|
GF.Grammar.Canonical
|
||||||
|
|
||||||
|
other-modules:
|
||||||
GF.Main GF.Compiler GF.Interactive
|
GF.Main GF.Compiler GF.Interactive
|
||||||
|
|
||||||
GF.Compile GF.CompileInParallel GF.CompileOne GF.Compile.GetGrammar
|
GF.Compile GF.CompileInParallel GF.CompileOne GF.Compile.GetGrammar
|
||||||
@@ -109,24 +181,27 @@ executable gf
|
|||||||
GF.Command.TreeOperations
|
GF.Command.TreeOperations
|
||||||
GF.Compile.CFGtoPGF
|
GF.Compile.CFGtoPGF
|
||||||
GF.Compile.CheckGrammar
|
GF.Compile.CheckGrammar
|
||||||
|
GF.Compile.Compute.ConcreteNew
|
||||||
GF.Compile.Compute.Predef
|
GF.Compile.Compute.Predef
|
||||||
GF.Compile.Compute.Value
|
GF.Compile.Compute.Value
|
||||||
GF.Compile.Compute.Concrete
|
|
||||||
GF.Compile.ExampleBased
|
GF.Compile.ExampleBased
|
||||||
GF.Compile.Export
|
GF.Compile.Export
|
||||||
GF.Compile.GenerateBC
|
GF.Compile.GenerateBC
|
||||||
GF.Compile.GeneratePMCFG
|
GF.Compile.GeneratePMCFG
|
||||||
|
GF.Compile.GrammarToLPGF
|
||||||
GF.Compile.GrammarToPGF
|
GF.Compile.GrammarToPGF
|
||||||
GF.Compile.Multi
|
GF.Compile.Multi
|
||||||
GF.Compile.Optimize
|
GF.Compile.Optimize
|
||||||
GF.Compile.OptimizePGF
|
|
||||||
GF.Compile.PGFtoHaskell
|
GF.Compile.PGFtoHaskell
|
||||||
GF.Compile.PGFtoJava
|
GF.Compile.PGFtoJava
|
||||||
GF.Haskell
|
GF.Haskell
|
||||||
GF.Compile.ConcreteToHaskell
|
GF.Compile.ConcreteToHaskell
|
||||||
GF.Compile.GrammarToCanonical
|
GF.Compile.GrammarToCanonical
|
||||||
GF.Grammar.CanonicalJSON
|
GF.Grammar.CanonicalJSON
|
||||||
|
GF.Compile.PGFtoJS
|
||||||
GF.Compile.PGFtoJSON
|
GF.Compile.PGFtoJSON
|
||||||
|
GF.Compile.PGFtoProlog
|
||||||
|
GF.Compile.PGFtoPython
|
||||||
GF.Compile.ReadFiles
|
GF.Compile.ReadFiles
|
||||||
GF.Compile.Rename
|
GF.Compile.Rename
|
||||||
GF.Compile.SubExOpt
|
GF.Compile.SubExOpt
|
||||||
@@ -136,12 +211,14 @@ executable gf
|
|||||||
GF.Compile.TypeCheck.Concrete
|
GF.Compile.TypeCheck.Concrete
|
||||||
GF.Compile.TypeCheck.ConcreteNew
|
GF.Compile.TypeCheck.ConcreteNew
|
||||||
GF.Compile.TypeCheck.Primitives
|
GF.Compile.TypeCheck.Primitives
|
||||||
|
GF.Compile.TypeCheck.RConcrete
|
||||||
GF.Compile.TypeCheck.TC
|
GF.Compile.TypeCheck.TC
|
||||||
GF.Compile.Update
|
GF.Compile.Update
|
||||||
GF.Data.BacktrackM
|
GF.Data.BacktrackM
|
||||||
GF.Data.ErrM
|
GF.Data.ErrM
|
||||||
GF.Data.Graph
|
GF.Data.Graph
|
||||||
GF.Data.Graphviz
|
GF.Data.Graphviz
|
||||||
|
GF.Data.IntMapBuilder
|
||||||
GF.Data.Relation
|
GF.Data.Relation
|
||||||
GF.Data.Str
|
GF.Data.Str
|
||||||
GF.Data.Utilities
|
GF.Data.Utilities
|
||||||
@@ -193,38 +270,491 @@ executable gf
|
|||||||
GF.System.Directory
|
GF.System.Directory
|
||||||
GF.System.Process
|
GF.System.Process
|
||||||
GF.System.Signal
|
GF.System.Signal
|
||||||
GF.System.NoSignal
|
GF.Text.Clitics
|
||||||
|
GF.Text.Coding
|
||||||
|
GF.Text.Transliterations
|
||||||
|
Paths_gf
|
||||||
|
|
||||||
|
if flag(c-runtime)
|
||||||
|
cpp-options: -DC_RUNTIME
|
||||||
|
|
||||||
|
if flag(server)
|
||||||
|
build-depends: httpd-shed>=0.4.0.3, network>=2.3 && <2.7,
|
||||||
|
cgi>=3001.2.2.0
|
||||||
|
if flag(network-uri)
|
||||||
|
build-depends: network-uri>=2.6, network>=2.6
|
||||||
|
else
|
||||||
|
build-depends: network<2.6
|
||||||
|
|
||||||
|
cpp-options: -DSERVER_MODE
|
||||||
|
other-modules:
|
||||||
|
GF.Server
|
||||||
|
PGFService
|
||||||
|
RunHTTP
|
||||||
|
SimpleEditor.Convert
|
||||||
|
SimpleEditor.JSON
|
||||||
|
SimpleEditor.Syntax
|
||||||
|
URLEncoding
|
||||||
|
CGI
|
||||||
|
CGIUtils
|
||||||
|
Cache
|
||||||
|
Fold
|
||||||
|
ExampleDemo
|
||||||
|
ExampleService
|
||||||
|
hs-source-dirs: src/server src/server/transfer src/example-based
|
||||||
|
|
||||||
|
if flag(interrupt)
|
||||||
|
cpp-options: -DUSE_INTERRUPT
|
||||||
|
other-modules: GF.System.UseSignal
|
||||||
|
else
|
||||||
|
other-modules: GF.System.NoSignal
|
||||||
|
|
||||||
|
if impl(ghc>=7.8)
|
||||||
|
build-tools: happy>=1.19, alex>=3.1
|
||||||
|
-- ghc-options: +RTS -A20M -RTS
|
||||||
|
else
|
||||||
|
build-tools: happy, alex>=3
|
||||||
|
|
||||||
|
ghc-options: -fno-warn-tabs
|
||||||
|
|
||||||
|
if os(windows)
|
||||||
|
build-depends: Win32
|
||||||
|
else
|
||||||
|
build-depends: unix, terminfo>=0.4
|
||||||
|
|
||||||
|
if impl(ghc>=8.2)
|
||||||
|
ghc-options: -fhide-source-paths
|
||||||
|
|
||||||
|
Executable gf
|
||||||
|
hs-source-dirs: src/programs
|
||||||
|
main-is: gf-main.hs
|
||||||
|
default-language: Haskell2010
|
||||||
|
build-depends: gf, base
|
||||||
|
ghc-options: -threaded
|
||||||
|
--ghc-options: -fwarn-unused-imports
|
||||||
|
|
||||||
|
if impl(ghc>=7.0)
|
||||||
|
ghc-options: -rtsopts -with-rtsopts=-I5
|
||||||
|
if impl(ghc<7.8)
|
||||||
|
ghc-options: -with-rtsopts=-K64M
|
||||||
|
|
||||||
|
ghc-prof-options: -auto-all
|
||||||
|
|
||||||
|
if impl(ghc>=8.2)
|
||||||
|
ghc-options: -fhide-source-paths
|
||||||
|
|
||||||
|
executable pgf-shell
|
||||||
|
--if !flag(c-runtime)
|
||||||
|
buildable: False
|
||||||
|
main-is: pgf-shell.hs
|
||||||
|
hs-source-dirs: src/runtime/haskell-bind/examples
|
||||||
|
build-depends: gf, base, containers, mtl, lifted-base
|
||||||
|
default-language: Haskell2010
|
||||||
|
if impl(ghc>=7.0)
|
||||||
|
ghc-options: -rtsopts
|
||||||
|
|
||||||
|
test-suite gf-tests
|
||||||
|
type: exitcode-stdio-1.0
|
||||||
|
main-is: run.hs
|
||||||
|
hs-source-dirs: testsuite
|
||||||
|
build-depends: base>=4.3 && <5, Cabal>=1.8, directory, filepath, process
|
||||||
|
default-language: Haskell2010
|
||||||
|
|
||||||
|
test-suite lpgf
|
||||||
|
type: exitcode-stdio-1.0
|
||||||
|
main-is: test.hs
|
||||||
|
hs-source-dirs:
|
||||||
|
src/compiler
|
||||||
|
src/runtime/haskell
|
||||||
|
testsuite/lpgf
|
||||||
|
other-modules:
|
||||||
|
Data.Binary
|
||||||
|
Data.Binary.Builder
|
||||||
|
Data.Binary.Get
|
||||||
|
Data.Binary.IEEE754
|
||||||
|
Data.Binary.Put
|
||||||
|
GF
|
||||||
|
GF.Command.Abstract
|
||||||
|
GF.Command.CommandInfo
|
||||||
|
GF.Command.Commands
|
||||||
|
GF.Command.CommonCommands
|
||||||
|
GF.Command.Help
|
||||||
|
GF.Command.Importing
|
||||||
|
GF.Command.Interpreter
|
||||||
|
GF.Command.Messages
|
||||||
|
GF.Command.Parse
|
||||||
|
GF.Command.SourceCommands
|
||||||
|
GF.Command.TreeOperations
|
||||||
|
GF.Compile
|
||||||
|
GF.Compile.CFGtoPGF
|
||||||
|
GF.Compile.CheckGrammar
|
||||||
|
GF.Compile.Compute.ConcreteNew
|
||||||
|
GF.Compile.Compute.Predef
|
||||||
|
GF.Compile.Compute.Value
|
||||||
|
GF.Compile.ConcreteToHaskell
|
||||||
|
GF.Compile.ExampleBased
|
||||||
|
GF.Compile.Export
|
||||||
|
GF.Compile.GenerateBC
|
||||||
|
GF.Compile.GeneratePMCFG
|
||||||
|
GF.Compile.GetGrammar
|
||||||
|
GF.Compile.GrammarToCanonical
|
||||||
|
GF.Compile.GrammarToLPGF
|
||||||
|
GF.Compile.GrammarToPGF
|
||||||
|
GF.Compile.Multi
|
||||||
|
GF.Compile.Optimize
|
||||||
|
GF.Compile.PGFtoHaskell
|
||||||
|
GF.Compile.PGFtoJava
|
||||||
|
GF.Compile.PGFtoJS
|
||||||
|
GF.Compile.PGFtoJSON
|
||||||
|
GF.Compile.PGFtoProlog
|
||||||
|
GF.Compile.PGFtoPython
|
||||||
|
GF.Compile.ReadFiles
|
||||||
|
GF.Compile.Rename
|
||||||
|
GF.Compile.SubExOpt
|
||||||
|
GF.Compile.Tags
|
||||||
|
GF.Compile.ToAPI
|
||||||
|
GF.Compile.TypeCheck.Abstract
|
||||||
|
GF.Compile.TypeCheck.ConcreteNew
|
||||||
|
GF.Compile.TypeCheck.Primitives
|
||||||
|
GF.Compile.TypeCheck.RConcrete
|
||||||
|
GF.Compile.TypeCheck.TC
|
||||||
|
GF.Compile.Update
|
||||||
|
GF.CompileInParallel
|
||||||
|
GF.CompileOne
|
||||||
|
GF.Compiler
|
||||||
|
GF.Data.BacktrackM
|
||||||
|
GF.Data.ErrM
|
||||||
|
GF.Data.Graph
|
||||||
|
GF.Data.Graphviz
|
||||||
|
GF.Data.IntMapBuilder
|
||||||
|
GF.Data.Operations
|
||||||
|
GF.Data.Relation
|
||||||
|
GF.Data.Str
|
||||||
|
GF.Data.Utilities
|
||||||
|
GF.Data.XML
|
||||||
|
GF.Grammar
|
||||||
|
GF.Grammar.Analyse
|
||||||
|
GF.Grammar.Binary
|
||||||
|
GF.Grammar.BNFC
|
||||||
|
GF.Grammar.Canonical
|
||||||
|
GF.Grammar.CanonicalJSON
|
||||||
|
GF.Grammar.CFG
|
||||||
|
GF.Grammar.EBNF
|
||||||
|
GF.Grammar.Grammar
|
||||||
|
GF.Grammar.Lexer
|
||||||
|
GF.Grammar.Lockfield
|
||||||
|
GF.Grammar.Lookup
|
||||||
|
GF.Grammar.Macros
|
||||||
|
GF.Grammar.Parser
|
||||||
|
GF.Grammar.PatternMatch
|
||||||
|
GF.Grammar.Predef
|
||||||
|
GF.Grammar.Printer
|
||||||
|
GF.Grammar.ShowTerm
|
||||||
|
GF.Grammar.Unify
|
||||||
|
GF.Grammar.Values
|
||||||
|
GF.Haskell
|
||||||
|
GF.Infra.BuildInfo
|
||||||
|
GF.Infra.CheckM
|
||||||
|
GF.Infra.Concurrency
|
||||||
|
GF.Infra.Dependencies
|
||||||
|
GF.Infra.GetOpt
|
||||||
|
GF.Infra.Ident
|
||||||
|
GF.Infra.Location
|
||||||
|
GF.Infra.Option
|
||||||
|
GF.Infra.SIO
|
||||||
|
GF.Infra.UseIO
|
||||||
|
GF.Interactive
|
||||||
|
GF.JavaScript.AbsJS
|
||||||
|
GF.JavaScript.PrintJS
|
||||||
|
GF.Main
|
||||||
|
GF.Quiz
|
||||||
|
GF.Speech.CFGToFA
|
||||||
|
GF.Speech.FiniteState
|
||||||
|
GF.Speech.GSL
|
||||||
|
GF.Speech.JSGF
|
||||||
|
GF.Speech.PGFToCFG
|
||||||
|
GF.Speech.PrRegExp
|
||||||
|
GF.Speech.RegExp
|
||||||
|
GF.Speech.SISR
|
||||||
|
GF.Speech.SLF
|
||||||
|
GF.Speech.SRG
|
||||||
|
GF.Speech.SRGS_ABNF
|
||||||
|
GF.Speech.SRGS_XML
|
||||||
|
GF.Speech.VoiceXML
|
||||||
|
GF.Support
|
||||||
|
GF.System.Catch
|
||||||
|
GF.System.Concurrency
|
||||||
|
GF.System.Console
|
||||||
|
GF.System.Directory
|
||||||
|
GF.System.Process
|
||||||
|
GF.System.Signal
|
||||||
GF.Text.Clitics
|
GF.Text.Clitics
|
||||||
GF.Text.Coding
|
GF.Text.Coding
|
||||||
GF.Text.Lexing
|
GF.Text.Lexing
|
||||||
|
GF.Text.Pretty
|
||||||
GF.Text.Transliterations
|
GF.Text.Transliterations
|
||||||
|
LPGF
|
||||||
|
PGF
|
||||||
|
PGF.Binary
|
||||||
|
PGF.ByteCode
|
||||||
|
PGF.CId
|
||||||
|
PGF.Data
|
||||||
|
PGF.Expr
|
||||||
|
PGF.Forest
|
||||||
|
PGF.Generate
|
||||||
|
PGF.Internal
|
||||||
|
PGF.Linearize
|
||||||
|
PGF.Macros
|
||||||
|
PGF.Morphology
|
||||||
|
PGF.OldBinary
|
||||||
|
PGF.Optimize
|
||||||
|
PGF.Paraphrase
|
||||||
|
PGF.Parse
|
||||||
|
PGF.Printer
|
||||||
|
PGF.Probabilistic
|
||||||
|
PGF.Tree
|
||||||
|
PGF.TrieMap
|
||||||
|
PGF.Type
|
||||||
|
PGF.TypeCheck
|
||||||
|
PGF.Utilities
|
||||||
|
PGF.VisualizeTree
|
||||||
Paths_gf
|
Paths_gf
|
||||||
|
if flag(interrupt)
|
||||||
-- not really part of GF but I have changed the original binary library
|
cpp-options: -DUSE_INTERRUPT
|
||||||
-- and we have to keep the copy for now.
|
other-modules: GF.System.UseSignal
|
||||||
Data.Binary
|
|
||||||
Data.Binary.Put
|
|
||||||
Data.Binary.Get
|
|
||||||
Data.Binary.Builder
|
|
||||||
Data.Binary.IEEE754
|
|
||||||
|
|
||||||
if os(windows)
|
|
||||||
build-depends:
|
|
||||||
Win32 >= 2.3.1.1 && < 2.7
|
|
||||||
else
|
else
|
||||||
build-depends:
|
other-modules: GF.System.NoSignal
|
||||||
terminfo >=0.4.0 && < 0.5,
|
|
||||||
unix >= 2.7.2 && < 2.8
|
|
||||||
|
|
||||||
test-suite gf-tests
|
|
||||||
type: exitcode-stdio-1.0
|
|
||||||
main-is: run.hs
|
|
||||||
hs-source-dirs: testsuite
|
|
||||||
build-depends:
|
build-depends:
|
||||||
base >= 4.9.1 && < 4.15,
|
ansi-terminal,
|
||||||
Cabal >= 1.8,
|
array,
|
||||||
directory >= 1.3.0 && < 1.4,
|
base>=4.6 && <5,
|
||||||
filepath >= 1.4.1 && < 1.5,
|
bytestring,
|
||||||
process >= 1.4.3 && < 1.7
|
containers,
|
||||||
build-tool-depends: gf:gf
|
directory,
|
||||||
|
filepath,
|
||||||
|
ghc-prim,
|
||||||
|
hashable,
|
||||||
|
haskeline,
|
||||||
|
json,
|
||||||
|
mtl,
|
||||||
|
parallel>=3,
|
||||||
|
pretty,
|
||||||
|
process,
|
||||||
|
random,
|
||||||
|
terminfo,
|
||||||
|
text,
|
||||||
|
time,
|
||||||
|
transformers-compat,
|
||||||
|
unix,
|
||||||
|
unordered-containers,
|
||||||
|
utf8-string
|
||||||
|
default-language: Haskell2010
|
||||||
|
|
||||||
|
benchmark lpgf-bench
|
||||||
|
type: exitcode-stdio-1.0
|
||||||
|
main-is: bench.hs
|
||||||
|
hs-source-dirs:
|
||||||
|
src/compiler
|
||||||
|
src/runtime/haskell
|
||||||
|
testsuite/lpgf
|
||||||
|
other-modules:
|
||||||
|
Data.Binary
|
||||||
|
Data.Binary.Builder
|
||||||
|
Data.Binary.Get
|
||||||
|
Data.Binary.IEEE754
|
||||||
|
Data.Binary.Put
|
||||||
|
GF
|
||||||
|
GF.Command.Abstract
|
||||||
|
GF.Command.CommandInfo
|
||||||
|
GF.Command.Commands
|
||||||
|
GF.Command.CommonCommands
|
||||||
|
GF.Command.Help
|
||||||
|
GF.Command.Importing
|
||||||
|
GF.Command.Interpreter
|
||||||
|
GF.Command.Messages
|
||||||
|
GF.Command.Parse
|
||||||
|
GF.Command.SourceCommands
|
||||||
|
GF.Command.TreeOperations
|
||||||
|
GF.Compile
|
||||||
|
GF.Compile.CFGtoPGF
|
||||||
|
GF.Compile.CheckGrammar
|
||||||
|
GF.Compile.Compute.ConcreteNew
|
||||||
|
GF.Compile.Compute.Predef
|
||||||
|
GF.Compile.Compute.Value
|
||||||
|
GF.Compile.ConcreteToHaskell
|
||||||
|
GF.Compile.ExampleBased
|
||||||
|
GF.Compile.Export
|
||||||
|
GF.Compile.GenerateBC
|
||||||
|
GF.Compile.GeneratePMCFG
|
||||||
|
GF.Compile.GetGrammar
|
||||||
|
GF.Compile.GrammarToCanonical
|
||||||
|
GF.Compile.GrammarToLPGF
|
||||||
|
GF.Compile.GrammarToPGF
|
||||||
|
GF.Compile.Multi
|
||||||
|
GF.Compile.Optimize
|
||||||
|
GF.Compile.PGFtoHaskell
|
||||||
|
GF.Compile.PGFtoJS
|
||||||
|
GF.Compile.PGFtoJSON
|
||||||
|
GF.Compile.PGFtoJava
|
||||||
|
GF.Compile.PGFtoProlog
|
||||||
|
GF.Compile.PGFtoPython
|
||||||
|
GF.Compile.ReadFiles
|
||||||
|
GF.Compile.Rename
|
||||||
|
GF.Compile.SubExOpt
|
||||||
|
GF.Compile.Tags
|
||||||
|
GF.Compile.ToAPI
|
||||||
|
GF.Compile.TypeCheck.Abstract
|
||||||
|
GF.Compile.TypeCheck.ConcreteNew
|
||||||
|
GF.Compile.TypeCheck.Primitives
|
||||||
|
GF.Compile.TypeCheck.RConcrete
|
||||||
|
GF.Compile.TypeCheck.TC
|
||||||
|
GF.Compile.Update
|
||||||
|
GF.CompileInParallel
|
||||||
|
GF.CompileOne
|
||||||
|
GF.Compiler
|
||||||
|
GF.Data.BacktrackM
|
||||||
|
GF.Data.ErrM
|
||||||
|
GF.Data.Graph
|
||||||
|
GF.Data.Graphviz
|
||||||
|
GF.Data.IntMapBuilder
|
||||||
|
GF.Data.Operations
|
||||||
|
GF.Data.Relation
|
||||||
|
GF.Data.Str
|
||||||
|
GF.Data.Utilities
|
||||||
|
GF.Data.XML
|
||||||
|
GF.Grammar
|
||||||
|
GF.Grammar.Analyse
|
||||||
|
GF.Grammar.BNFC
|
||||||
|
GF.Grammar.Binary
|
||||||
|
GF.Grammar.CFG
|
||||||
|
GF.Grammar.Canonical
|
||||||
|
GF.Grammar.CanonicalJSON
|
||||||
|
GF.Grammar.EBNF
|
||||||
|
GF.Grammar.Grammar
|
||||||
|
GF.Grammar.Lexer
|
||||||
|
GF.Grammar.Lockfield
|
||||||
|
GF.Grammar.Lookup
|
||||||
|
GF.Grammar.Macros
|
||||||
|
GF.Grammar.Parser
|
||||||
|
GF.Grammar.PatternMatch
|
||||||
|
GF.Grammar.Predef
|
||||||
|
GF.Grammar.Printer
|
||||||
|
GF.Grammar.ShowTerm
|
||||||
|
GF.Grammar.Unify
|
||||||
|
GF.Grammar.Values
|
||||||
|
GF.Haskell
|
||||||
|
GF.Infra.BuildInfo
|
||||||
|
GF.Infra.CheckM
|
||||||
|
GF.Infra.Concurrency
|
||||||
|
GF.Infra.Dependencies
|
||||||
|
GF.Infra.GetOpt
|
||||||
|
GF.Infra.Ident
|
||||||
|
GF.Infra.Location
|
||||||
|
GF.Infra.Option
|
||||||
|
GF.Infra.SIO
|
||||||
|
GF.Infra.UseIO
|
||||||
|
GF.Interactive
|
||||||
|
GF.JavaScript.AbsJS
|
||||||
|
GF.JavaScript.PrintJS
|
||||||
|
GF.Main
|
||||||
|
GF.Quiz
|
||||||
|
GF.Speech.CFGToFA
|
||||||
|
GF.Speech.FiniteState
|
||||||
|
GF.Speech.GSL
|
||||||
|
GF.Speech.JSGF
|
||||||
|
GF.Speech.PGFToCFG
|
||||||
|
GF.Speech.PrRegExp
|
||||||
|
GF.Speech.RegExp
|
||||||
|
GF.Speech.SISR
|
||||||
|
GF.Speech.SLF
|
||||||
|
GF.Speech.SRG
|
||||||
|
GF.Speech.SRGS_ABNF
|
||||||
|
GF.Speech.SRGS_XML
|
||||||
|
GF.Speech.VoiceXML
|
||||||
|
GF.Support
|
||||||
|
GF.System.Catch
|
||||||
|
GF.System.Concurrency
|
||||||
|
GF.System.Console
|
||||||
|
GF.System.Directory
|
||||||
|
GF.System.Process
|
||||||
|
GF.System.Signal
|
||||||
|
GF.Text.Clitics
|
||||||
|
GF.Text.Coding
|
||||||
|
GF.Text.Lexing
|
||||||
|
GF.Text.Pretty
|
||||||
|
GF.Text.Transliterations
|
||||||
|
LPGF
|
||||||
|
PGF
|
||||||
|
PGF.Binary
|
||||||
|
PGF.ByteCode
|
||||||
|
PGF.CId
|
||||||
|
PGF.Data
|
||||||
|
PGF.Expr
|
||||||
|
PGF.Expr
|
||||||
|
PGF.Forest
|
||||||
|
PGF.Generate
|
||||||
|
PGF.Internal
|
||||||
|
PGF.Linearize
|
||||||
|
PGF.Macros
|
||||||
|
PGF.Morphology
|
||||||
|
PGF.OldBinary
|
||||||
|
PGF.Optimize
|
||||||
|
PGF.Paraphrase
|
||||||
|
PGF.Parse
|
||||||
|
PGF.Printer
|
||||||
|
PGF.Probabilistic
|
||||||
|
PGF.Tree
|
||||||
|
PGF.TrieMap
|
||||||
|
PGF.Type
|
||||||
|
PGF.TypeCheck
|
||||||
|
PGF.Utilities
|
||||||
|
PGF.VisualizeTree
|
||||||
|
PGF2
|
||||||
|
PGF2.Expr
|
||||||
|
PGF2.Type
|
||||||
|
PGF2.FFI
|
||||||
|
Paths_gf
|
||||||
|
if flag(interrupt)
|
||||||
|
cpp-options: -DUSE_INTERRUPT
|
||||||
|
other-modules: GF.System.UseSignal
|
||||||
|
else
|
||||||
|
other-modules: GF.System.NoSignal
|
||||||
|
|
||||||
|
hs-source-dirs:
|
||||||
|
src/runtime/haskell-bind
|
||||||
|
other-modules:
|
||||||
|
PGF2
|
||||||
|
PGF2.FFI
|
||||||
|
PGF2.Expr
|
||||||
|
PGF2.Type
|
||||||
|
build-tools: hsc2hs
|
||||||
|
extra-libraries: pgf gu
|
||||||
|
c-sources: src/runtime/haskell-bind/utils.c
|
||||||
|
cc-options: -std=c99
|
||||||
|
|
||||||
|
build-depends:
|
||||||
|
ansi-terminal,
|
||||||
|
array,
|
||||||
|
base>=4.6 && <5,
|
||||||
|
bytestring,
|
||||||
|
containers,
|
||||||
|
deepseq,
|
||||||
|
directory,
|
||||||
|
filepath,
|
||||||
|
ghc-prim,
|
||||||
|
hashable,
|
||||||
|
haskeline,
|
||||||
|
json,
|
||||||
|
mtl,
|
||||||
|
parallel>=3,
|
||||||
|
pretty,
|
||||||
|
process,
|
||||||
|
random,
|
||||||
|
terminfo,
|
||||||
|
text,
|
||||||
|
time,
|
||||||
|
transformers-compat,
|
||||||
|
unix,
|
||||||
|
unordered-containers,
|
||||||
|
utf8-string
|
||||||
default-language: Haskell2010
|
default-language: Haskell2010
|
||||||
|
|||||||
18
index.html
18
index.html
@@ -214,9 +214,9 @@ least one, it may help you to get a first idea of what GF is.
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
We run the IRC channel <strong><code>#gf</code></strong> on the Libera network, where you are welcome to look for help with small questions or just start a general discussion.
|
We run the IRC channel <strong><code>#gf</code></strong> on the Freenode network, where you are welcome to look for help with small questions or just start a general discussion.
|
||||||
You can <a href="https://web.libera.chat/?channels=#gf">open a web chat</a>
|
You can <a href="https://webchat.freenode.net/?channels=gf">open a web chat</a>
|
||||||
or <a href="https://www.grammaticalframework.org/irc/?C=M;O=D">browse the channel logs</a>.
|
or <a href="/irc/">browse the channel logs</a>.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
If you have a larger question which the community may benefit from, we recommend you ask it on the <a href="http://groups.google.com/group/gf-dev">mailing list</a>.
|
If you have a larger question which the community may benefit from, we recommend you ask it on the <a href="http://groups.google.com/group/gf-dev">mailing list</a>.
|
||||||
@@ -226,19 +226,11 @@ least one, it may help you to get a first idea of what GF is.
|
|||||||
|
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<h2>News</h2>
|
<h2>News</h2>
|
||||||
<dt class="col-sm-3 text-center text-nowrap">2021-07-25</dt>
|
|
||||||
<dd class="col-sm-9">
|
|
||||||
<strong>GF 3.11 released.</strong>
|
|
||||||
<a href="download/release-3.11.html">Release notes</a>
|
|
||||||
</dd>
|
|
||||||
<dl class="row">
|
<dl class="row">
|
||||||
<dt class="col-sm-3 text-center text-nowrap">2021-05-05</dt>
|
|
||||||
<dd class="col-sm-9">
|
|
||||||
<a href="https://cloud.grammaticalframework.org/wordnet/">GF WordNet</a> now supports languages for which there are no other WordNets. New additions: Afrikaans, German, Korean, Maltese, Polish, Somali, Swahili.
|
|
||||||
</dd>
|
|
||||||
<dt class="col-sm-3 text-center text-nowrap">2021-03-01</dt>
|
<dt class="col-sm-3 text-center text-nowrap">2021-03-01</dt>
|
||||||
<dd class="col-sm-9">
|
<dd class="col-sm-9">
|
||||||
<a href="//school.grammaticalframework.org/2020/">Seventh GF Summer School</a>, in Singapore and online, 26 July – 6 August 2021.
|
<a href="//school.grammaticalframework.org/2020/">Seventh GF Summer School</a>, in Singapore and online, 26 July – 8 August 2021.
|
||||||
</dd>
|
</dd>
|
||||||
<dt class="col-sm-3 text-center text-nowrap">2020-09-29</dt>
|
<dt class="col-sm-3 text-center text-nowrap">2020-09-29</dt>
|
||||||
<dd class="col-sm-9">
|
<dd class="col-sm-9">
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
module GF.Command.Abstract(module GF.Command.Abstract,Expr,showExpr,Term) where
|
module GF.Command.Abstract(module GF.Command.Abstract,Expr,showExpr,Term) where
|
||||||
|
|
||||||
import PGF2(Expr,showExpr)
|
import PGF(CId,mkCId,Expr,showExpr)
|
||||||
import GF.Grammar.Grammar(Term)
|
import GF.Grammar.Grammar(Term)
|
||||||
|
|
||||||
type Ident = String
|
type Ident = String
|
||||||
@@ -11,7 +11,7 @@ type Pipe = [Command]
|
|||||||
|
|
||||||
data Command
|
data Command
|
||||||
= Command Ident [Option] Argument
|
= Command Ident [Option] Argument
|
||||||
deriving Show
|
deriving (Eq,Ord,Show)
|
||||||
|
|
||||||
data Option
|
data Option
|
||||||
= OOpt Ident
|
= OOpt Ident
|
||||||
@@ -29,7 +29,13 @@ data Argument
|
|||||||
| ATerm Term
|
| ATerm Term
|
||||||
| ANoArg
|
| ANoArg
|
||||||
| AMacro Ident
|
| AMacro Ident
|
||||||
deriving Show
|
deriving (Eq,Ord,Show)
|
||||||
|
|
||||||
|
valCIdOpts :: String -> CId -> [Option] -> CId
|
||||||
|
valCIdOpts flag def opts =
|
||||||
|
case [v | OFlag f (VId v) <- opts, f == flag] of
|
||||||
|
(v:_) -> mkCId v
|
||||||
|
_ -> def
|
||||||
|
|
||||||
valIntOpts :: String -> Int -> [Option] -> Int
|
valIntOpts :: String -> Int -> [Option] -> Int
|
||||||
valIntOpts flag def opts =
|
valIntOpts flag def opts =
|
||||||
@@ -43,18 +49,6 @@ valStrOpts flag def opts =
|
|||||||
v:_ -> valueString v
|
v:_ -> valueString v
|
||||||
_ -> def
|
_ -> def
|
||||||
|
|
||||||
maybeIntOpts :: String -> a -> (Int -> a) -> [Option] -> a
|
|
||||||
maybeIntOpts flag def fn opts =
|
|
||||||
case [v | OFlag f (VInt v) <- opts, f == flag] of
|
|
||||||
(v:_) -> fn v
|
|
||||||
_ -> def
|
|
||||||
|
|
||||||
maybeStrOpts :: String -> a -> (String -> a) -> [Option] -> a
|
|
||||||
maybeStrOpts flag def fn opts =
|
|
||||||
case listFlags flag opts of
|
|
||||||
v:_ -> fn (valueString v)
|
|
||||||
_ -> def
|
|
||||||
|
|
||||||
listFlags flag opts = [v | OFlag f v <- opts, f == flag]
|
listFlags flag opts = [v | OFlag f v <- opts, f == flag]
|
||||||
|
|
||||||
valueString v =
|
valueString v =
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ import GF.Command.Abstract(Option,Expr,Term)
|
|||||||
import GF.Text.Pretty(render)
|
import GF.Text.Pretty(render)
|
||||||
import GF.Grammar.Printer() -- instance Pretty Term
|
import GF.Grammar.Printer() -- instance Pretty Term
|
||||||
import GF.Grammar.Macros(string2term)
|
import GF.Grammar.Macros(string2term)
|
||||||
import PGF2(mkStr,unStr,showExpr)
|
import qualified PGF as H(showExpr)
|
||||||
|
import qualified PGF.Internal as H(Literal(LStr),Expr(ELit)) ----
|
||||||
|
|
||||||
data CommandInfo m = CommandInfo {
|
data CommandInfo m = CommandInfo {
|
||||||
exec :: [Option] -> CommandArguments -> m CommandOutput,
|
exec :: [Option] -> CommandArguments -> m CommandOutput,
|
||||||
@@ -37,19 +38,21 @@ class Monad m => TypeCheckArg m where typeCheckArg :: Expr -> m Expr
|
|||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
data CommandArguments = Exprs [(Expr,Float)] | Strings [String] | Term Term
|
data CommandArguments = Exprs [Expr] | Strings [String] | Term Term
|
||||||
|
|
||||||
newtype CommandOutput = Piped (CommandArguments,String) ---- errors, etc
|
newtype CommandOutput = Piped (CommandArguments,String) ---- errors, etc
|
||||||
|
|
||||||
-- ** Converting command output
|
-- ** Converting command output
|
||||||
fromStrings ss = Piped (Strings ss, unlines ss)
|
fromStrings ss = Piped (Strings ss, unlines ss)
|
||||||
fromExprs show_p es = Piped (Exprs es,unlines (map (\(e,p) -> (if show_p then (++) ("["++show p++"] ") else id) (showExpr [] e)) es))
|
fromExprs es = Piped (Exprs es,unlines (map (H.showExpr []) es))
|
||||||
fromString s = Piped (Strings [s], s)
|
fromString s = Piped (Strings [s], s)
|
||||||
pipeWithMessage es msg = Piped (Exprs es,msg)
|
pipeWithMessage es msg = Piped (Exprs es,msg)
|
||||||
pipeMessage msg = Piped (Exprs [],msg)
|
pipeMessage msg = Piped (Exprs [],msg)
|
||||||
pipeExprs es = Piped (Exprs es,[]) -- only used in emptyCommandInfo
|
pipeExprs es = Piped (Exprs es,[]) -- only used in emptyCommandInfo
|
||||||
void = Piped (Exprs [],"")
|
void = Piped (Exprs [],"")
|
||||||
|
|
||||||
|
stringAsExpr = H.ELit . H.LStr -- should be a pattern macro
|
||||||
|
|
||||||
-- ** Converting command input
|
-- ** Converting command input
|
||||||
|
|
||||||
toStrings args =
|
toStrings args =
|
||||||
@@ -58,23 +61,23 @@ toStrings args =
|
|||||||
Exprs es -> zipWith showAsString (True:repeat False) es
|
Exprs es -> zipWith showAsString (True:repeat False) es
|
||||||
Term t -> [render t]
|
Term t -> [render t]
|
||||||
where
|
where
|
||||||
showAsString first (e,p) =
|
showAsString first t =
|
||||||
case unStr e of
|
case t of
|
||||||
Just s -> s
|
H.ELit (H.LStr s) -> s
|
||||||
Nothing -> ['\n'|not first] ++
|
_ -> ['\n'|not first] ++
|
||||||
showExpr [] e ---newline needed in other cases than the first
|
H.showExpr [] t ---newline needed in other cases than the first
|
||||||
|
|
||||||
toExprs args =
|
toExprs args =
|
||||||
case args of
|
case args of
|
||||||
Exprs es -> map fst es
|
Exprs es -> es
|
||||||
Strings ss -> map mkStr ss
|
Strings ss -> map stringAsExpr ss
|
||||||
Term t -> [mkStr (render t)]
|
Term t -> [stringAsExpr (render t)]
|
||||||
|
|
||||||
toTerm args =
|
toTerm args =
|
||||||
case args of
|
case args of
|
||||||
Term t -> t
|
Term t -> t
|
||||||
Strings ss -> string2term $ unwords ss -- hmm
|
Strings ss -> string2term $ unwords ss -- hmm
|
||||||
Exprs es -> string2term $ unwords $ map (showExpr [] . fst) es -- hmm
|
Exprs es -> string2term $ unwords $ map (H.showExpr []) es -- hmm
|
||||||
|
|
||||||
-- ** Creating documentation
|
-- ** Creating documentation
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
{-# LANGUAGE FlexibleInstances, UndecidableInstances, CPP #-}
|
{-# LANGUAGE FlexibleInstances, UndecidableInstances #-}
|
||||||
module GF.Command.Commands (
|
module GF.Command.Commands (
|
||||||
HasPGF(..),pgfCommands,
|
PGFEnv,HasPGFEnv(..),pgf,mos,pgfEnv,pgfCommands,
|
||||||
options,flags,
|
options,flags,
|
||||||
) where
|
) where
|
||||||
import Prelude hiding (putStrLn,(<>))
|
import Prelude hiding (putStrLn,(<>)) -- GHC 8.4.1 clash with Text.PrettyPrint
|
||||||
|
|
||||||
import PGF2
|
import PGF
|
||||||
import PGF2.Internal(writePGF)
|
|
||||||
|
import PGF.Internal(lookStartCat,functionsToCat,lookValCat,restrictPGF,hasLin)
|
||||||
|
import PGF.Internal(abstract,funs,cats,Expr(EFun)) ----
|
||||||
|
import PGF.Internal(ppFun,ppCat)
|
||||||
|
import PGF.Internal(optimizePGF)
|
||||||
|
|
||||||
import GF.Compile.Export
|
import GF.Compile.Export
|
||||||
import GF.Compile.ToAPI
|
import GF.Compile.ToAPI
|
||||||
@@ -24,28 +28,28 @@ import GF.Command.TreeOperations ---- temporary place for typecheck and compute
|
|||||||
|
|
||||||
import GF.Data.Operations
|
import GF.Data.Operations
|
||||||
|
|
||||||
import Data.Char
|
import PGF.Internal (encodeFile)
|
||||||
import Data.List(intersperse,nub)
|
import Data.List(intersperse,nub)
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
import GF.Text.Pretty
|
import GF.Text.Pretty
|
||||||
import Data.List (sort)
|
import Data.List (sort)
|
||||||
import Control.Monad(mplus)
|
|
||||||
import qualified Control.Monad.Fail as Fail
|
import qualified Control.Monad.Fail as Fail
|
||||||
--import Debug.Trace
|
--import Debug.Trace
|
||||||
|
|
||||||
|
|
||||||
class (Functor m,Monad m,MonadSIO m) => HasPGF m where getPGF :: m (Maybe PGF)
|
data PGFEnv = Env {pgf::PGF,mos::Map.Map Language Morpho}
|
||||||
|
|
||||||
instance (Monad m,HasPGF m,Fail.MonadFail m) => TypeCheckArg m where
|
pgfEnv pgf = Env pgf mos
|
||||||
typeCheckArg e = do mb_pgf <- getPGF
|
where mos = Map.fromList [(la,buildMorpho pgf la) | la <- languages pgf]
|
||||||
case mb_pgf of
|
|
||||||
Just pgf -> either fail
|
|
||||||
(return . fst)
|
|
||||||
(inferExpr pgf e)
|
|
||||||
Nothing -> fail "Import a grammar before using this command"
|
|
||||||
|
|
||||||
pgfCommands :: HasPGF m => Map.Map String (CommandInfo m)
|
class (Functor m,Monad m,MonadSIO m) => HasPGFEnv m where getPGFEnv :: m PGFEnv
|
||||||
|
|
||||||
|
instance (Monad m,HasPGFEnv m,Fail.MonadFail m) => TypeCheckArg m where
|
||||||
|
typeCheckArg e = (either (fail . render . ppTcError) (return . fst)
|
||||||
|
. flip inferExpr e . pgf) =<< getPGFEnv
|
||||||
|
|
||||||
|
pgfCommands :: HasPGFEnv m => Map.Map String (CommandInfo m)
|
||||||
pgfCommands = Map.fromList [
|
pgfCommands = Map.fromList [
|
||||||
("aw", emptyCommandInfo {
|
("aw", emptyCommandInfo {
|
||||||
longname = "align_words",
|
longname = "align_words",
|
||||||
@@ -58,7 +62,7 @@ pgfCommands = Map.fromList [
|
|||||||
"by the view flag. The target format is png, unless overridden by the",
|
"by the view flag. The target format is png, unless overridden by the",
|
||||||
"flag -format. Results from multiple trees are combined to pdf with convert (ImageMagick)."
|
"flag -format. Results from multiple trees are combined to pdf with convert (ImageMagick)."
|
||||||
],
|
],
|
||||||
exec = needPGF $ \ opts arg pgf -> do
|
exec = getEnv $ \ opts arg (Env pgf mos) -> do
|
||||||
let es = toExprs arg
|
let es = toExprs arg
|
||||||
let langs = optLangs pgf opts
|
let langs = optLangs pgf opts
|
||||||
if isOpt "giza" opts
|
if isOpt "giza" opts
|
||||||
@@ -70,7 +74,7 @@ pgfCommands = Map.fromList [
|
|||||||
let grph = if null es then [] else lsrc ++ "\n--end_source--\n\n"++ltrg++"\n-end_target--\n\n"++align
|
let grph = if null es then [] else lsrc ++ "\n--end_source--\n\n"++ltrg++"\n-end_target--\n\n"++align
|
||||||
return $ fromString grph
|
return $ fromString grph
|
||||||
else do
|
else do
|
||||||
let grphs = map (graphvizWordAlignment langs graphvizDefaults) es
|
let grphs = map (graphvizAlignment pgf langs) es
|
||||||
if isFlag "view" opts || isFlag "format" opts
|
if isFlag "view" opts || isFlag "format" opts
|
||||||
then do
|
then do
|
||||||
let view = optViewGraph opts
|
let view = optViewGraph opts
|
||||||
@@ -92,7 +96,6 @@ pgfCommands = Map.fromList [
|
|||||||
("view", "program to open the resulting file")
|
("view", "program to open the resulting file")
|
||||||
]
|
]
|
||||||
}),
|
}),
|
||||||
|
|
||||||
("ca", emptyCommandInfo {
|
("ca", emptyCommandInfo {
|
||||||
longname = "clitic_analyse",
|
longname = "clitic_analyse",
|
||||||
synopsis = "print the analyses of all words into stems and clitics",
|
synopsis = "print the analyses of all words into stems and clitics",
|
||||||
@@ -103,17 +106,16 @@ pgfCommands = Map.fromList [
|
|||||||
"by the flag '-clitics'. The list of stems is given as the list of words",
|
"by the flag '-clitics'. The list of stems is given as the list of words",
|
||||||
"of the language given by the '-lang' flag."
|
"of the language given by the '-lang' flag."
|
||||||
],
|
],
|
||||||
exec = needPGF $ \opts ts pgf -> do
|
exec = getEnv $ \opts ts env -> case opts of
|
||||||
concr <- optLang pgf opts
|
_ | isOpt "raw" opts ->
|
||||||
case opts of
|
return . fromString .
|
||||||
_ | isOpt "raw" opts ->
|
unlines . map (unwords . map (concat . intersperse "+")) .
|
||||||
return . fromString .
|
map (getClitics (isInMorpho (optMorpho env opts)) (optClitics opts)) .
|
||||||
unlines . map (unwords . map (concat . intersperse "+")) .
|
concatMap words $ toStrings ts
|
||||||
map (getClitics (not . null . lookupMorpho concr) (optClitics opts)) .
|
_ ->
|
||||||
concatMap words $ toStrings ts
|
return . fromStrings .
|
||||||
_ -> return . fromStrings .
|
getCliticsText (isInMorpho (optMorpho env opts)) (optClitics opts) .
|
||||||
getCliticsText (not . null . lookupMorpho concr) (optClitics opts) .
|
concatMap words $ toStrings ts,
|
||||||
concatMap words $ toStrings ts,
|
|
||||||
flags = [
|
flags = [
|
||||||
("clitics","the list of possible clitics (comma-separated, no spaces)"),
|
("clitics","the list of possible clitics (comma-separated, no spaces)"),
|
||||||
("lang", "the language of analysis")
|
("lang", "the language of analysis")
|
||||||
@@ -145,19 +147,19 @@ pgfCommands = Map.fromList [
|
|||||||
],
|
],
|
||||||
flags = [
|
flags = [
|
||||||
("file","the file to be converted (suffix .gfe must be given)"),
|
("file","the file to be converted (suffix .gfe must be given)"),
|
||||||
("lang","the language in which to parse")
|
("lang","the language in which to parse"),
|
||||||
|
("probs","file with probabilities to rank the parses")
|
||||||
],
|
],
|
||||||
exec = needPGF $ \opts _ pgf -> do
|
exec = getEnv $ \ opts _ env@(Env pgf mos) -> do
|
||||||
let file = optFile opts
|
let file = optFile opts
|
||||||
|
pgf <- optProbs opts pgf
|
||||||
let printer = if (isOpt "api" opts) then exprToAPI else (showExpr [])
|
let printer = if (isOpt "api" opts) then exprToAPI else (showExpr [])
|
||||||
concr <- optLang pgf opts
|
let conf = configureExBased pgf (optMorpho env opts) (optLang pgf opts) printer
|
||||||
let conf = configureExBased pgf concr printer
|
|
||||||
(file',ws) <- restricted $ parseExamplesInGrammar conf file
|
(file',ws) <- restricted $ parseExamplesInGrammar conf file
|
||||||
if null ws then return () else putStrLn ("unknown words: " ++ unwords ws)
|
if null ws then return () else putStrLn ("unknown words: " ++ unwords ws)
|
||||||
return (fromString ("wrote " ++ file')),
|
return (fromString ("wrote " ++ file')),
|
||||||
needsTypeCheck = False
|
needsTypeCheck = False
|
||||||
}),
|
}),
|
||||||
|
|
||||||
("gr", emptyCommandInfo {
|
("gr", emptyCommandInfo {
|
||||||
longname = "generate_random",
|
longname = "generate_random",
|
||||||
synopsis = "generate random trees in the current abstract syntax",
|
synopsis = "generate random trees in the current abstract syntax",
|
||||||
@@ -172,53 +174,54 @@ pgfCommands = Map.fromList [
|
|||||||
explanation = unlines [
|
explanation = unlines [
|
||||||
"Generates a list of random trees, by default one tree.",
|
"Generates a list of random trees, by default one tree.",
|
||||||
"If a tree argument is given, the command completes the Tree with values to",
|
"If a tree argument is given, the command completes the Tree with values to",
|
||||||
"all metavariables in the tree. The generation can be biased by probabilities",
|
"all metavariables in the tree. The generation can be biased by probabilities,",
|
||||||
"if the grammar was compiled with option -probs"
|
"given in a file in the -probs flag."
|
||||||
],
|
|
||||||
options = [
|
|
||||||
("show_probs", "show the probability of each result")
|
|
||||||
],
|
],
|
||||||
flags = [
|
flags = [
|
||||||
("cat","generation category"),
|
("cat","generation category"),
|
||||||
("lang","uses only functions that have linearizations in all these languages"),
|
("lang","uses only functions that have linearizations in all these languages"),
|
||||||
("number","number of trees generated")
|
("number","number of trees generated"),
|
||||||
|
("depth","the maximum generation depth"),
|
||||||
|
("probs", "file with biased probabilities (format 'f 0.4' one by line)")
|
||||||
],
|
],
|
||||||
exec = needPGF $ \opts arg pgf -> do
|
exec = getEnv $ \ opts arg (Env pgf mos) -> do
|
||||||
|
pgf <- optProbs opts (optRestricted opts pgf)
|
||||||
gen <- newStdGen
|
gen <- newStdGen
|
||||||
|
let dp = valIntOpts "depth" 4 opts
|
||||||
let ts = case mexp (toExprs arg) of
|
let ts = case mexp (toExprs arg) of
|
||||||
Just ex -> generateRandomFrom gen pgf ex
|
Just ex -> generateRandomFromDepth gen pgf ex (Just dp)
|
||||||
Nothing -> generateRandom gen pgf (optType pgf opts)
|
Nothing -> generateRandomDepth gen pgf (optType pgf opts) (Just dp)
|
||||||
returnFromExprs (isOpt "show_probs" opts) $ take (optNum opts) ts
|
returnFromExprs $ take (optNum opts) ts
|
||||||
}),
|
}),
|
||||||
|
|
||||||
("gt", emptyCommandInfo {
|
("gt", emptyCommandInfo {
|
||||||
longname = "generate_trees",
|
longname = "generate_trees",
|
||||||
synopsis = "generates a list of trees, by default exhaustive",
|
synopsis = "generates a list of trees, by default exhaustive",
|
||||||
explanation = unlines [
|
explanation = unlines [
|
||||||
"Generates all trees of a given category.",
|
"Generates all trees of a given category. By default, ",
|
||||||
|
"the depth is limited to 4, but this can be changed by a flag.",
|
||||||
"If a Tree argument is given, the command completes the Tree with values",
|
"If a Tree argument is given, the command completes the Tree with values",
|
||||||
"to all metavariables in the tree."
|
"to all metavariables in the tree."
|
||||||
],
|
],
|
||||||
options = [
|
|
||||||
("show_probs", "show the probability of each result")
|
|
||||||
],
|
|
||||||
flags = [
|
flags = [
|
||||||
("cat","the generation category"),
|
("cat","the generation category"),
|
||||||
|
("depth","the maximum generation depth"),
|
||||||
("lang","excludes functions that have no linearization in this language"),
|
("lang","excludes functions that have no linearization in this language"),
|
||||||
("number","the number of trees generated")
|
("number","the number of trees generated")
|
||||||
],
|
],
|
||||||
examples = [
|
examples = [
|
||||||
mkEx "gt -- all trees in the startcat",
|
mkEx "gt -- all trees in the startcat, to depth 4",
|
||||||
mkEx "gt -cat=NP -number=16 -- 16 trees in the category NP",
|
mkEx "gt -cat=NP -number=16 -- 16 trees in the category NP",
|
||||||
|
mkEx "gt -cat=NP -depth=2 -- trees in the category NP to depth 2",
|
||||||
mkEx "gt (AdjCN ? (UseN ?)) -- trees of form (AdjCN ? (UseN ?))"
|
mkEx "gt (AdjCN ? (UseN ?)) -- trees of form (AdjCN ? (UseN ?))"
|
||||||
],
|
],
|
||||||
exec = needPGF $ \opts arg pgf -> do
|
exec = getEnv $ \ opts arg (Env pgf mos) -> do
|
||||||
let es = case mexp (toExprs arg) of
|
let pgfr = optRestricted opts pgf
|
||||||
Just ex -> generateAllFrom pgf ex
|
let dp = valIntOpts "depth" 4 opts
|
||||||
Nothing -> generateAll pgf (optType pgf opts)
|
let ts = case mexp (toExprs arg) of
|
||||||
returnFromExprs (isOpt "show_probs" opts) $ takeOptNum opts es
|
Just ex -> generateFromDepth pgfr ex (Just dp)
|
||||||
|
Nothing -> generateAllDepth pgfr (optType pgf opts) (Just dp)
|
||||||
|
returnFromExprs $ take (optNumInf opts) ts
|
||||||
}),
|
}),
|
||||||
|
|
||||||
("i", emptyCommandInfo {
|
("i", emptyCommandInfo {
|
||||||
longname = "import",
|
longname = "import",
|
||||||
synopsis = "import a grammar from source code or compiled .pgf file",
|
synopsis = "import a grammar from source code or compiled .pgf file",
|
||||||
@@ -239,28 +242,33 @@ pgfCommands = Map.fromList [
|
|||||||
("probs","file with biased probabilities for generation")
|
("probs","file with biased probabilities for generation")
|
||||||
],
|
],
|
||||||
options = [
|
options = [
|
||||||
|
-- ["gfo", "src", "no-cpu", "cpu", "quiet", "verbose"]
|
||||||
("retain","retain operations (used for cc command)"),
|
("retain","retain operations (used for cc command)"),
|
||||||
("src", "force compilation from source"),
|
("src", "force compilation from source"),
|
||||||
("v", "be verbose - show intermediate status information")
|
("v", "be verbose - show intermediate status information")
|
||||||
],
|
],
|
||||||
needsTypeCheck = False
|
needsTypeCheck = False
|
||||||
}),
|
}),
|
||||||
|
|
||||||
("l", emptyCommandInfo {
|
("l", emptyCommandInfo {
|
||||||
longname = "linearize",
|
longname = "linearize",
|
||||||
synopsis = "convert an abstract syntax expression to string",
|
synopsis = "convert an abstract syntax expression to string",
|
||||||
explanation = unlines [
|
explanation = unlines [
|
||||||
"Shows the linearization of a tree by the grammars in scope.",
|
"Shows the linearization of a Tree by the grammars in scope.",
|
||||||
"The -lang flag can be used to restrict this to fewer languages.",
|
"The -lang flag can be used to restrict this to fewer languages.",
|
||||||
"A sequence of string operations (see command ps) can be given",
|
"A sequence of string operations (see command ps) can be given",
|
||||||
"as options, and works then like a pipe to the ps command, except",
|
"as options, and works then like a pipe to the ps command, except",
|
||||||
"that it only affect the strings, not e.g. the table labels."
|
"that it only affect the strings, not e.g. the table labels.",
|
||||||
|
"These can be given separately to each language with the unlexer flag",
|
||||||
|
"whose results are prepended to the other lexer flags. The value of the",
|
||||||
|
"unlexer flag is a space-separated list of comma-separated string operation",
|
||||||
|
"sequences; see example."
|
||||||
],
|
],
|
||||||
examples = [
|
examples = [
|
||||||
mkEx "l -lang=LangSwe,LangNor no_Utt -- linearize tree to LangSwe and LangNor",
|
mkEx "l -lang=LangSwe,LangNor no_Utt -- linearize tree to LangSwe and LangNor",
|
||||||
mkEx "gr -lang=LangHin -cat=Cl | l -table -to_devanagari -- hindi table"
|
mkEx "gr -lang=LangHin -cat=Cl | l -table -to_devanagari -- hindi table",
|
||||||
|
mkEx "l -unlexer=\"LangAra=to_arabic LangHin=to_devanagari\" -- different unlexers"
|
||||||
],
|
],
|
||||||
exec = needPGF $ \ opts ts pgf -> return . fromStrings . optLins pgf opts $ toExprs ts,
|
exec = getEnv $ \ opts ts (Env pgf mos) -> return . fromStrings . optLins pgf opts $ toExprs ts,
|
||||||
options = [
|
options = [
|
||||||
("all", "show all forms and variants, one by line (cf. l -list)"),
|
("all", "show all forms and variants, one by line (cf. l -list)"),
|
||||||
("bracket","show tree structure with brackets and paths to nodes"),
|
("bracket","show tree structure with brackets and paths to nodes"),
|
||||||
@@ -268,13 +276,33 @@ pgfCommands = Map.fromList [
|
|||||||
("list","show all forms and variants, comma-separated on one line (cf. l -all)"),
|
("list","show all forms and variants, comma-separated on one line (cf. l -all)"),
|
||||||
("multi","linearize to all languages (default)"),
|
("multi","linearize to all languages (default)"),
|
||||||
("table","show all forms labelled by parameters"),
|
("table","show all forms labelled by parameters"),
|
||||||
|
("tabtreebank","show the tree and its linearizations on a tab-separated line"),
|
||||||
|
("treebank","show the tree and tag linearizations with language names")
|
||||||
|
] ++ stringOpOptions,
|
||||||
|
flags = [
|
||||||
|
("lang","the languages of linearization (comma-separated, no spaces)"),
|
||||||
|
("unlexer","set unlexers separately to each language (space-separated)")
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
("lc", emptyCommandInfo {
|
||||||
|
longname = "linearize_chunks",
|
||||||
|
synopsis = "linearize a tree that has metavariables in maximal chunks without them",
|
||||||
|
explanation = unlines [
|
||||||
|
"A hopefully temporary command, intended to work around the type checker that fails",
|
||||||
|
"trees where a function node is a metavariable."
|
||||||
|
],
|
||||||
|
examples = [
|
||||||
|
mkEx "l -lang=LangSwe,LangNor -chunks ? a b (? c d)"
|
||||||
|
],
|
||||||
|
exec = getEnv $ \ opts ts (Env pgf mos) -> return . fromStrings $ optLins pgf (opts ++ [OOpt "chunks"]) (toExprs ts),
|
||||||
|
options = [
|
||||||
("treebank","show the tree and tag linearizations with language names")
|
("treebank","show the tree and tag linearizations with language names")
|
||||||
] ++ stringOpOptions,
|
] ++ stringOpOptions,
|
||||||
flags = [
|
flags = [
|
||||||
("lang","the languages of linearization (comma-separated, no spaces)")
|
("lang","the languages of linearization (comma-separated, no spaces)")
|
||||||
]
|
],
|
||||||
|
needsTypeCheck = False
|
||||||
}),
|
}),
|
||||||
|
|
||||||
("ma", emptyCommandInfo {
|
("ma", emptyCommandInfo {
|
||||||
longname = "morpho_analyse",
|
longname = "morpho_analyse",
|
||||||
synopsis = "print the morphological analyses of all words in the string",
|
synopsis = "print the morphological analyses of all words in the string",
|
||||||
@@ -282,20 +310,18 @@ pgfCommands = Map.fromList [
|
|||||||
"Prints all the analyses of space-separated words in the input string,",
|
"Prints all the analyses of space-separated words in the input string,",
|
||||||
"using the morphological analyser of the actual grammar (see command pg)"
|
"using the morphological analyser of the actual grammar (see command pg)"
|
||||||
],
|
],
|
||||||
exec = needPGF $ \opts ts pgf -> do
|
exec = getEnv $ \opts ts env -> case opts of
|
||||||
concr <- optLang pgf opts
|
_ | isOpt "missing" opts ->
|
||||||
case opts of
|
return . fromString . unwords .
|
||||||
_ | isOpt "missing" opts ->
|
morphoMissing (optMorpho env opts) .
|
||||||
return . fromString . unwords .
|
concatMap words $ toStrings ts
|
||||||
morphoMissing concr .
|
_ | isOpt "known" opts ->
|
||||||
concatMap words $ toStrings ts
|
return . fromString . unwords .
|
||||||
_ | isOpt "known" opts ->
|
morphoKnown (optMorpho env opts) .
|
||||||
return . fromString . unwords .
|
concatMap words $ toStrings ts
|
||||||
morphoKnown concr .
|
_ -> return . fromString . unlines .
|
||||||
concatMap words $ toStrings ts
|
map prMorphoAnalysis . concatMap (morphos env opts) .
|
||||||
_ -> return . fromString . unlines .
|
concatMap words $ toStrings ts,
|
||||||
map prMorphoAnalysis . concatMap (morphos pgf opts) .
|
|
||||||
concatMap words $ toStrings ts,
|
|
||||||
flags = [
|
flags = [
|
||||||
("lang","the languages of analysis (comma-separated, no spaces)")
|
("lang","the languages of analysis (comma-separated, no spaces)")
|
||||||
],
|
],
|
||||||
@@ -309,16 +335,18 @@ pgfCommands = Map.fromList [
|
|||||||
longname = "morpho_quiz",
|
longname = "morpho_quiz",
|
||||||
synopsis = "start a morphology quiz",
|
synopsis = "start a morphology quiz",
|
||||||
syntax = "mq (-cat=CAT)? (-probs=FILE)? TREE?",
|
syntax = "mq (-cat=CAT)? (-probs=FILE)? TREE?",
|
||||||
exec = needPGF $ \ opts arg pgf -> do
|
exec = getEnv $ \ opts arg (Env pgf mos) -> do
|
||||||
lang <- optLang pgf opts
|
let lang = optLang pgf opts
|
||||||
let typ = optType pgf opts
|
let typ = optType pgf opts
|
||||||
|
pgf <- optProbs opts pgf
|
||||||
let mt = mexp (toExprs arg)
|
let mt = mexp (toExprs arg)
|
||||||
restricted $ morphologyQuiz mt pgf lang typ
|
restricted $ morphologyQuiz mt pgf lang typ
|
||||||
return void,
|
return void,
|
||||||
flags = [
|
flags = [
|
||||||
("lang","language of the quiz"),
|
("lang","language of the quiz"),
|
||||||
("cat","category of the quiz"),
|
("cat","category of the quiz"),
|
||||||
("number","maximum number of questions")
|
("number","maximum number of questions"),
|
||||||
|
("probs","file with biased probabilities for generation")
|
||||||
]
|
]
|
||||||
}),
|
}),
|
||||||
|
|
||||||
@@ -329,25 +357,24 @@ pgfCommands = Map.fromList [
|
|||||||
"Shows all trees returned by parsing a string in the grammars in scope.",
|
"Shows all trees returned by parsing a string in the grammars in scope.",
|
||||||
"The -lang flag can be used to restrict this to fewer languages.",
|
"The -lang flag can be used to restrict this to fewer languages.",
|
||||||
"The default start category can be overridden by the -cat flag.",
|
"The default start category can be overridden by the -cat flag.",
|
||||||
"See also the ps command for lexing and character encoding."
|
"See also the ps command for lexing and character encoding.",
|
||||||
],
|
"",
|
||||||
exec = needPGF $ \opts ts pgf ->
|
"The -openclass flag is experimental and allows some robustness in ",
|
||||||
return $
|
"the parser. For example if -openclass=\"A,N,V\" is given, the parser",
|
||||||
foldr (joinPiped . fromParse1 opts) void
|
"will accept unknown adjectives, nouns and verbs with the resource grammar."
|
||||||
(concat [
|
|
||||||
[(s,parse concr (optType pgf opts) s) |
|
|
||||||
concr <- optLangs pgf opts]
|
|
||||||
| s <- toStrings ts]),
|
|
||||||
options = [
|
|
||||||
("show_probs", "show the probability of each result")
|
|
||||||
],
|
],
|
||||||
|
exec = getEnv $ \ opts ts (Env pgf mos) ->
|
||||||
|
return $ fromParse opts (concat [map ((,) s) (par pgf opts s) | s <- toStrings ts]),
|
||||||
flags = [
|
flags = [
|
||||||
("cat","target category of parsing"),
|
("cat","target category of parsing"),
|
||||||
("lang","the languages of parsing (comma-separated, no spaces)"),
|
("lang","the languages of parsing (comma-separated, no spaces)"),
|
||||||
("number","limit the results to the top N trees")
|
("openclass","list of open-class categories for robust parsing"),
|
||||||
|
("depth","maximal depth for proof search if the abstract syntax tree has meta variables")
|
||||||
|
],
|
||||||
|
options = [
|
||||||
|
("bracket","prints the bracketed string from the parser")
|
||||||
]
|
]
|
||||||
}),
|
}),
|
||||||
|
|
||||||
("pg", emptyCommandInfo { -----
|
("pg", emptyCommandInfo { -----
|
||||||
longname = "print_grammar",
|
longname = "print_grammar",
|
||||||
synopsis = "print the actual grammar with the given printer",
|
synopsis = "print the actual grammar with the given printer",
|
||||||
@@ -367,8 +394,9 @@ pgfCommands = Map.fromList [
|
|||||||
" " ++ opt ++ "\t\t" ++ expl |
|
" " ++ opt ++ "\t\t" ++ expl |
|
||||||
((opt,_),expl) <- outputFormatsExpl, take 1 expl /= "*"
|
((opt,_),expl) <- outputFormatsExpl, take 1 expl /= "*"
|
||||||
]),
|
]),
|
||||||
exec = needPGF $ \opts _ pgf -> prGrammar pgf opts,
|
exec = getEnv $ \opts _ env -> prGrammar env opts,
|
||||||
flags = [
|
flags = [
|
||||||
|
--"cat",
|
||||||
("file", "set the file name when printing with -pgf option"),
|
("file", "set the file name when printing with -pgf option"),
|
||||||
("lang", "select languages for the some options (default all languages)"),
|
("lang", "select languages for the some options (default all languages)"),
|
||||||
("printer","select the printing format (see flag values above)")
|
("printer","select the printing format (see flag values above)")
|
||||||
@@ -388,7 +416,6 @@ pgfCommands = Map.fromList [
|
|||||||
mkEx ("pg -funs | ? grep \" S ;\" -- show functions with value cat S")
|
mkEx ("pg -funs | ? grep \" S ;\" -- show functions with value cat S")
|
||||||
]
|
]
|
||||||
}),
|
}),
|
||||||
|
|
||||||
("pt", emptyCommandInfo {
|
("pt", emptyCommandInfo {
|
||||||
longname = "put_tree",
|
longname = "put_tree",
|
||||||
syntax = "pt OPT? TREE",
|
syntax = "pt OPT? TREE",
|
||||||
@@ -402,12 +429,11 @@ pgfCommands = Map.fromList [
|
|||||||
examples = [
|
examples = [
|
||||||
mkEx "pt -compute (plus one two) -- compute value"
|
mkEx "pt -compute (plus one two) -- compute value"
|
||||||
],
|
],
|
||||||
exec = needPGF $ \opts arg pgf ->
|
exec = getEnv $ \ opts arg (Env pgf mos) ->
|
||||||
returnFromExprs False . takeOptNum opts . map (flip (,) 0) . treeOps pgf opts $ toExprs arg,
|
returnFromExprs . takeOptNum opts . treeOps pgf opts $ toExprs arg,
|
||||||
options = treeOpOptions undefined{-pgf-},
|
options = treeOpOptions undefined{-pgf-},
|
||||||
flags = [("number","take at most this many trees")] ++ treeOpFlags undefined{-pgf-}
|
flags = [("number","take at most this many trees")] ++ treeOpFlags undefined{-pgf-}
|
||||||
}),
|
}),
|
||||||
|
|
||||||
("rf", emptyCommandInfo {
|
("rf", emptyCommandInfo {
|
||||||
longname = "read_file",
|
longname = "read_file",
|
||||||
synopsis = "read string or tree input from a file",
|
synopsis = "read string or tree input from a file",
|
||||||
@@ -420,9 +446,10 @@ pgfCommands = Map.fromList [
|
|||||||
],
|
],
|
||||||
options = [
|
options = [
|
||||||
("lines","return the list of lines, instead of the singleton of all contents"),
|
("lines","return the list of lines, instead of the singleton of all contents"),
|
||||||
|
("paragraphs","return the list of paragraphs, as separated by empty lines"),
|
||||||
("tree","convert strings into trees")
|
("tree","convert strings into trees")
|
||||||
],
|
],
|
||||||
exec = needPGF $ \ opts _ pgf -> do
|
exec = getEnv $ \ opts _ (Env pgf mos) -> do
|
||||||
let file = valStrOpts "file" "_gftmp" opts
|
let file = valStrOpts "file" "_gftmp" opts
|
||||||
let exprs [] = ([],empty)
|
let exprs [] = ([],empty)
|
||||||
exprs ((n,s):ls) | null s
|
exprs ((n,s):ls) | null s
|
||||||
@@ -431,12 +458,12 @@ pgfCommands = Map.fromList [
|
|||||||
Just e -> let (es,err) = exprs ls
|
Just e -> let (es,err) = exprs ls
|
||||||
in case inferExpr pgf e of
|
in case inferExpr pgf e of
|
||||||
Right (e,t) -> (e:es,err)
|
Right (e,t) -> (e:es,err)
|
||||||
Left err -> (es,"on line" <+> n <> ':' $$ nest 2 err $$ err)
|
Left tcerr -> (es,"on line" <+> n <> ':' $$ nest 2 (ppTcError tcerr) $$ err)
|
||||||
Nothing -> let (es,err) = exprs ls
|
Nothing -> let (es,err) = exprs ls
|
||||||
in (es,"on line" <+> n <> ':' <+> "parse error" $$ err)
|
in (es,"on line" <+> n <> ':' <+> "parse error" $$ err)
|
||||||
returnFromLines ls = case exprs ls of
|
returnFromLines ls = case exprs ls of
|
||||||
(es, err) | null es -> return $ pipeMessage $ render (err $$ "no trees found")
|
(es, err) | null es -> return $ pipeMessage $ render (err $$ "no trees found")
|
||||||
| otherwise -> return $ pipeWithMessage (map (flip (,) 0) es) (render err)
|
| otherwise -> return $ pipeWithMessage es (render err)
|
||||||
|
|
||||||
s <- restricted $ readFile file
|
s <- restricted $ readFile file
|
||||||
case opts of
|
case opts of
|
||||||
@@ -445,26 +472,56 @@ pgfCommands = Map.fromList [
|
|||||||
_ | isOpt "tree" opts ->
|
_ | isOpt "tree" opts ->
|
||||||
returnFromLines [(1::Int,s)]
|
returnFromLines [(1::Int,s)]
|
||||||
_ | isOpt "lines" opts -> return (fromStrings $ lines s)
|
_ | isOpt "lines" opts -> return (fromStrings $ lines s)
|
||||||
|
_ | isOpt "paragraphs" opts -> return (fromStrings $ toParagraphs $ lines s)
|
||||||
_ -> return (fromString s),
|
_ -> return (fromString s),
|
||||||
flags = [("file","the input file name")]
|
flags = [("file","the input file name")]
|
||||||
}),
|
}),
|
||||||
|
("rt", emptyCommandInfo {
|
||||||
|
longname = "rank_trees",
|
||||||
|
synopsis = "show trees in an order of decreasing probability",
|
||||||
|
explanation = unlines [
|
||||||
|
"Order trees from the most to the least probable, using either",
|
||||||
|
"even distribution in each category (default) or biased as specified",
|
||||||
|
"by the file given by flag -probs=FILE, where each line has the form",
|
||||||
|
"'function probability', e.g. 'youPol_Pron 0.01'."
|
||||||
|
],
|
||||||
|
exec = getEnv $ \ opts arg (Env pgf mos) -> do
|
||||||
|
let ts = toExprs arg
|
||||||
|
pgf <- optProbs opts pgf
|
||||||
|
let tds = rankTreesByProbs pgf ts
|
||||||
|
if isOpt "v" opts
|
||||||
|
then putStrLn $
|
||||||
|
unlines [showExpr [] t ++ "\t--" ++ show d | (t,d) <- tds]
|
||||||
|
else return ()
|
||||||
|
returnFromExprs $ map fst tds,
|
||||||
|
flags = [
|
||||||
|
("probs","probabilities from this file (format 'f 0.6' per line)")
|
||||||
|
],
|
||||||
|
options = [
|
||||||
|
("v","show all trees with their probability scores")
|
||||||
|
],
|
||||||
|
examples = [
|
||||||
|
mkEx "p \"you are here\" | rt -probs=probs | pt -number=1 -- most probable result"
|
||||||
|
]
|
||||||
|
}),
|
||||||
("tq", emptyCommandInfo {
|
("tq", emptyCommandInfo {
|
||||||
longname = "translation_quiz",
|
longname = "translation_quiz",
|
||||||
syntax = "tq -from=LANG -to=LANG (-cat=CAT)? (-probs=FILE)? TREE?",
|
syntax = "tq -from=LANG -to=LANG (-cat=CAT)? (-probs=FILE)? TREE?",
|
||||||
synopsis = "start a translation quiz",
|
synopsis = "start a translation quiz",
|
||||||
exec = needPGF $ \ opts arg pgf -> do
|
exec = getEnv $ \ opts arg (Env pgf mos) -> do
|
||||||
from <- optLangFlag "from" pgf opts
|
let from = optLangFlag "from" pgf opts
|
||||||
to <- optLangFlag "to" pgf opts
|
let to = optLangFlag "to" pgf opts
|
||||||
let typ = optType pgf opts
|
let typ = optType pgf opts
|
||||||
let mt = mexp (toExprs arg)
|
let mt = mexp (toExprs arg)
|
||||||
|
pgf <- optProbs opts pgf
|
||||||
restricted $ translationQuiz mt pgf from to typ
|
restricted $ translationQuiz mt pgf from to typ
|
||||||
return void,
|
return void,
|
||||||
flags = [
|
flags = [
|
||||||
("from","translate from this language"),
|
("from","translate from this language"),
|
||||||
("to","translate to this language"),
|
("to","translate to this language"),
|
||||||
("cat","translate in this category"),
|
("cat","translate in this category"),
|
||||||
("number","the maximum number of questions")
|
("number","the maximum number of questions"),
|
||||||
|
("probs","file with biased probabilities for generation")
|
||||||
],
|
],
|
||||||
examples = [
|
examples = [
|
||||||
mkEx ("tq -from=Eng -to=Swe -- any trees in startcat"),
|
mkEx ("tq -from=Eng -to=Swe -- any trees in startcat"),
|
||||||
@@ -472,6 +529,7 @@ pgfCommands = Map.fromList [
|
|||||||
]
|
]
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
|
||||||
("vd", emptyCommandInfo {
|
("vd", emptyCommandInfo {
|
||||||
longname = "visualize_dependency",
|
longname = "visualize_dependency",
|
||||||
synopsis = "show word dependency tree graphically",
|
synopsis = "show word dependency tree graphically",
|
||||||
@@ -489,7 +547,7 @@ pgfCommands = Map.fromList [
|
|||||||
"flag -format. Results from multiple trees are combined to pdf with convert (ImageMagick).",
|
"flag -format. Results from multiple trees are combined to pdf with convert (ImageMagick).",
|
||||||
"See also 'vp -showdep' for another visualization of dependencies."
|
"See also 'vp -showdep' for another visualization of dependencies."
|
||||||
],
|
],
|
||||||
exec = needPGF $ \ opts arg pgf -> do
|
exec = getEnv $ \ opts arg (Env pgf mos) -> do
|
||||||
let absname = abstractName pgf
|
let absname = abstractName pgf
|
||||||
let es = toExprs arg
|
let es = toExprs arg
|
||||||
let debug = isOpt "v" opts
|
let debug = isOpt "v" opts
|
||||||
@@ -502,8 +560,8 @@ pgfCommands = Map.fromList [
|
|||||||
mclab <- case cnclabels of
|
mclab <- case cnclabels of
|
||||||
"" -> return Nothing
|
"" -> return Nothing
|
||||||
_ -> (Just . getCncDepLabels) `fmap` restricted (readFile cnclabels)
|
_ -> (Just . getCncDepLabels) `fmap` restricted (readFile cnclabels)
|
||||||
concr <- optLang pgf opts
|
let lang = optLang pgf opts
|
||||||
let grphs = map (graphvizDependencyTree outp debug mlab mclab concr) es
|
let grphs = map (graphvizDependencyTree outp debug mlab mclab pgf lang) es
|
||||||
if isOpt "conll2latex" opts
|
if isOpt "conll2latex" opts
|
||||||
then return $ fromString $ conlls2latexDoc $ stanzas $ unlines $ toStrings arg
|
then return $ fromString $ conlls2latexDoc $ stanzas $ unlines $ toStrings arg
|
||||||
else if isFlag "view" opts && valStrOpts "output" "" opts == "latex"
|
else if isFlag "view" opts && valStrOpts "output" "" opts == "latex"
|
||||||
@@ -538,6 +596,7 @@ pgfCommands = Map.fromList [
|
|||||||
]
|
]
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
|
||||||
("vp", emptyCommandInfo {
|
("vp", emptyCommandInfo {
|
||||||
longname = "visualize_parse",
|
longname = "visualize_parse",
|
||||||
synopsis = "show parse tree graphically",
|
synopsis = "show parse tree graphically",
|
||||||
@@ -549,8 +608,9 @@ pgfCommands = Map.fromList [
|
|||||||
"by the view flag. The target format is png, unless overridden by the",
|
"by the view flag. The target format is png, unless overridden by the",
|
||||||
"flag -format. Results from multiple trees are combined to pdf with convert (ImageMagick)."
|
"flag -format. Results from multiple trees are combined to pdf with convert (ImageMagick)."
|
||||||
],
|
],
|
||||||
exec = needPGF $ \opts arg pgf -> do
|
exec = getEnv $ \ opts arg (Env pgf mos) -> do
|
||||||
let es = toExprs arg
|
let es = toExprs arg
|
||||||
|
let lang = optLang pgf opts
|
||||||
let gvOptions = GraphvizOptions {noLeaves = isOpt "noleaves" opts && not (isOpt "showleaves" opts),
|
let gvOptions = GraphvizOptions {noLeaves = isOpt "noleaves" opts && not (isOpt "showleaves" opts),
|
||||||
noFun = isOpt "nofun" opts || not (isOpt "showfun" opts),
|
noFun = isOpt "nofun" opts || not (isOpt "showfun" opts),
|
||||||
noCat = isOpt "nocat" opts && not (isOpt "showcat" opts),
|
noCat = isOpt "nocat" opts && not (isOpt "showcat" opts),
|
||||||
@@ -563,11 +623,10 @@ pgfCommands = Map.fromList [
|
|||||||
leafEdgeStyle = valStrOpts "leafedgestyle" "dashed" opts
|
leafEdgeStyle = valStrOpts "leafedgestyle" "dashed" opts
|
||||||
}
|
}
|
||||||
let depfile = valStrOpts "file" "" opts
|
let depfile = valStrOpts "file" "" opts
|
||||||
concr <- optLang pgf opts
|
|
||||||
mlab <- case depfile of
|
mlab <- case depfile of
|
||||||
"" -> return Nothing
|
"" -> return Nothing
|
||||||
_ -> (Just . getDepLabels) `fmap` restricted (readFile depfile)
|
_ -> (Just . getDepLabels) `fmap` restricted (readFile depfile)
|
||||||
let grphs = map (graphvizDependencyTree "dot" False mlab Nothing concr) es
|
let grphs = map (graphvizParseTreeDep mlab pgf lang gvOptions) es
|
||||||
if isFlag "view" opts || isFlag "format" opts
|
if isFlag "view" opts || isFlag "format" opts
|
||||||
then do
|
then do
|
||||||
let view = optViewGraph opts
|
let view = optViewGraph opts
|
||||||
@@ -602,6 +661,7 @@ pgfCommands = Map.fromList [
|
|||||||
]
|
]
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
|
||||||
("vt", emptyCommandInfo {
|
("vt", emptyCommandInfo {
|
||||||
longname = "visualize_tree",
|
longname = "visualize_tree",
|
||||||
synopsis = "show a set of trees graphically",
|
synopsis = "show a set of trees graphically",
|
||||||
@@ -614,7 +674,7 @@ pgfCommands = Map.fromList [
|
|||||||
"flag -format. Results from multiple trees are combined to pdf with convert (ImageMagick).",
|
"flag -format. Results from multiple trees are combined to pdf with convert (ImageMagick).",
|
||||||
"With option -mk, use for showing library style function names of form 'mkC'."
|
"With option -mk, use for showing library style function names of form 'mkC'."
|
||||||
],
|
],
|
||||||
exec = needPGF $ \opts arg pgf ->
|
exec = getEnv $ \ opts arg (Env pgf mos) ->
|
||||||
let es = toExprs arg in
|
let es = toExprs arg in
|
||||||
if isOpt "mk" opts
|
if isOpt "mk" opts
|
||||||
then return $ fromString $ unlines $ map (tree2mk pgf) es
|
then return $ fromString $ unlines $ map (tree2mk pgf) es
|
||||||
@@ -626,7 +686,7 @@ pgfCommands = Map.fromList [
|
|||||||
else do
|
else do
|
||||||
let funs = not (isOpt "nofun" opts)
|
let funs = not (isOpt "nofun" opts)
|
||||||
let cats = not (isOpt "nocat" opts)
|
let cats = not (isOpt "nocat" opts)
|
||||||
let grphs = map (graphvizAbstractTree pgf (graphvizDefaults{noFun=funs,noCat=cats})) es
|
let grphs = map (graphvizAbstractTree pgf (funs,cats)) es
|
||||||
if isFlag "view" opts || isFlag "format" opts
|
if isFlag "view" opts || isFlag "format" opts
|
||||||
then do
|
then do
|
||||||
let view = optViewGraph opts
|
let view = optViewGraph opts
|
||||||
@@ -648,7 +708,6 @@ pgfCommands = Map.fromList [
|
|||||||
("view","program to open the resulting file (default \"open\")")
|
("view","program to open the resulting file (default \"open\")")
|
||||||
]
|
]
|
||||||
}),
|
}),
|
||||||
|
|
||||||
("ai", emptyCommandInfo {
|
("ai", emptyCommandInfo {
|
||||||
longname = "abstract_info",
|
longname = "abstract_info",
|
||||||
syntax = "ai IDENTIFIER or ai EXPR",
|
syntax = "ai IDENTIFIER or ai EXPR",
|
||||||
@@ -661,150 +720,205 @@ pgfCommands = Map.fromList [
|
|||||||
"If a whole expression is given it prints the expression with refined",
|
"If a whole expression is given it prints the expression with refined",
|
||||||
"metavariables and the type of the expression."
|
"metavariables and the type of the expression."
|
||||||
],
|
],
|
||||||
exec = needPGF $ \opts arg pgf -> do
|
exec = getEnv $ \ opts arg (Env pgf mos) -> do
|
||||||
case toExprs arg of
|
case toExprs arg of
|
||||||
[e] -> case unApp e of
|
[EFun id] -> case Map.lookup id (funs (abstract pgf)) of
|
||||||
Just (id, []) -> case functionType pgf id of
|
Just fd -> do putStrLn $ render (ppFun id fd)
|
||||||
Just ty -> do putStrLn (showFun pgf id ty)
|
let (_,_,_,prob) = fd
|
||||||
putStrLn ("Probability: "++show (treeProbability pgf e))
|
putStrLn ("Probability: "++show prob)
|
||||||
return void
|
return void
|
||||||
Nothing -> case categoryContext pgf id of
|
Nothing -> case Map.lookup id (cats (abstract pgf)) of
|
||||||
Just hypos -> do putStrLn ("cat "++id++if null hypos then "" else ' ':showContext [] hypos)
|
Just cd -> do putStrLn $
|
||||||
let ls = [showFun pgf fn ty | fn <- functionsByCat pgf id, Just ty <- [functionType pgf fn]]
|
render (ppCat id cd $$
|
||||||
if null ls
|
if null (functionsToCat pgf id)
|
||||||
then return ()
|
then empty
|
||||||
else putStrLn (unlines ("":ls))
|
else ' ' $$
|
||||||
putStrLn ("Probability: "++show (categoryProbability pgf id))
|
vcat [ppFun fid (ty,0,Just ([],[]),0) | (fid,ty) <- functionsToCat pgf id] $$
|
||||||
return void
|
' ')
|
||||||
Nothing -> do putStrLn ("unknown category of function identifier "++show id)
|
let (_,_,prob) = cd
|
||||||
return void
|
putStrLn ("Probability: "++show prob)
|
||||||
_ -> case inferExpr pgf e of
|
return void
|
||||||
Left err -> error err
|
Nothing -> do putStrLn ("unknown category of function identifier "++show id)
|
||||||
Right (e,ty) -> do putStrLn ("Expression: "++showExpr [] e)
|
return void
|
||||||
putStrLn ("Type: "++showType [] ty)
|
[e] -> case inferExpr pgf e of
|
||||||
putStrLn ("Probability: "++show (treeProbability pgf e))
|
Left tcErr -> error $ render (ppTcError tcErr)
|
||||||
return void
|
Right (e,ty) -> do putStrLn ("Expression: "++showExpr [] e)
|
||||||
|
putStrLn ("Type: "++showType [] ty)
|
||||||
|
putStrLn ("Probability: "++show (probTree pgf e))
|
||||||
|
return void
|
||||||
_ -> do putStrLn "a single identifier or expression is expected from the command"
|
_ -> do putStrLn "a single identifier or expression is expected from the command"
|
||||||
return void,
|
return void,
|
||||||
needsTypeCheck = False
|
needsTypeCheck = False
|
||||||
})
|
})
|
||||||
]
|
]
|
||||||
where
|
where
|
||||||
needPGF exec opts ts = do
|
getEnv exec opts ts = liftSIO . exec opts ts =<< getPGFEnv
|
||||||
mb_pgf <- getPGF
|
|
||||||
case mb_pgf of
|
par pgf opts s = case optOpenTypes opts of
|
||||||
Just pgf -> liftSIO $ exec opts ts pgf
|
[] -> [parse_ pgf lang (optType pgf opts) (Just dp) s | lang <- optLangs pgf opts]
|
||||||
_ -> fail "Import a grammar before using this command"
|
open_typs -> [parseWithRecovery pgf lang (optType pgf opts) open_typs (Just dp) s | lang <- optLangs pgf opts]
|
||||||
|
where
|
||||||
|
dp = valIntOpts "depth" 4 opts
|
||||||
|
|
||||||
|
fromParse opts = foldr (joinPiped . fromParse1 opts) void
|
||||||
|
|
||||||
joinPiped (Piped (es1,ms1)) (Piped (es2,ms2)) = Piped (jA es1 es2,ms1+++-ms2)
|
joinPiped (Piped (es1,ms1)) (Piped (es2,ms2)) = Piped (jA es1 es2,ms1+++-ms2)
|
||||||
where
|
where
|
||||||
jA (Exprs es1) (Exprs es2) = Exprs (es1++es2)
|
jA (Exprs es1) (Exprs es2) = Exprs (es1++es2)
|
||||||
|
-- ^ fromParse1 always output Exprs
|
||||||
|
|
||||||
fromParse1 opts (s,po) =
|
fromParse1 opts (s,(po,bs))
|
||||||
case po of
|
| isOpt "bracket" opts = pipeMessage (showBracketedString bs)
|
||||||
ParseOk ts -> fromExprs (isOpt "show_probs" opts) (takeOptNum opts ts)
|
| otherwise =
|
||||||
ParseFailed i t -> pipeMessage $ "The parser failed at token "
|
case po of
|
||||||
++ show i ++": "
|
ParseOk ts -> fromExprs ts
|
||||||
++ show t
|
ParseFailed i -> pipeMessage $ "The parser failed at token "
|
||||||
ParseIncomplete -> pipeMessage "The sentence is not complete"
|
++ show i ++": "
|
||||||
|
++ show (words s !! max 0 (i-1))
|
||||||
|
-- ++ " in " ++ show s
|
||||||
|
ParseIncomplete -> pipeMessage "The sentence is not complete"
|
||||||
|
TypeError errs ->
|
||||||
|
pipeMessage . render $
|
||||||
|
"The parsing is successful but the type checking failed with error(s):"
|
||||||
|
$$ nest 2 (vcat (map (ppTcError . snd) errs))
|
||||||
|
|
||||||
optLins pgf opts ts = concatMap (optLin pgf opts) ts
|
optLins pgf opts ts = case opts of
|
||||||
|
_ | isOpt "groups" opts ->
|
||||||
|
concatMap snd $ groupResults
|
||||||
|
[[(lang, s) | lang <- optLangs pgf opts,s <- linear pgf opts lang t] | t <- ts]
|
||||||
|
_ -> concatMap (optLin pgf opts) ts
|
||||||
optLin pgf opts t =
|
optLin pgf opts t =
|
||||||
case opts of
|
case opts of
|
||||||
|
_ | isOpt "treebank" opts && isOpt "chunks" opts ->
|
||||||
|
(showCId (abstractName pgf) ++ ": " ++ showExpr [] t) :
|
||||||
|
[showCId lang ++ ": " ++ li | (lang,li) <- linChunks pgf opts t] --linear pgf opts lang t | lang <- optLangs pgf opts]
|
||||||
_ | isOpt "treebank" opts ->
|
_ | isOpt "treebank" opts ->
|
||||||
(abstractName pgf ++ ": " ++ showExpr [] t) :
|
(showCId (abstractName pgf) ++ ": " ++ showExpr [] t) :
|
||||||
[concreteName concr ++ ": " ++ s | concr <- optLangs pgf opts, s<-linear opts concr t]
|
[showCId lang ++ ": " ++ s | lang <- optLangs pgf opts, s<-linear pgf opts lang t]
|
||||||
_ -> [s | concr <- optLangs pgf opts, s <- linear opts concr t]
|
_ | isOpt "tabtreebank" opts ->
|
||||||
|
return $ concat $ intersperse "\t" $ (showExpr [] t) :
|
||||||
|
[s | lang <- optLangs pgf opts, s <- linear pgf opts lang t]
|
||||||
|
_ | isOpt "chunks" opts -> map snd $ linChunks pgf opts t
|
||||||
|
_ -> [s | lang <- optLangs pgf opts, s<-linear pgf opts lang t]
|
||||||
|
linChunks pgf opts t =
|
||||||
|
[(lang, unwords (intersperse "<+>" (map (unlines . linear pgf opts lang) (treeChunks t)))) | lang <- optLangs pgf opts]
|
||||||
|
|
||||||
linear :: [Option] -> Concr -> Expr -> [String]
|
linear :: PGF -> [Option] -> CId -> Expr -> [String]
|
||||||
linear opts concr = case opts of
|
linear pgf opts lang = let unl = unlex opts lang in case opts of
|
||||||
_ | isOpt "all" opts -> concat .
|
_ | isOpt "all" opts -> concat . -- intersperse [[]] .
|
||||||
map (map snd) . tabularLinearizeAll concr
|
map (map (unl . snd)) . tabularLinearizes pgf lang
|
||||||
_ | isOpt "list" opts -> (:[]) . commaList . concat .
|
_ | isOpt "list" opts -> (:[]) . commaList . concat .
|
||||||
map (map snd) . tabularLinearizeAll concr
|
map (map (unl . snd)) . tabularLinearizes pgf lang
|
||||||
_ | isOpt "table" opts -> concat .
|
_ | isOpt "table" opts -> concat . -- intersperse [[]] .
|
||||||
map (map (\(p,v) -> p+++":"+++v)) . tabularLinearizeAll concr
|
map (map (\(p,v) -> p+++":"+++unl v)) . tabularLinearizes pgf lang
|
||||||
_ | isOpt "bracket" opts -> (:[]) . unwords . map showBracketedString . bracketedLinearize concr
|
_ | isOpt "bracket" opts -> (:[]) . unwords . map showBracketedString . bracketedLinearize pgf lang
|
||||||
_ -> (:[]) . linearize concr
|
_ -> (:[]) . unl . linearize pgf lang
|
||||||
|
|
||||||
-- replace each non-atomic constructor with mkC, where C is the val cat
|
-- replace each non-atomic constructor with mkC, where C is the val cat
|
||||||
tree2mk pgf = showExpr [] . t2m where
|
tree2mk pgf = showExpr [] . t2m where
|
||||||
t2m t = case unApp t of
|
t2m t = case unApp t of
|
||||||
Just (cid,ts@(_:_)) -> mkApp (mk cid) (map t2m ts)
|
Just (cid,ts@(_:_)) -> mkApp (mk cid) (map t2m ts)
|
||||||
_ -> t
|
_ -> t
|
||||||
mk f = case functionType pgf f of
|
mk = mkCId . ("mk" ++) . showCId . lookValCat (abstract pgf)
|
||||||
Just ty -> let (_,cat,_) = unType ty
|
|
||||||
in "mk" ++ cat
|
unlex opts lang = stringOps Nothing (getUnlex opts lang ++ map prOpt opts) ----
|
||||||
Nothing -> f
|
|
||||||
|
getUnlex opts lang = case words (valStrOpts "unlexer" "" opts) of
|
||||||
|
lexs -> case lookup lang
|
||||||
|
[(mkCId la,tail le) | lex <- lexs, let (la,le) = span (/='=') lex, not (null le)] of
|
||||||
|
Just le -> chunks ',' le
|
||||||
|
_ -> []
|
||||||
|
|
||||||
commaList [] = []
|
commaList [] = []
|
||||||
commaList ws = concat $ head ws : map (", " ++) (tail ws)
|
commaList ws = concat $ head ws : map (", " ++) (tail ws)
|
||||||
|
|
||||||
|
-- Proposed logic of coding in unlexing:
|
||||||
|
-- - If lang has no coding flag, or -to_utf8 is not in opts, just opts are used.
|
||||||
|
-- - If lang has flag coding=utf8, -to_utf8 is ignored.
|
||||||
|
-- - If lang has coding=other, and -to_utf8 is in opts, from_other is applied first.
|
||||||
|
-- THIS DOES NOT WORK UNFORTUNATELY - can't use the grammar flag properly
|
||||||
|
{-
|
||||||
|
unlexx pgf opts lang = {- trace (unwords optsC) $ -} stringOps Nothing optsC where ----
|
||||||
|
optsC = case lookConcrFlag pgf (mkCId lang) (mkCId "coding") of
|
||||||
|
Just (LStr "utf8") -> filter (/="to_utf8") $ map prOpt opts
|
||||||
|
Just (LStr other) | isOpt "to_utf8" opts ->
|
||||||
|
let cod = ("from_" ++ other)
|
||||||
|
in cod : filter (/=cod) (map prOpt opts)
|
||||||
|
_ -> map prOpt opts
|
||||||
|
-}
|
||||||
|
optRestricted opts pgf =
|
||||||
|
restrictPGF (\f -> and [hasLin pgf la f | la <- optLangs pgf opts]) pgf
|
||||||
|
|
||||||
optLang = optLangFlag "lang"
|
optLang = optLangFlag "lang"
|
||||||
optLangs = optLangsFlag "lang"
|
optLangs = optLangsFlag "lang"
|
||||||
|
|
||||||
optLangFlag flag pgf opts =
|
optLangsFlag f pgf opts = case valStrOpts f "" opts of
|
||||||
case optLangsFlag flag pgf opts of
|
"" -> languages pgf
|
||||||
[] -> fail "no language specified"
|
lang -> map (completeLang pgf) (chunks ',' lang)
|
||||||
(l:ls) -> return l
|
completeLang pgf la = let cla = (mkCId la) in
|
||||||
|
if elem cla (languages pgf)
|
||||||
|
then cla
|
||||||
|
else (mkCId (showCId (abstractName pgf) ++ la))
|
||||||
|
|
||||||
optLangsFlag flag pgf opts =
|
optLangFlag f pgf opts = head $ optLangsFlag f pgf opts ++ [wildCId]
|
||||||
case valStrOpts flag "" opts of
|
|
||||||
"" -> Map.elems langs
|
|
||||||
str -> mapMaybe (completeLang pgf) (chunks ',' str)
|
|
||||||
where
|
|
||||||
langs = languages pgf
|
|
||||||
|
|
||||||
completeLang pgf la =
|
optOpenTypes opts = case valStrOpts "openclass" "" opts of
|
||||||
mplus (Map.lookup la langs)
|
"" -> []
|
||||||
(Map.lookup (abstractName pgf ++ la) langs)
|
cats -> mapMaybe readType (chunks ',' cats)
|
||||||
|
|
||||||
|
optProbs opts pgf = case valStrOpts "probs" "" opts of
|
||||||
|
"" -> return pgf
|
||||||
|
file -> do
|
||||||
|
probs <- restricted $ readProbabilitiesFromFile file pgf
|
||||||
|
return (setProbabilities probs pgf)
|
||||||
|
|
||||||
optFile opts = valStrOpts "file" "_gftmp" opts
|
optFile opts = valStrOpts "file" "_gftmp" opts
|
||||||
|
|
||||||
optType pgf opts =
|
optType pgf opts =
|
||||||
let readOpt str = case readType str of
|
let str = valStrOpts "cat" (showCId $ lookStartCat pgf) opts
|
||||||
Just ty -> case checkType pgf ty of
|
in case readType str of
|
||||||
Left err -> error err
|
Just ty -> case checkType pgf ty of
|
||||||
Right ty -> ty
|
Left tcErr -> error $ render (ppTcError tcErr)
|
||||||
Nothing -> error ("Can't parse '"++str++"' as a type")
|
Right ty -> ty
|
||||||
in maybeStrOpts "cat" (startCat pgf) readOpt opts
|
Nothing -> error ("Can't parse '"++str++"' as a type")
|
||||||
optViewFormat opts = valStrOpts "format" "png" opts
|
optViewFormat opts = valStrOpts "format" "png" opts
|
||||||
optViewGraph opts = valStrOpts "view" "open" opts
|
optViewGraph opts = valStrOpts "view" "open" opts
|
||||||
optNum opts = valIntOpts "number" 1 opts
|
optNum opts = valIntOpts "number" 1 opts
|
||||||
optNumInf opts = valIntOpts "number" 1000000000 opts ---- 10^9
|
optNumInf opts = valIntOpts "number" 1000000000 opts ---- 10^9
|
||||||
takeOptNum opts = take (optNumInf opts)
|
takeOptNum opts = take (optNumInf opts)
|
||||||
|
|
||||||
returnFromExprs show_p es =
|
returnFromExprs es = return $ case es of
|
||||||
return $
|
[] -> pipeMessage "no trees found"
|
||||||
case es of
|
_ -> fromExprs es
|
||||||
[] -> pipeMessage "no trees found"
|
|
||||||
_ -> fromExprs show_p es
|
|
||||||
|
|
||||||
prGrammar pgf opts
|
prGrammar (Env pgf mos) opts
|
||||||
| isOpt "pgf" opts = do
|
| isOpt "pgf" opts = do
|
||||||
let outfile = valStrOpts "file" (abstractName pgf ++ ".pgf") opts
|
let pgf1 = if isOpt "opt" opts then optimizePGF pgf else pgf
|
||||||
restricted $ writePGF outfile pgf
|
let outfile = valStrOpts "file" (showCId (abstractName pgf) ++ ".pgf") opts
|
||||||
|
restricted $ encodeFile outfile pgf1
|
||||||
putStrLn $ "wrote file " ++ outfile
|
putStrLn $ "wrote file " ++ outfile
|
||||||
return void
|
return void
|
||||||
| isOpt "cats" opts = return $ fromString $ unwords $ categories pgf
|
| isOpt "cats" opts = return $ fromString $ unwords $ map showCId $ categories pgf
|
||||||
| isOpt "funs" opts = return $ fromString $ unlines [showFun pgf f ty | f <- functions pgf, Just ty <- [functionType pgf f]]
|
| isOpt "funs" opts = return $ fromString $ unlines $ map showFun $ funsigs pgf
|
||||||
| isOpt "fullform" opts = return $ fromString $ concatMap prFullFormLexicon $ optLangs pgf opts
|
| isOpt "fullform" opts = return $ fromString $ concatMap (morpho mos "" prFullFormLexicon) $ optLangs pgf opts
|
||||||
| isOpt "langs" opts = return $ fromString $ unwords $ Map.keys $ languages pgf
|
| isOpt "langs" opts = return $ fromString $ unwords $ map showCId $ languages pgf
|
||||||
|
|
||||||
| isOpt "lexc" opts = return $ fromString $ concatMap prLexcLexicon $ optLangs pgf opts
|
| isOpt "lexc" opts = return $ fromString $ concatMap (morpho mos "" prLexcLexicon) $ optLangs pgf opts
|
||||||
| isOpt "missing" opts = return $ fromString $ unlines $ [unwords (concreteName concr:":":[f | f <- functions pgf, not (hasLinearization concr f)]) |
|
| isOpt "missing" opts = return $ fromString $ unlines $ [unwords (showCId la:":": map showCId cs) |
|
||||||
concr <- optLangs pgf opts]
|
la <- optLangs pgf opts, let cs = missingLins pgf la]
|
||||||
| isOpt "words" opts = return $ fromString $ concatMap prAllWords $ optLangs pgf opts
|
| isOpt "words" opts = return $ fromString $ concatMap (morpho mos "" prAllWords) $ optLangs pgf opts
|
||||||
| otherwise = do fmt <- readOutputFormat (valStrOpts "printer" "pgf_pretty" opts)
|
| otherwise = do fmt <- readOutputFormat (valStrOpts "printer" "pgf_pretty" opts)
|
||||||
return $ fromString $ concatMap snd $ exportPGF noOptions fmt pgf
|
return $ fromString $ concatMap snd $ exportPGF noOptions fmt pgf
|
||||||
|
|
||||||
showFun pgf id ty = kwd++" "++ id ++ " : " ++ showType [] ty
|
funsigs pgf = [(f,ty) | (f,(ty,_,_,_)) <- Map.assocs (funs (abstract pgf))]
|
||||||
where
|
showFun (f,ty) = showCId f ++ " : " ++ showType [] ty ++ " ;"
|
||||||
kwd | functionIsDataCon pgf id = "data"
|
|
||||||
| otherwise = "fun"
|
|
||||||
|
|
||||||
morphos pgf opts s =
|
morphos (Env pgf mos) opts s =
|
||||||
[(s,lookupMorpho concr s) | concr <- optLangs pgf opts]
|
[(s,morpho mos [] (\mo -> lookupMorpho mo s) la) | la <- optLangs pgf opts]
|
||||||
|
|
||||||
|
morpho mos z f la = maybe z f $ Map.lookup la mos
|
||||||
|
|
||||||
|
optMorpho (Env pgf mos) opts = morpho mos (error "no morpho") id (head (optLangs pgf opts))
|
||||||
|
|
||||||
optClitics opts = case valStrOpts "clitics" "" opts of
|
optClitics opts = case valStrOpts "clitics" "" opts of
|
||||||
"" -> []
|
"" -> []
|
||||||
@@ -817,28 +931,18 @@ pgfCommands = Map.fromList [
|
|||||||
-- ps -f -g s returns g (f s)
|
-- ps -f -g s returns g (f s)
|
||||||
treeOps pgf opts s = foldr app s (reverse opts) where
|
treeOps pgf opts s = foldr app s (reverse opts) where
|
||||||
app (OOpt op) | Just (Left f) <- treeOp pgf op = f
|
app (OOpt op) | Just (Left f) <- treeOp pgf op = f
|
||||||
app (OFlag op (VId x)) | Just (Right f) <- treeOp pgf op = f x
|
app (OFlag op (VId x)) | Just (Right f) <- treeOp pgf op = f (mkCId x)
|
||||||
app _ = id
|
app _ = id
|
||||||
|
|
||||||
morphoMissing :: Concr -> [String] -> [String]
|
|
||||||
morphoMissing = morphoClassify False
|
|
||||||
|
|
||||||
morphoKnown :: Concr -> [String] -> [String]
|
|
||||||
morphoKnown = morphoClassify True
|
|
||||||
|
|
||||||
morphoClassify :: Bool -> Concr -> [String] -> [String]
|
|
||||||
morphoClassify k concr ws = [w | w <- ws, k /= null (lookupMorpho concr w), notLiteral w] where
|
|
||||||
notLiteral w = not (all isDigit w)
|
|
||||||
|
|
||||||
treeOpOptions pgf = [(op,expl) | (op,(expl,Left _)) <- allTreeOps pgf]
|
treeOpOptions pgf = [(op,expl) | (op,(expl,Left _)) <- allTreeOps pgf]
|
||||||
treeOpFlags pgf = [(op,expl) | (op,(expl,Right _)) <- allTreeOps pgf]
|
treeOpFlags pgf = [(op,expl) | (op,(expl,Right _)) <- allTreeOps pgf]
|
||||||
|
|
||||||
translationQuiz :: Maybe Expr -> PGF -> Concr -> Concr -> Type -> IO ()
|
translationQuiz :: Maybe Expr -> PGF -> Language -> Language -> Type -> IO ()
|
||||||
translationQuiz mex pgf ig og typ = do
|
translationQuiz mex pgf ig og typ = do
|
||||||
tts <- translationList mex pgf ig og typ infinity
|
tts <- translationList mex pgf ig og typ infinity
|
||||||
mkQuiz "Welcome to GF Translation Quiz." tts
|
mkQuiz "Welcome to GF Translation Quiz." tts
|
||||||
|
|
||||||
morphologyQuiz :: Maybe Expr -> PGF -> Concr -> Type -> IO ()
|
morphologyQuiz :: Maybe Expr -> PGF -> Language -> Type -> IO ()
|
||||||
morphologyQuiz mex pgf ig typ = do
|
morphologyQuiz mex pgf ig typ = do
|
||||||
tts <- morphologyList mex pgf ig typ infinity
|
tts <- morphologyList mex pgf ig typ infinity
|
||||||
mkQuiz "Welcome to GF Morphology Quiz." tts
|
mkQuiz "Welcome to GF Morphology Quiz." tts
|
||||||
@@ -847,28 +951,30 @@ morphologyQuiz mex pgf ig typ = do
|
|||||||
infinity :: Int
|
infinity :: Int
|
||||||
infinity = 256
|
infinity = 256
|
||||||
|
|
||||||
prLexcLexicon :: Concr -> String
|
prLexcLexicon :: Morpho -> String
|
||||||
prLexcLexicon concr =
|
prLexcLexicon mo =
|
||||||
unlines $ "Multichar_Symbols":multichars:"":"LEXICON Root" : [prLexc l p ++ ":" ++ w ++ " # ;" | (w,lps) <- morpho, (l,p,_) <- lps] ++ ["END"]
|
unlines $ "Multichar_Symbols":multichars:"":"LEXICON Root" : [prLexc l p ++ ":" ++ w ++ " # ;" | (w,lps) <- morpho, (l,p) <- lps] ++ ["END"]
|
||||||
where
|
where
|
||||||
morpho = fullFormLexicon concr
|
morpho = fullFormLexicon mo
|
||||||
prLexc l p = l ++ concat (mkTags (words p))
|
prLexc l p = showCId l ++ concat (mkTags (words p))
|
||||||
mkTags p = case p of
|
mkTags p = case p of
|
||||||
"s":ws -> mkTags ws --- remove record field
|
"s":ws -> mkTags ws --- remove record field
|
||||||
ws -> map ('+':) ws
|
ws -> map ('+':) ws
|
||||||
|
|
||||||
multichars = unwords $ nub $ concat [mkTags (words p) | (w,lps) <- morpho, (l,p,_) <- lps]
|
multichars = unwords $ nub $ concat [mkTags (words p) | (w,lps) <- morpho, (l,p) <- lps]
|
||||||
|
-- thick_A+(AAdj+Posit+Gen):thick's # ;
|
||||||
|
|
||||||
prFullFormLexicon :: Concr -> String
|
prFullFormLexicon :: Morpho -> String
|
||||||
prFullFormLexicon concr =
|
prFullFormLexicon mo =
|
||||||
unlines (map prMorphoAnalysis (fullFormLexicon concr))
|
unlines (map prMorphoAnalysis (fullFormLexicon mo))
|
||||||
|
|
||||||
prAllWords :: Concr -> String
|
prAllWords :: Morpho -> String
|
||||||
prAllWords concr =
|
prAllWords mo =
|
||||||
unwords [w | (w,_) <- fullFormLexicon concr]
|
unwords [w | (w,_) <- fullFormLexicon mo]
|
||||||
|
|
||||||
|
prMorphoAnalysis :: (String,[(Lemma,Analysis)]) -> String
|
||||||
prMorphoAnalysis (w,lps) =
|
prMorphoAnalysis (w,lps) =
|
||||||
unlines (w:[l ++ " : " ++ p ++ show prob | (l,p,prob) <- lps])
|
unlines (w:[showCId l ++ " : " ++ p | (l,p) <- lps])
|
||||||
|
|
||||||
viewGraphviz :: String -> String -> String -> [String] -> SIO CommandOutput
|
viewGraphviz :: String -> String -> String -> [String] -> SIO CommandOutput
|
||||||
viewGraphviz view format name grphs = do
|
viewGraphviz view format name grphs = do
|
||||||
@@ -913,7 +1019,3 @@ stanzas = map unlines . chop . lines where
|
|||||||
chop ls = case break (=="") ls of
|
chop ls = case break (=="") ls of
|
||||||
(ls1,[]) -> [ls1]
|
(ls1,[]) -> [ls1]
|
||||||
(ls1,_:ls2) -> ls1 : chop ls2
|
(ls1,_:ls2) -> ls1 : chop ls2
|
||||||
|
|
||||||
#if !(MIN_VERSION_base(4,9,0))
|
|
||||||
errorWithoutStackTrace = error
|
|
||||||
#endif
|
|
||||||
|
|||||||
831
src/compiler/GF/Command/Commands2.hs
Normal file
831
src/compiler/GF/Command/Commands2.hs
Normal file
@@ -0,0 +1,831 @@
|
|||||||
|
{-# LANGUAGE FlexibleInstances, UndecidableInstances #-}
|
||||||
|
module GF.Command.Commands2 (
|
||||||
|
PGFEnv,HasPGFEnv(..),pgf,concs,pgfEnv,emptyPGFEnv,pgfCommands,
|
||||||
|
options, flags,
|
||||||
|
) where
|
||||||
|
import Prelude hiding (putStrLn,(<>)) -- GHC 8.4.1 clash with Text.PrettyPrint
|
||||||
|
|
||||||
|
import PGF2
|
||||||
|
import qualified PGF as H
|
||||||
|
import GF.Compile.ToAPI(exprToAPI)
|
||||||
|
import GF.Infra.UseIO(writeUTF8File)
|
||||||
|
import GF.Infra.SIO(MonadSIO,liftSIO,putStrLn,restricted,restrictedSystem)
|
||||||
|
import GF.Command.Abstract
|
||||||
|
import GF.Command.CommandInfo
|
||||||
|
import GF.Data.Operations
|
||||||
|
import Data.List(intersperse,intersect,nub,sortBy)
|
||||||
|
import Data.Maybe
|
||||||
|
import qualified Data.Map as Map
|
||||||
|
import GF.Text.Pretty
|
||||||
|
import Control.Monad(mplus)
|
||||||
|
import qualified Control.Monad.Fail as Fail
|
||||||
|
|
||||||
|
|
||||||
|
data PGFEnv = Env {pgf::Maybe PGF,concs::Map.Map ConcName Concr}
|
||||||
|
|
||||||
|
pgfEnv pgf = Env (Just pgf) (languages pgf)
|
||||||
|
emptyPGFEnv = Env Nothing Map.empty
|
||||||
|
|
||||||
|
class (Fail.MonadFail m,MonadSIO m) => HasPGFEnv m where getPGFEnv :: m PGFEnv
|
||||||
|
|
||||||
|
instance (Monad m,HasPGFEnv m) => TypeCheckArg m where
|
||||||
|
typeCheckArg e = do env <- getPGFEnv
|
||||||
|
case pgf env of
|
||||||
|
Just gr -> either fail
|
||||||
|
(return . hsExpr . fst)
|
||||||
|
(inferExpr gr (cExpr e))
|
||||||
|
Nothing -> fail "Import a grammar before using this command"
|
||||||
|
|
||||||
|
pgfCommands :: HasPGFEnv m => Map.Map String (CommandInfo m)
|
||||||
|
pgfCommands = Map.fromList [
|
||||||
|
("aw", emptyCommandInfo {
|
||||||
|
longname = "align_words",
|
||||||
|
synopsis = "show word alignments between languages graphically",
|
||||||
|
explanation = unlines [
|
||||||
|
"Prints a set of strings in the .dot format (the graphviz format).",
|
||||||
|
"The graph can be saved in a file by the wf command as usual.",
|
||||||
|
"If the -view flag is defined, the graph is saved in a temporary file",
|
||||||
|
"which is processed by graphviz and displayed by the program indicated",
|
||||||
|
"by the flag. The target format is postscript, unless overridden by the",
|
||||||
|
"flag -format."
|
||||||
|
],
|
||||||
|
exec = needPGF $ \opts es env -> do
|
||||||
|
let cncs = optConcs env opts
|
||||||
|
if isOpt "giza" opts
|
||||||
|
then if length cncs == 2
|
||||||
|
then let giz = map (gizaAlignment pgf (snd (cncs !! 0)) (snd (cncs !! 1)) . cExpr) (toExprs es)
|
||||||
|
lsrc = unlines $ map (\(x,_,_) -> x) giz
|
||||||
|
ltrg = unlines $ map (\(_,x,_) -> x) giz
|
||||||
|
align = unlines $ map (\(_,_,x) -> x) giz
|
||||||
|
grph = if null (toExprs es) then [] else lsrc ++ "\n--end_source--\n\n"++ltrg++"\n-end_target--\n\n"++align
|
||||||
|
in return (fromString grph)
|
||||||
|
else error "For giza alignment you need exactly two languages"
|
||||||
|
else let gvOptions=graphvizDefaults{leafFont = valStrOpts "font" "" opts,
|
||||||
|
leafColor = valStrOpts "color" "" opts,
|
||||||
|
leafEdgeStyle = valStrOpts "edgestyle" "" opts
|
||||||
|
}
|
||||||
|
grph = if null (toExprs es) then [] else graphvizWordAlignment (map snd cncs) gvOptions (cExpr (head (toExprs es)))
|
||||||
|
in if isFlag "view" opts || isFlag "format" opts
|
||||||
|
then do let file s = "_grph." ++ s
|
||||||
|
let view = optViewGraph opts
|
||||||
|
let format = optViewFormat opts
|
||||||
|
restricted $ writeUTF8File (file "dot") grph
|
||||||
|
restrictedSystem $ "dot -T" ++ format ++ " " ++ file "dot" ++ " > " ++ file format
|
||||||
|
restrictedSystem $ view ++ " " ++ file format
|
||||||
|
return void
|
||||||
|
else return (fromString grph),
|
||||||
|
examples = [
|
||||||
|
("gr | aw" , "generate a tree and show word alignment as graph script"),
|
||||||
|
("gr | aw -view=\"open\"" , "generate a tree and display alignment on Mac"),
|
||||||
|
("gr | aw -view=\"eog\"" , "generate a tree and display alignment on Ubuntu"),
|
||||||
|
("gt | aw -giza | wf -file=aligns" , "generate trees, send giza alignments to file")
|
||||||
|
],
|
||||||
|
options = [
|
||||||
|
("giza", "show alignments in the Giza format; the first two languages")
|
||||||
|
],
|
||||||
|
flags = [
|
||||||
|
("format","format of the visualization file (default \"png\")"),
|
||||||
|
("lang", "alignments for this list of languages (default: all)"),
|
||||||
|
("view", "program to open the resulting file"),
|
||||||
|
("font", "font for the words"),
|
||||||
|
("color", "color for the words"),
|
||||||
|
("edgestyle", "the style for links between words")
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
{-
|
||||||
|
("eb", emptyCommandInfo {
|
||||||
|
longname = "example_based",
|
||||||
|
syntax = "eb (-probs=FILE | -lang=LANG)* -file=FILE.gfe",
|
||||||
|
synopsis = "converts .gfe files to .gf files by parsing examples to trees",
|
||||||
|
explanation = unlines [
|
||||||
|
"Reads FILE.gfe and writes FILE.gf. Each expression of form",
|
||||||
|
"'%ex CAT QUOTEDSTRING' in FILE.gfe is replaced by a syntax tree.",
|
||||||
|
"This tree is the first one returned by the parser; a biased ranking",
|
||||||
|
"can be used to regulate the order. If there are more than one parses",
|
||||||
|
"the rest are shown in comments, with probabilities if the order is biased.",
|
||||||
|
"The probabilities flag and configuration file is similar to the commands",
|
||||||
|
"gr and rt. Notice that the command doesn't change the environment,",
|
||||||
|
"but the resulting .gf file must be imported separately."
|
||||||
|
],
|
||||||
|
options = [
|
||||||
|
("api","convert trees to overloaded API expressions (using Syntax not Lang)")
|
||||||
|
],
|
||||||
|
flags = [
|
||||||
|
("file","the file to be converted (suffix .gfe must be given)"),
|
||||||
|
("lang","the language in which to parse"),
|
||||||
|
("probs","file with probabilities to rank the parses")
|
||||||
|
],
|
||||||
|
exec = \env@(pgf, mos) opts _ -> do
|
||||||
|
let file = optFile opts
|
||||||
|
pgf <- optProbs opts pgf
|
||||||
|
let printer = if (isOpt "api" opts) then exprToAPI else (H.showExpr [])
|
||||||
|
let conf = configureExBased pgf (optMorpho env opts) (optLang pgf opts) printer
|
||||||
|
(file',ws) <- restricted $ parseExamplesInGrammar conf file
|
||||||
|
if null ws then return () else putStrLn ("unknown words: " ++ unwords ws)
|
||||||
|
return (fromString ("wrote " ++ file')),
|
||||||
|
needsTypeCheck = False
|
||||||
|
}),
|
||||||
|
-}
|
||||||
|
{-
|
||||||
|
("gr", emptyCommandInfo {
|
||||||
|
longname = "generate_random",
|
||||||
|
synopsis = "generate random trees in the current abstract syntax",
|
||||||
|
syntax = "gr [-cat=CAT] [-number=INT]",
|
||||||
|
examples = [
|
||||||
|
mkEx "gr -- one tree in the startcat of the current grammar",
|
||||||
|
mkEx "gr -cat=NP -number=16 -- 16 trees in the category NP",
|
||||||
|
mkEx "gr -lang=LangHin,LangTha -cat=Cl -- Cl, both in LangHin and LangTha",
|
||||||
|
mkEx "gr -probs=FILE -- generate with bias",
|
||||||
|
mkEx "gr (AdjCN ? (UseN ?)) -- generate trees of form (AdjCN ? (UseN ?))"
|
||||||
|
],
|
||||||
|
explanation = unlines [
|
||||||
|
"Generates a list of random trees, by default one tree.",
|
||||||
|
"If a tree argument is given, the command completes the Tree with values to",
|
||||||
|
"all metavariables in the tree. The generation can be biased by probabilities,",
|
||||||
|
"given in a file in the -probs flag."
|
||||||
|
],
|
||||||
|
flags = [
|
||||||
|
("cat","generation category"),
|
||||||
|
("lang","uses only functions that have linearizations in all these languages"),
|
||||||
|
("number","number of trees generated"),
|
||||||
|
("depth","the maximum generation depth"),
|
||||||
|
("probs", "file with biased probabilities (format 'f 0.4' one by line)")
|
||||||
|
],
|
||||||
|
exec = \env@(pgf, mos) opts xs -> do
|
||||||
|
pgf <- optProbs opts (optRestricted opts pgf)
|
||||||
|
gen <- newStdGen
|
||||||
|
let dp = valIntOpts "depth" 4 opts
|
||||||
|
let ts = case mexp xs of
|
||||||
|
Just ex -> H.generateRandomFromDepth gen pgf ex (Just dp)
|
||||||
|
Nothing -> H.generateRandomDepth gen pgf (optType pgf opts) (Just dp)
|
||||||
|
returnFromExprs $ take (optNum opts) ts
|
||||||
|
}),
|
||||||
|
-}
|
||||||
|
("gt", emptyCommandInfo {
|
||||||
|
longname = "generate_trees",
|
||||||
|
synopsis = "generates a list of trees, by default exhaustive",
|
||||||
|
flags = [("cat","the generation category"),
|
||||||
|
("number","the number of trees generated")],
|
||||||
|
examples = [
|
||||||
|
mkEx "gt -- all trees in the startcat",
|
||||||
|
mkEx "gt -cat=NP -number=16 -- 16 trees in the category NP"],
|
||||||
|
exec = needPGF $ \ opts _ env@(pgf,_) ->
|
||||||
|
let ts = map fst (generateAll pgf cat)
|
||||||
|
cat = optType pgf opts
|
||||||
|
in returnFromCExprs (takeOptNum opts ts),
|
||||||
|
needsTypeCheck = False
|
||||||
|
}),
|
||||||
|
("i", emptyCommandInfo {
|
||||||
|
longname = "import",
|
||||||
|
synopsis = "import a grammar from a compiled .pgf file",
|
||||||
|
explanation = unlines [
|
||||||
|
"Reads a grammar from a compiled .pgf file.",
|
||||||
|
"Old modules are discarded.",
|
||||||
|
{-
|
||||||
|
"The grammar parser depends on the file name suffix:",
|
||||||
|
|
||||||
|
" .cf context-free (labelled BNF) source",
|
||||||
|
" .ebnf extended BNF source",
|
||||||
|
" .gfm multi-module GF source",
|
||||||
|
" .gf normal GF source",
|
||||||
|
" .gfo compiled GF source",
|
||||||
|
-}
|
||||||
|
" .pgf precompiled grammar in Portable Grammar Format"
|
||||||
|
],
|
||||||
|
flags = [
|
||||||
|
-- ("probs","file with biased probabilities for generation")
|
||||||
|
],
|
||||||
|
options = [
|
||||||
|
-- ["gfo", "src", "no-cpu", "cpu", "quiet", "verbose"]
|
||||||
|
-- ("retain","retain operations (used for cc command)"),
|
||||||
|
-- ("src", "force compilation from source"),
|
||||||
|
-- ("v", "be verbose - show intermediate status information")
|
||||||
|
],
|
||||||
|
needsTypeCheck = False
|
||||||
|
}),
|
||||||
|
("l", emptyCommandInfo {
|
||||||
|
longname = "linearize",
|
||||||
|
synopsis = "convert an abstract syntax expression to string",
|
||||||
|
explanation = unlines [
|
||||||
|
"Shows the linearization of a Tree by the grammars in scope.",
|
||||||
|
"The -lang flag can be used to restrict this to fewer languages.",
|
||||||
|
"A sequence of string operations (see command ps) can be given",
|
||||||
|
"as options, and works then like a pipe to the ps command, except",
|
||||||
|
"that it only affect the strings, not e.g. the table labels.",
|
||||||
|
"These can be given separately to each language with the unlexer flag",
|
||||||
|
"whose results are prepended to the other lexer flags. The value of the",
|
||||||
|
"unlexer flag is a space-separated list of comma-separated string operation",
|
||||||
|
"sequences; see example."
|
||||||
|
],
|
||||||
|
examples = [
|
||||||
|
mkEx "l -lang=LangSwe,LangNor no_Utt -- linearize a tree to LangSwe and LangNor",
|
||||||
|
mkEx "gr -lang=LangHin -cat=Cl | l -table -to_devanagari -- hindi table",
|
||||||
|
mkEx "l -unlexer=\"LangAra=to_arabic LangHin=to_devanagari\" -- different unlexers"
|
||||||
|
],
|
||||||
|
exec = needPGF $ \ opts arg env ->
|
||||||
|
return . fromStrings . optLins env opts . map cExpr $ toExprs arg,
|
||||||
|
options = [
|
||||||
|
("all", "show all forms and variants, one by line (cf. l -list)"),
|
||||||
|
("bracket","show tree structure with brackets and paths to nodes"),
|
||||||
|
("groups", "all languages, grouped by lang, remove duplicate strings"),
|
||||||
|
("list","show all forms and variants, comma-separated on one line (cf. l -all)"),
|
||||||
|
("multi","linearize to all languages (default)"),
|
||||||
|
("table","show all forms labelled by parameters"),
|
||||||
|
("treebank","show the tree and tag linearizations with language names")
|
||||||
|
],
|
||||||
|
flags = [
|
||||||
|
("lang","the languages of linearization (comma-separated, no spaces)")
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
("ma", emptyCommandInfo {
|
||||||
|
longname = "morpho_analyse",
|
||||||
|
synopsis = "print the morphological analyses of the (multiword) expression in the string",
|
||||||
|
explanation = unlines [
|
||||||
|
"Prints all the analyses of the (multiword) expression in the input string,",
|
||||||
|
"using the morphological analyser of the actual grammar (see command pg)"
|
||||||
|
],
|
||||||
|
exec = needPGF $ \opts args env ->
|
||||||
|
return ((fromString . unlines .
|
||||||
|
map prMorphoAnalysis . concatMap (morphos env opts) . toStrings) args),
|
||||||
|
flags = [
|
||||||
|
("lang","the languages of analysis (comma-separated, no spaces)")
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
{-
|
||||||
|
("mq", emptyCommandInfo {
|
||||||
|
longname = "morpho_quiz",
|
||||||
|
synopsis = "start a morphology quiz",
|
||||||
|
syntax = "mq (-cat=CAT)? (-probs=FILE)? TREE?",
|
||||||
|
exec = \env@(pgf, mos) opts xs -> do
|
||||||
|
let lang = optLang pgf opts
|
||||||
|
let typ = optType pgf opts
|
||||||
|
pgf <- optProbs opts pgf
|
||||||
|
let mt = mexp xs
|
||||||
|
restricted $ morphologyQuiz mt pgf lang typ
|
||||||
|
return void,
|
||||||
|
flags = [
|
||||||
|
("lang","language of the quiz"),
|
||||||
|
("cat","category of the quiz"),
|
||||||
|
("number","maximum number of questions"),
|
||||||
|
("probs","file with biased probabilities for generation")
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
-}
|
||||||
|
("p", emptyCommandInfo {
|
||||||
|
longname = "parse",
|
||||||
|
synopsis = "parse a string to abstract syntax expression",
|
||||||
|
explanation = unlines [
|
||||||
|
"Shows all trees returned by parsing a string in the grammars in scope.",
|
||||||
|
"The -lang flag can be used to restrict this to fewer languages.",
|
||||||
|
"The default start category can be overridden by the -cat flag.",
|
||||||
|
"See also the ps command for lexing and character encoding."
|
||||||
|
],
|
||||||
|
flags = [
|
||||||
|
("cat","target category of parsing"),
|
||||||
|
("lang","the languages of parsing (comma-separated, no spaces)"),
|
||||||
|
("number","maximum number of trees returned")
|
||||||
|
],
|
||||||
|
examples = [
|
||||||
|
mkEx "p \"this fish is fresh\" | l -lang=Swe -- try parsing with all languages and translate the successful parses to Swedish"
|
||||||
|
],
|
||||||
|
exec = needPGF $ \ opts ts env -> return . cParse env opts $ toStrings ts
|
||||||
|
}),
|
||||||
|
("pg", emptyCommandInfo {
|
||||||
|
longname = "print_grammar",
|
||||||
|
synopsis = "prints different information about the grammar",
|
||||||
|
exec = needPGF $ \opts _ env -> prGrammar env opts,
|
||||||
|
options = [
|
||||||
|
("cats", "show just the names of abstract syntax categories"),
|
||||||
|
("fullform", "print the fullform lexicon"),
|
||||||
|
("funs", "show just the names and types of abstract syntax functions"),
|
||||||
|
("langs", "show just the names of top concrete syntax modules"),
|
||||||
|
("lexc", "print the lexicon in Xerox LEXC format"),
|
||||||
|
("missing","show just the names of functions that have no linearization"),
|
||||||
|
("words", "print the list of words")
|
||||||
|
],
|
||||||
|
flags = [
|
||||||
|
("lang","the languages that need to be printed")
|
||||||
|
],
|
||||||
|
examples = [
|
||||||
|
mkEx "pg -langs -- show the names of top concrete syntax modules",
|
||||||
|
mkEx "pg -funs | ? grep \" S ;\" -- show functions with value cat S"
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
|
||||||
|
{-
|
||||||
|
("pt", emptyCommandInfo {
|
||||||
|
longname = "put_tree",
|
||||||
|
syntax = "pt OPT? TREE",
|
||||||
|
synopsis = "return a tree, possibly processed with a function",
|
||||||
|
explanation = unlines [
|
||||||
|
"Returns a tree obtained from its argument tree by applying",
|
||||||
|
"tree processing functions in the order given in the command line",
|
||||||
|
"option list. Thus 'pt -f -g s' returns g (f s). Typical tree processors",
|
||||||
|
"are type checking and semantic computation."
|
||||||
|
],
|
||||||
|
examples = [
|
||||||
|
mkEx "pt -compute (plus one two) -- compute value",
|
||||||
|
mkEx "p \"4 dogs love 5 cats\" | pt -transfer=digits2numeral | l -- four...five..."
|
||||||
|
],
|
||||||
|
exec = \env@(pgf, mos) opts ->
|
||||||
|
returnFromExprs . takeOptNum opts . treeOps pgf opts,
|
||||||
|
options = treeOpOptions undefined{-pgf-},
|
||||||
|
flags = [("number","take at most this many trees")] ++ treeOpFlags undefined{-pgf-}
|
||||||
|
}),
|
||||||
|
-}
|
||||||
|
("rf", emptyCommandInfo {
|
||||||
|
longname = "read_file",
|
||||||
|
synopsis = "read string or tree input from a file",
|
||||||
|
explanation = unlines [
|
||||||
|
"Reads input from file. The filename must be in double quotes.",
|
||||||
|
"The input is interpreted as a string by default, and can hence be",
|
||||||
|
"piped e.g. to the parse command. The option -tree interprets the",
|
||||||
|
"input as a tree, which can be given e.g. to the linearize command.",
|
||||||
|
"The option -lines will result in a list of strings or trees, one by line."
|
||||||
|
],
|
||||||
|
options = [
|
||||||
|
("lines","return the list of lines, instead of the singleton of all contents"),
|
||||||
|
("tree","convert strings into trees")
|
||||||
|
],
|
||||||
|
exec = needPGF $ \opts _ env@(pgf, mos) -> do
|
||||||
|
let file = optFile opts
|
||||||
|
let exprs [] = ([],empty)
|
||||||
|
exprs ((n,s):ls) | null s
|
||||||
|
= exprs ls
|
||||||
|
exprs ((n,s):ls) = case readExpr s of
|
||||||
|
Just e -> let (es,err) = exprs ls
|
||||||
|
in case inferExpr pgf e of
|
||||||
|
Right (e,t) -> (e:es,err)
|
||||||
|
Left msg -> (es,"on line" <+> n <> ':' $$ msg $$ err)
|
||||||
|
Nothing -> let (es,err) = exprs ls
|
||||||
|
in (es,"on line" <+> n <> ':' <+> "parse error" $$ err)
|
||||||
|
returnFromLines ls = case exprs ls of
|
||||||
|
(es, err) | null es -> return $ pipeMessage $ render (err $$ "no trees found")
|
||||||
|
| otherwise -> return $ pipeWithMessage (map hsExpr es) (render err)
|
||||||
|
|
||||||
|
s <- restricted $ readFile file
|
||||||
|
case opts of
|
||||||
|
_ | isOpt "lines" opts && isOpt "tree" opts ->
|
||||||
|
returnFromLines (zip [1::Int ..] (lines s))
|
||||||
|
_ | isOpt "tree" opts ->
|
||||||
|
returnFromLines [(1::Int,s)]
|
||||||
|
_ | isOpt "lines" opts -> return (fromStrings $ lines s)
|
||||||
|
_ -> return (fromString s),
|
||||||
|
flags = [("file","the input file name")]
|
||||||
|
}),
|
||||||
|
("rt", emptyCommandInfo {
|
||||||
|
longname = "rank_trees",
|
||||||
|
synopsis = "show trees in an order of decreasing probability",
|
||||||
|
explanation = unlines [
|
||||||
|
"Order trees from the most to the least probable, using either",
|
||||||
|
"even distribution in each category (default) or biased as specified",
|
||||||
|
"by the file given by flag -probs=FILE, where each line has the form",
|
||||||
|
"'function probability', e.g. 'youPol_Pron 0.01'."
|
||||||
|
],
|
||||||
|
exec = needPGF $ \opts es env@(pgf, _) -> do
|
||||||
|
let tds = sortBy (\(_,p) (_,q) -> compare p q)
|
||||||
|
[(t, treeProbability pgf t) | t <- map cExpr (toExprs es)]
|
||||||
|
if isOpt "v" opts
|
||||||
|
then putStrLn $
|
||||||
|
unlines [PGF2.showExpr [] t ++ "\t--" ++ show d | (t,d) <- tds]
|
||||||
|
else return ()
|
||||||
|
returnFromExprs $ map (hsExpr . fst) tds,
|
||||||
|
flags = [
|
||||||
|
("probs","probabilities from this file (format 'f 0.6' per line)")
|
||||||
|
],
|
||||||
|
options = [
|
||||||
|
("v","show all trees with their probability scores")
|
||||||
|
],
|
||||||
|
examples = [
|
||||||
|
mkEx "p \"you are here\" | rt -probs=probs | pt -number=1 -- most probable result"
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
{-
|
||||||
|
("tq", emptyCommandInfo {
|
||||||
|
longname = "translation_quiz",
|
||||||
|
syntax = "tq -from=LANG -to=LANG (-cat=CAT)? (-probs=FILE)? TREE?",
|
||||||
|
synopsis = "start a translation quiz",
|
||||||
|
exec = \env@(pgf, mos) opts xs -> do
|
||||||
|
let from = optLangFlag "from" pgf opts
|
||||||
|
let to = optLangFlag "to" pgf opts
|
||||||
|
let typ = optType pgf opts
|
||||||
|
let mt = mexp xs
|
||||||
|
pgf <- optProbs opts pgf
|
||||||
|
restricted $ translationQuiz mt pgf from to typ
|
||||||
|
return void,
|
||||||
|
flags = [
|
||||||
|
("from","translate from this language"),
|
||||||
|
("to","translate to this language"),
|
||||||
|
("cat","translate in this category"),
|
||||||
|
("number","the maximum number of questions"),
|
||||||
|
("probs","file with biased probabilities for generation")
|
||||||
|
],
|
||||||
|
examples = [
|
||||||
|
mkEx ("tq -from=Eng -to=Swe -- any trees in startcat"),
|
||||||
|
mkEx ("tq -from=Eng -to=Swe (AdjCN (PositA ?2) (UseN ?)) -- only trees of this form")
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
("vd", emptyCommandInfo {
|
||||||
|
longname = "visualize_dependency",
|
||||||
|
synopsis = "show word dependency tree graphically",
|
||||||
|
explanation = unlines [
|
||||||
|
"Prints a dependency tree in the .dot format (the graphviz format, default)",
|
||||||
|
"or the CoNLL/MaltParser format (flag -output=conll for training, malt_input",
|
||||||
|
"for unanalysed input).",
|
||||||
|
"By default, the last argument is the head of every abstract syntax",
|
||||||
|
"function; moreover, the head depends on the head of the function above.",
|
||||||
|
"The graph can be saved in a file by the wf command as usual.",
|
||||||
|
"If the -view flag is defined, the graph is saved in a temporary file",
|
||||||
|
"which is processed by graphviz and displayed by the program indicated",
|
||||||
|
"by the flag. The target format is png, unless overridden by the",
|
||||||
|
"flag -format."
|
||||||
|
],
|
||||||
|
exec = \env@(pgf, mos) opts es -> do
|
||||||
|
let debug = isOpt "v" opts
|
||||||
|
let file = valStrOpts "file" "" opts
|
||||||
|
let outp = valStrOpts "output" "dot" opts
|
||||||
|
mlab <- case file of
|
||||||
|
"" -> return Nothing
|
||||||
|
_ -> (Just . H.getDepLabels . lines) `fmap` restricted (readFile file)
|
||||||
|
let lang = optLang pgf opts
|
||||||
|
let grphs = unlines $ map (H.graphvizDependencyTree outp debug mlab Nothing pgf lang) es
|
||||||
|
if isFlag "view" opts || isFlag "format" opts then do
|
||||||
|
let file s = "_grphd." ++ s
|
||||||
|
let view = optViewGraph opts
|
||||||
|
let format = optViewFormat opts
|
||||||
|
restricted $ writeUTF8File (file "dot") grphs
|
||||||
|
restrictedSystem $ "dot -T" ++ format ++ " " ++ file "dot" ++ " > " ++ file format
|
||||||
|
restrictedSystem $ view ++ " " ++ file format
|
||||||
|
return void
|
||||||
|
else return $ fromString grphs,
|
||||||
|
examples = [
|
||||||
|
mkEx "gr | vd -- generate a tree and show dependency tree in .dot",
|
||||||
|
mkEx "gr | vd -view=open -- generate a tree and display dependency tree on a Mac",
|
||||||
|
mkEx "gr -number=1000 | vd -file=dep.labels -output=malt -- generate training treebank",
|
||||||
|
mkEx "gr -number=100 | vd -file=dep.labels -output=malt_input -- generate test sentences"
|
||||||
|
],
|
||||||
|
options = [
|
||||||
|
("v","show extra information")
|
||||||
|
],
|
||||||
|
flags = [
|
||||||
|
("file","configuration file for labels per fun, format 'fun l1 ... label ... l2'"),
|
||||||
|
("format","format of the visualization file (default \"png\")"),
|
||||||
|
("output","output format of graph source (default \"dot\")"),
|
||||||
|
("view","program to open the resulting file (default \"open\")"),
|
||||||
|
("lang","the language of analysis")
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
-}
|
||||||
|
|
||||||
|
("vp", emptyCommandInfo {
|
||||||
|
longname = "visualize_parse",
|
||||||
|
synopsis = "show parse tree graphically",
|
||||||
|
explanation = unlines [
|
||||||
|
"Prints a parse tree in the .dot format (the graphviz format).",
|
||||||
|
"The graph can be saved in a file by the wf command as usual.",
|
||||||
|
"If the -view flag is defined, the graph is saved in a temporary file",
|
||||||
|
"which is processed by graphviz and displayed by the program indicated",
|
||||||
|
"by the flag. The target format is png, unless overridden by the",
|
||||||
|
"flag -format."
|
||||||
|
],
|
||||||
|
exec = needPGF $ \opts arg env@(pgf, concs) ->
|
||||||
|
do let es = toExprs arg
|
||||||
|
let concs = optConcs env opts
|
||||||
|
|
||||||
|
let gvOptions=graphvizDefaults{noLeaves = isOpt "noleaves" opts && not (isOpt "showleaves" opts),
|
||||||
|
noFun = isOpt "nofun" opts || not (isOpt "showfun" opts),
|
||||||
|
noCat = isOpt "nocat" opts && not (isOpt "showcat" opts),
|
||||||
|
nodeFont = valStrOpts "nodefont" "" opts,
|
||||||
|
leafFont = valStrOpts "leaffont" "" opts,
|
||||||
|
nodeColor = valStrOpts "nodecolor" "" opts,
|
||||||
|
leafColor = valStrOpts "leafcolor" "" opts,
|
||||||
|
nodeEdgeStyle = valStrOpts "nodeedgestyle" "solid" opts,
|
||||||
|
leafEdgeStyle = valStrOpts "leafedgestyle" "dashed" opts
|
||||||
|
}
|
||||||
|
|
||||||
|
let grph= if null es || null concs
|
||||||
|
then []
|
||||||
|
else graphvizParseTree (snd (head concs)) gvOptions (cExpr (head es))
|
||||||
|
if isFlag "view" opts || isFlag "format" opts then do
|
||||||
|
let file s = "_grph." ++ s
|
||||||
|
let view = optViewGraph opts
|
||||||
|
let format = optViewFormat opts
|
||||||
|
restricted $ writeUTF8File (file "dot") grph
|
||||||
|
restrictedSystem $ "dot -T" ++ format ++ " " ++ file "dot" ++ " > " ++ file format
|
||||||
|
restrictedSystem $ view ++ " " ++ file format
|
||||||
|
return void
|
||||||
|
else return $ fromString grph,
|
||||||
|
examples = [
|
||||||
|
mkEx "p -lang=Eng \"John walks\" | vp -- generate a tree and show parse tree as .dot script",
|
||||||
|
mkEx "gr | vp -view=\"open\" -- generate a tree and display parse tree on a Mac"
|
||||||
|
],
|
||||||
|
options = [
|
||||||
|
("showcat","show categories in the tree nodes (default)"),
|
||||||
|
("nocat","don't show categories"),
|
||||||
|
("showfun","show function names in the tree nodes"),
|
||||||
|
("nofun","don't show function names (default)"),
|
||||||
|
("showleaves","show the leaves of the tree (default)"),
|
||||||
|
("noleaves","don't show the leaves of the tree (i.e., only the abstract tree)")
|
||||||
|
],
|
||||||
|
flags = [
|
||||||
|
("lang","the language to visualize"),
|
||||||
|
("format","format of the visualization file (default \"png\")"),
|
||||||
|
("view","program to open the resulting file (default \"open\")"),
|
||||||
|
("nodefont","font for tree nodes (default: Times -- graphviz standard font)"),
|
||||||
|
("leaffont","font for tree leaves (default: nodefont)"),
|
||||||
|
("nodecolor","color for tree nodes (default: black -- graphviz standard color)"),
|
||||||
|
("leafcolor","color for tree leaves (default: nodecolor)"),
|
||||||
|
("nodeedgestyle","edge style between tree nodes (solid/dashed/dotted/bold, default: solid)"),
|
||||||
|
("leafedgestyle","edge style for links to leaves (solid/dashed/dotted/bold, default: dashed)")
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
|
||||||
|
("vt", emptyCommandInfo {
|
||||||
|
longname = "visualize_tree",
|
||||||
|
synopsis = "show a set of trees graphically",
|
||||||
|
explanation = unlines [
|
||||||
|
"Prints a set of trees in the .dot format (the graphviz format).",
|
||||||
|
"The graph can be saved in a file by the wf command as usual.",
|
||||||
|
"If the -view flag is defined, the graph is saved in a temporary file",
|
||||||
|
"which is processed by graphviz and displayed by the program indicated",
|
||||||
|
"by the flag. The target format is postscript, unless overridden by the",
|
||||||
|
"flag -format."
|
||||||
|
],
|
||||||
|
exec = needPGF $ \opts arg env@(pgf, _) ->
|
||||||
|
let es = toExprs arg in
|
||||||
|
if isOpt "api" opts
|
||||||
|
then do
|
||||||
|
mapM_ (putStrLn . exprToAPI) es
|
||||||
|
return void
|
||||||
|
else do
|
||||||
|
let gvOptions=graphvizDefaults{noFun = isOpt "nofun" opts,
|
||||||
|
noCat = isOpt "nocat" opts,
|
||||||
|
nodeFont = valStrOpts "nodefont" "" opts,
|
||||||
|
nodeColor = valStrOpts "nodecolor" "" opts,
|
||||||
|
nodeEdgeStyle = valStrOpts "nodeedgestyle" "solid" opts
|
||||||
|
}
|
||||||
|
let grph = unlines (map (graphvizAbstractTree pgf gvOptions . cExpr) es)
|
||||||
|
if isFlag "view" opts || isFlag "format" opts then do
|
||||||
|
let file s = "_grph." ++ s
|
||||||
|
let view = optViewGraph opts
|
||||||
|
let format = optViewFormat opts
|
||||||
|
restricted $ writeUTF8File (file "dot") grph
|
||||||
|
restrictedSystem $ "dot -T" ++ format ++ " " ++ file "dot" ++ " > " ++ file format
|
||||||
|
restrictedSystem $ view ++ " " ++ file format
|
||||||
|
return void
|
||||||
|
else return $ fromString grph,
|
||||||
|
examples = [
|
||||||
|
mkEx "p \"hello\" | vt -- parse a string and show trees as graph script",
|
||||||
|
mkEx "p \"hello\" | vt -view=\"open\" -- parse a string and display trees on a Mac"
|
||||||
|
],
|
||||||
|
options = [
|
||||||
|
("api", "show the tree with function names converted to 'mkC' with value cats C"),
|
||||||
|
("nofun","don't show functions but only categories"),
|
||||||
|
("nocat","don't show categories but only functions")
|
||||||
|
],
|
||||||
|
flags = [
|
||||||
|
("format","format of the visualization file (default \"png\")"),
|
||||||
|
("view","program to open the resulting file (default \"open\")"),
|
||||||
|
("nodefont","font for tree nodes (default: Times -- graphviz standard font)"),
|
||||||
|
("nodecolor","color for tree nodes (default: black -- graphviz standard color)"),
|
||||||
|
("nodeedgestyle","edge style between tree nodes (solid/dashed/dotted/bold, default: solid)")
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
|
||||||
|
("ai", emptyCommandInfo {
|
||||||
|
longname = "abstract_info",
|
||||||
|
syntax = "ai IDENTIFIER or ai EXPR",
|
||||||
|
synopsis = "Provides an information about a function, an expression or a category from the abstract syntax",
|
||||||
|
explanation = unlines [
|
||||||
|
"The command has one argument which is either function, expression or",
|
||||||
|
"a category defined in the abstract syntax of the current grammar. ",
|
||||||
|
"If the argument is a function then its type is printed out.",
|
||||||
|
"If it is a category then the category definition is printed.",
|
||||||
|
"If a whole expression is given it prints the expression with refined",
|
||||||
|
"metavariables and the type of the expression."
|
||||||
|
],
|
||||||
|
exec = needPGF $ \opts args env@(pgf,cncs) ->
|
||||||
|
case map cExpr (toExprs args) of
|
||||||
|
[e] -> case unApp e of
|
||||||
|
Just (id,[]) -> return (fromString
|
||||||
|
(case functionType pgf id of
|
||||||
|
Just ty -> showFun id ty
|
||||||
|
Nothing -> let funs = functionsByCat pgf id
|
||||||
|
in showCat id funs))
|
||||||
|
where
|
||||||
|
showCat c funs = "cat "++c++
|
||||||
|
" ;\n\n"++
|
||||||
|
unlines [showFun f ty| f<-funs,
|
||||||
|
Just ty <- [functionType pgf f]]
|
||||||
|
showFun f ty = "fun "++f++" : "++showType [] ty++" ;"
|
||||||
|
_ -> case inferExpr pgf e of
|
||||||
|
Left msg -> error msg
|
||||||
|
Right (e,ty) -> do putStrLn ("Expression: "++PGF2.showExpr [] e)
|
||||||
|
putStrLn ("Type: "++PGF2.showType [] ty)
|
||||||
|
putStrLn ("Probability: "++show (treeProbability pgf e))
|
||||||
|
return void
|
||||||
|
_ -> do putStrLn "a single function name or category name is expected"
|
||||||
|
return void,
|
||||||
|
needsTypeCheck = False
|
||||||
|
})
|
||||||
|
]
|
||||||
|
where
|
||||||
|
cParse env@(pgf,_) opts ss =
|
||||||
|
parsed [ parse cnc cat s | s<-ss,(lang,cnc)<-cncs]
|
||||||
|
where
|
||||||
|
cat = optType pgf opts
|
||||||
|
cncs = optConcs env opts
|
||||||
|
parsed rs = Piped (Exprs ts,unlines msgs)
|
||||||
|
where
|
||||||
|
ts = [hsExpr t|ParseOk ts<-rs,(t,p)<-takeOptNum opts ts]
|
||||||
|
msgs = concatMap mkMsg rs
|
||||||
|
|
||||||
|
mkMsg (ParseOk ts) = (map (PGF2.showExpr [] . fst).takeOptNum opts) ts
|
||||||
|
mkMsg (ParseFailed _ tok) = ["Parse failed: "++tok]
|
||||||
|
mkMsg (ParseIncomplete) = ["The sentence is incomplete"]
|
||||||
|
|
||||||
|
optLins env opts ts = case opts of
|
||||||
|
_ | isOpt "groups" opts ->
|
||||||
|
concatMap snd $ groupResults
|
||||||
|
[[(lang, s) | (lang,concr) <- optConcs env opts,s <- linear opts lang concr t] | t <- ts]
|
||||||
|
_ -> concatMap (optLin env opts) ts
|
||||||
|
optLin env@(pgf,_) opts t =
|
||||||
|
case opts of
|
||||||
|
_ | isOpt "treebank" opts ->
|
||||||
|
(abstractName pgf ++ ": " ++ PGF2.showExpr [] t) :
|
||||||
|
[lang ++ ": " ++ s | (lang,concr) <- optConcs env opts, s<-linear opts lang concr t]
|
||||||
|
_ -> [s | (lang,concr) <- optConcs env opts, s<-linear opts lang concr t]
|
||||||
|
|
||||||
|
linear :: [Option] -> ConcName -> Concr -> PGF2.Expr -> [String]
|
||||||
|
linear opts lang concr = case opts of
|
||||||
|
_ | isOpt "all" opts -> concat . map (map snd) . tabularLinearizeAll concr
|
||||||
|
_ | isOpt "list" opts -> (:[]) . commaList .
|
||||||
|
concatMap (map snd) . tabularLinearizeAll concr
|
||||||
|
_ | isOpt "table" opts -> concatMap (map (\(p,v) -> p+++":"+++v)) . tabularLinearizeAll concr
|
||||||
|
_ | isOpt "bracket" opts -> (:[]) . unwords . map showBracketedString . bracketedLinearize concr
|
||||||
|
_ -> (:[]) . linearize concr
|
||||||
|
|
||||||
|
groupResults :: [[(ConcName,String)]] -> [(ConcName,[String])]
|
||||||
|
groupResults = Map.toList . foldr more Map.empty . start . concat
|
||||||
|
where
|
||||||
|
start ls = [(l,[s]) | (l,s) <- ls]
|
||||||
|
more (l,s) =
|
||||||
|
Map.insertWith (\ [x] xs -> if elem x xs then xs else (x : xs)) l s
|
||||||
|
|
||||||
|
optConcs = optConcsFlag "lang"
|
||||||
|
|
||||||
|
optConcsFlag f (pgf,cncs) opts =
|
||||||
|
case valStrOpts f "" opts of
|
||||||
|
"" -> Map.toList cncs
|
||||||
|
lang -> mapMaybe pickLang (chunks ',' lang)
|
||||||
|
where
|
||||||
|
pickLang l = pick l `mplus` pick fl
|
||||||
|
where
|
||||||
|
fl = abstractName pgf++l
|
||||||
|
pick l = (,) l `fmap` Map.lookup l cncs
|
||||||
|
|
||||||
|
{-
|
||||||
|
-- replace each non-atomic constructor with mkC, where C is the val cat
|
||||||
|
tree2mk pgf = H.showExpr [] . t2m where
|
||||||
|
t2m t = case H.unApp t of
|
||||||
|
Just (cid,ts@(_:_)) -> H.mkApp (mk cid) (map t2m ts)
|
||||||
|
_ -> t
|
||||||
|
mk = H.mkCId . ("mk" ++) . H.showCId . H.lookValCat (H.abstract pgf)
|
||||||
|
|
||||||
|
unlex opts lang = stringOps Nothing (getUnlex opts lang ++ map prOpt opts) ----
|
||||||
|
|
||||||
|
getUnlex opts lang = case words (valStrOpts "unlexer" "" opts) of
|
||||||
|
lexs -> case lookup lang
|
||||||
|
[(H.mkCId la,tail le) | lex <- lexs, let (la,le) = span (/='=') lex, not (null le)] of
|
||||||
|
Just le -> chunks ',' le
|
||||||
|
_ -> []
|
||||||
|
-}
|
||||||
|
commaList [] = []
|
||||||
|
commaList ws = concat $ head ws : map (", " ++) (tail ws)
|
||||||
|
|
||||||
|
optFile opts = valStrOpts "file" "_gftmp" opts
|
||||||
|
|
||||||
|
optType pgf opts =
|
||||||
|
case listFlags "cat" opts of
|
||||||
|
v:_ -> let str = valueString v
|
||||||
|
in case readType str of
|
||||||
|
Just ty -> case checkType pgf ty of
|
||||||
|
Left msg -> error msg
|
||||||
|
Right ty -> ty
|
||||||
|
Nothing -> error ("Can't parse '"++str++"' as a type")
|
||||||
|
_ -> startCat pgf
|
||||||
|
|
||||||
|
optViewFormat opts = valStrOpts "format" "png" opts
|
||||||
|
optViewGraph opts = valStrOpts "view" "open" opts
|
||||||
|
{-
|
||||||
|
optNum opts = valIntOpts "number" 1 opts
|
||||||
|
-}
|
||||||
|
optNumInf opts = valIntOpts "number" 1000000000 opts ---- 10^9
|
||||||
|
takeOptNum opts = take (optNumInf opts)
|
||||||
|
|
||||||
|
returnFromCExprs = returnFromExprs . map hsExpr
|
||||||
|
returnFromExprs es =
|
||||||
|
return $ case es of
|
||||||
|
[] -> pipeMessage "no trees found"
|
||||||
|
_ -> fromExprs es
|
||||||
|
|
||||||
|
prGrammar env@(pgf,cncs) opts
|
||||||
|
| isOpt "langs" opts = return . fromString . unwords $ (map fst (optConcs env opts))
|
||||||
|
| isOpt "cats" opts = return . fromString . unwords $ categories pgf
|
||||||
|
| isOpt "funs" opts = return . fromString . unwords $ functions pgf
|
||||||
|
| isOpt "missing" opts = return . fromString . unwords $
|
||||||
|
[f | f <- functions pgf, not (and [hasLinearization concr f | (_,concr) <- optConcs env opts])]
|
||||||
|
| isOpt "fullform" opts = return $ fromString $ concatMap (prFullFormLexicon . snd) $ optConcs env opts
|
||||||
|
| isOpt "words" opts = return $ fromString $ concatMap (prAllWords . snd) $ optConcs env opts
|
||||||
|
| isOpt "lexc" opts = return $ fromString $ concatMap (prLexcLexicon . snd) $ optConcs env opts
|
||||||
|
| otherwise = return void
|
||||||
|
|
||||||
|
gizaAlignment pgf src_cnc tgt_cnc e =
|
||||||
|
let src_res = alignWords src_cnc e
|
||||||
|
tgt_res = alignWords tgt_cnc e
|
||||||
|
alignment = [show i++"-"++show j | (i,(_,src_fids)) <- zip [0..] src_res, (j,(_,tgt_fids)) <- zip [0..] tgt_res, not (null (intersect src_fids tgt_fids))]
|
||||||
|
in (unwords (map fst src_res), unwords (map fst tgt_res), unwords alignment)
|
||||||
|
|
||||||
|
morphos env opts s =
|
||||||
|
[(s,res) | (lang,concr) <- optConcs env opts, let res = lookupMorpho concr s, not (null res)]
|
||||||
|
{-
|
||||||
|
mexp xs = case xs of
|
||||||
|
t:_ -> Just t
|
||||||
|
_ -> Nothing
|
||||||
|
-}
|
||||||
|
-- ps -f -g s returns g (f s)
|
||||||
|
{-
|
||||||
|
treeOps pgf opts s = foldr app s (reverse opts) where
|
||||||
|
app (OOpt op) | Just (Left f) <- treeOp pgf op = f
|
||||||
|
app (OFlag op (VId x)) | Just (Right f) <- treeOp pgf op = f (H.mkCId x)
|
||||||
|
app _ = id
|
||||||
|
|
||||||
|
treeOpOptions pgf = [(op,expl) | (op,(expl,Left _)) <- allTreeOps pgf]
|
||||||
|
treeOpFlags pgf = [(op,expl) | (op,(expl,Right _)) <- allTreeOps pgf]
|
||||||
|
|
||||||
|
translationQuiz :: Maybe H.Expr -> H.PGF -> H.Language -> H.Language -> H.Type -> IO ()
|
||||||
|
translationQuiz mex pgf ig og typ = do
|
||||||
|
tts <- translationList mex pgf ig og typ infinity
|
||||||
|
mkQuiz "Welcome to GF Translation Quiz." tts
|
||||||
|
|
||||||
|
morphologyQuiz :: Maybe H.Expr -> H.PGF -> H.Language -> H.Type -> IO ()
|
||||||
|
morphologyQuiz mex pgf ig typ = do
|
||||||
|
tts <- morphologyList mex pgf ig typ infinity
|
||||||
|
mkQuiz "Welcome to GF Morphology Quiz." tts
|
||||||
|
|
||||||
|
-- | the maximal number of precompiled quiz problems
|
||||||
|
infinity :: Int
|
||||||
|
infinity = 256
|
||||||
|
-}
|
||||||
|
prLexcLexicon :: Concr -> String
|
||||||
|
prLexcLexicon concr =
|
||||||
|
unlines $ "Multichar_Symbols":multichars:"":"LEXICON Root" : [prLexc l p ++ ":" ++ w ++ " # ;" | (w,lps) <- morpho, (l,p,_) <- lps] ++ ["END"]
|
||||||
|
where
|
||||||
|
morpho = fullFormLexicon concr
|
||||||
|
prLexc l p = l ++ concat (mkTags (words p))
|
||||||
|
mkTags p = case p of
|
||||||
|
"s":ws -> mkTags ws --- remove record field
|
||||||
|
ws -> map ('+':) ws
|
||||||
|
|
||||||
|
multichars = unwords $ nub $ concat [mkTags (words p) | (w,lps) <- morpho, (l,p,_) <- lps]
|
||||||
|
-- thick_A+(AAdj+Posit+Gen):thick's # ;
|
||||||
|
|
||||||
|
prFullFormLexicon :: Concr -> String
|
||||||
|
prFullFormLexicon concr =
|
||||||
|
unlines (map prMorphoAnalysis (fullFormLexicon concr))
|
||||||
|
|
||||||
|
prAllWords :: Concr -> String
|
||||||
|
prAllWords concr =
|
||||||
|
unwords [w | (w,_) <- fullFormLexicon concr]
|
||||||
|
|
||||||
|
prMorphoAnalysis :: (String,[MorphoAnalysis]) -> String
|
||||||
|
prMorphoAnalysis (w,lps) =
|
||||||
|
unlines (w:[fun ++ " : " ++ cat | (fun,cat,p) <- lps])
|
||||||
|
|
||||||
|
hsExpr c =
|
||||||
|
case unApp c of
|
||||||
|
Just (f,cs) -> H.mkApp (H.mkCId f) (map hsExpr cs)
|
||||||
|
_ -> case unStr c of
|
||||||
|
Just str -> H.mkStr str
|
||||||
|
_ -> case unInt c of
|
||||||
|
Just n -> H.mkInt n
|
||||||
|
_ -> case unFloat c of
|
||||||
|
Just d -> H.mkFloat d
|
||||||
|
_ -> error $ "GF.Command.Commands2.hsExpr "++show c
|
||||||
|
|
||||||
|
cExpr e =
|
||||||
|
case H.unApp e of
|
||||||
|
Just (f,es) -> mkApp (H.showCId f) (map cExpr es)
|
||||||
|
_ -> case H.unStr e of
|
||||||
|
Just str -> mkStr str
|
||||||
|
_ -> case H.unInt e of
|
||||||
|
Just n -> mkInt n
|
||||||
|
_ -> case H.unFloat e of
|
||||||
|
Just d -> mkFloat d
|
||||||
|
_ -> error $ "GF.Command.Commands2.cExpr "++show e
|
||||||
|
|
||||||
|
needPGF exec opts ts =
|
||||||
|
do Env mb_pgf cncs <- getPGFEnv
|
||||||
|
case mb_pgf of
|
||||||
|
Just pgf -> liftSIO $ exec opts ts (pgf,cncs)
|
||||||
|
_ -> fail "Import a grammar before using this command"
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
-- elsewhere
|
-- elsewhere
|
||||||
module GF.Command.CommonCommands where
|
module GF.Command.CommonCommands where
|
||||||
import Data.List(sort)
|
import Data.List(sort)
|
||||||
|
import Data.Char (isSpace)
|
||||||
import GF.Command.CommandInfo
|
import GF.Command.CommandInfo
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
import GF.Infra.SIO
|
import GF.Infra.SIO
|
||||||
@@ -14,9 +15,8 @@ import GF.Command.Abstract --(isOpt,valStrOpts,prOpt)
|
|||||||
import GF.Text.Pretty
|
import GF.Text.Pretty
|
||||||
import GF.Text.Transliterations
|
import GF.Text.Transliterations
|
||||||
import GF.Text.Lexing(stringOp,opInEnv)
|
import GF.Text.Lexing(stringOp,opInEnv)
|
||||||
import Data.Char (isSpace)
|
|
||||||
|
|
||||||
import PGF2(showExpr)
|
import qualified PGF as H(showCId,showExpr,toATree,toTrie,Trie(..))
|
||||||
|
|
||||||
extend old new = Map.union (Map.fromList new) old -- Map.union is left-biased
|
extend old new = Map.union (Map.fromList new) old -- Map.union is left-biased
|
||||||
|
|
||||||
@@ -102,7 +102,9 @@ commonCommands = fmap (mapCommandExec liftSIO) $ Map.fromList [
|
|||||||
"To see transliteration tables, use command ut."
|
"To see transliteration tables, use command ut."
|
||||||
],
|
],
|
||||||
examples = [
|
examples = [
|
||||||
|
-- mkEx "l (EAdd 3 4) | ps -code -- linearize code-like output",
|
||||||
mkEx "l (EAdd 3 4) | ps -unlexcode -- linearize code-like output",
|
mkEx "l (EAdd 3 4) | ps -unlexcode -- linearize code-like output",
|
||||||
|
-- mkEx "ps -lexer=code | p -cat=Exp -- parse code-like input",
|
||||||
mkEx "ps -lexcode | p -cat=Exp -- parse code-like input",
|
mkEx "ps -lexcode | p -cat=Exp -- parse code-like input",
|
||||||
mkEx "gr -cat=QCl | l | ps -bind -- linearization output from LangFin",
|
mkEx "gr -cat=QCl | l | ps -bind -- linearization output from LangFin",
|
||||||
mkEx "ps -to_devanagari \"A-p\" -- show Devanagari in UTF8 terminal",
|
mkEx "ps -to_devanagari \"A-p\" -- show Devanagari in UTF8 terminal",
|
||||||
@@ -115,11 +117,13 @@ commonCommands = fmap (mapCommandExec liftSIO) $ Map.fromList [
|
|||||||
let (os,fs) = optsAndFlags opts
|
let (os,fs) = optsAndFlags opts
|
||||||
trans <- optTranslit opts
|
trans <- optTranslit opts
|
||||||
|
|
||||||
if isOpt "lines" opts
|
case opts of
|
||||||
then return $ fromStrings $ map (trans . stringOps (envFlag fs) (map prOpt os)) $ toStrings x
|
_ | isOpt "lines" opts -> return $ fromStrings $ map (trans . stringOps (envFlag fs) (map prOpt os)) $ toStrings x
|
||||||
else return ((fromString . trans . stringOps (envFlag fs) (map prOpt os) . toString) x),
|
_ | isOpt "paragraphs" opts -> return $ fromStrings $ map (trans . stringOps (envFlag fs) (map prOpt os)) $ toParagraphs $ toStrings x
|
||||||
|
_ -> return ((fromString . trans . stringOps (envFlag fs) (map prOpt os) . toString) x),
|
||||||
options = [
|
options = [
|
||||||
("lines","apply the operation separately to each input line, returning a list of lines")
|
("lines","apply the operation separately to each input line, returning a list of lines"),
|
||||||
|
("paragraphs","apply separately to each input paragraph (as separated by empty lines), returning a list of lines")
|
||||||
] ++
|
] ++
|
||||||
stringOpOptions,
|
stringOpOptions,
|
||||||
flags = [
|
flags = [
|
||||||
@@ -166,8 +170,7 @@ commonCommands = fmap (mapCommandExec liftSIO) $ Map.fromList [
|
|||||||
restrictedSystem $ syst ++ " <" ++ tmpi ++ " >" ++ tmpo
|
restrictedSystem $ syst ++ " <" ++ tmpi ++ " >" ++ tmpo
|
||||||
fmap fromString $ restricted $ readFile tmpo,
|
fmap fromString $ restricted $ readFile tmpo,
|
||||||
-}
|
-}
|
||||||
fmap (fromStrings . lines) . restricted . readShellProcess syst . unlines . map (dropWhile (=='\n')) $ toStrings $ arg,
|
fmap fromString . restricted . readShellProcess syst $ toString arg,
|
||||||
|
|
||||||
flags = [
|
flags = [
|
||||||
("command","the system command applied to the argument")
|
("command","the system command applied to the argument")
|
||||||
],
|
],
|
||||||
@@ -175,6 +178,12 @@ commonCommands = fmap (mapCommandExec liftSIO) $ Map.fromList [
|
|||||||
mkEx "gt | l | ? wc -- generate trees, linearize, and count words"
|
mkEx "gt | l | ? wc -- generate trees, linearize, and count words"
|
||||||
]
|
]
|
||||||
}),
|
}),
|
||||||
|
("tt", emptyCommandInfo {
|
||||||
|
longname = "to_trie",
|
||||||
|
syntax = "to_trie",
|
||||||
|
synopsis = "combine a list of trees into a trie",
|
||||||
|
exec = \ _ -> return . fromString . trie . toExprs
|
||||||
|
}),
|
||||||
("ut", emptyCommandInfo {
|
("ut", emptyCommandInfo {
|
||||||
longname = "unicode_table",
|
longname = "unicode_table",
|
||||||
synopsis = "show a transliteration table for a unicode character set",
|
synopsis = "show a transliteration table for a unicode character set",
|
||||||
@@ -222,6 +231,7 @@ envFlag fs =
|
|||||||
_ -> Nothing
|
_ -> Nothing
|
||||||
|
|
||||||
stringOpOptions = sort $ [
|
stringOpOptions = sort $ [
|
||||||
|
("bind","bind tokens separated by Prelude.BIND, i.e. &+"),
|
||||||
("chars","lexer that makes every non-space character a token"),
|
("chars","lexer that makes every non-space character a token"),
|
||||||
("from_cp1251","decode from cp1251 (Cyrillic used in Bulgarian resource)"),
|
("from_cp1251","decode from cp1251 (Cyrillic used in Bulgarian resource)"),
|
||||||
("from_utf8","decode from utf8 (default)"),
|
("from_utf8","decode from utf8 (default)"),
|
||||||
@@ -246,6 +256,27 @@ stringOpOptions = sort $ [
|
|||||||
("to_" ++ p, "from GF " ++ n ++ " transliteration to unicode")] |
|
("to_" ++ p, "from GF " ++ n ++ " transliteration to unicode")] |
|
||||||
(p,n) <- transliterationPrintNames]
|
(p,n) <- transliterationPrintNames]
|
||||||
|
|
||||||
|
trie = render . pptss . H.toTrie . map H.toATree
|
||||||
|
where
|
||||||
|
pptss [ts] = "*"<+>nest 2 (ppts ts)
|
||||||
|
pptss tss = vcat [i<+>nest 2 (ppts ts)|(i,ts)<-zip [(1::Int)..] tss]
|
||||||
|
|
||||||
|
ppts = vcat . map ppt
|
||||||
|
|
||||||
|
ppt t =
|
||||||
|
case t of
|
||||||
|
H.Oth e -> pp (H.showExpr [] e)
|
||||||
|
H.Ap f [[]] -> pp (H.showCId f)
|
||||||
|
H.Ap f tss -> H.showCId f $$ nest 2 (pptss tss)
|
||||||
|
|
||||||
-- ** Converting command input
|
-- ** Converting command input
|
||||||
toString = unwords . toStrings
|
toString = unwords . toStrings
|
||||||
toLines = unlines . toStrings
|
toLines = unlines . toStrings
|
||||||
|
|
||||||
|
toParagraphs = map (unwords . words) . toParas
|
||||||
|
where
|
||||||
|
toParas ls = case break (all isSpace) ls of
|
||||||
|
([],[]) -> []
|
||||||
|
([],_:ll) -> toParas ll
|
||||||
|
(l, []) -> [unwords l]
|
||||||
|
(l, _:ll) -> unwords l : toParas ll
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
module GF.Command.Importing (importGrammar, importSource) where
|
module GF.Command.Importing (importGrammar, importSource) where
|
||||||
|
|
||||||
import PGF2
|
import PGF
|
||||||
import PGF2.Internal(unionPGF)
|
import PGF.Internal(optimizePGF,unionPGF,msgUnionPGF)
|
||||||
|
|
||||||
import GF.Compile
|
import GF.Compile
|
||||||
import GF.Compile.Multi (readMulti)
|
import GF.Compile.Multi (readMulti)
|
||||||
@@ -17,16 +17,14 @@ import GF.Data.ErrM
|
|||||||
|
|
||||||
import System.FilePath
|
import System.FilePath
|
||||||
import qualified Data.Set as Set
|
import qualified Data.Set as Set
|
||||||
import qualified Data.Map as Map
|
|
||||||
import Control.Monad(foldM)
|
|
||||||
|
|
||||||
-- import a grammar in an environment where it extends an existing grammar
|
-- import a grammar in an environment where it extends an existing grammar
|
||||||
importGrammar :: Maybe PGF -> Options -> [FilePath] -> IO (Maybe PGF)
|
importGrammar :: PGF -> Options -> [FilePath] -> IO PGF
|
||||||
importGrammar pgf0 _ [] = return pgf0
|
importGrammar pgf0 _ [] = return pgf0
|
||||||
importGrammar pgf0 opts files =
|
importGrammar pgf0 opts files =
|
||||||
case takeExtensions (last files) of
|
case takeExtensions (last files) of
|
||||||
".cf" -> fmap Just $ importCF opts files getBNFCRules bnfc2cf
|
".cf" -> importCF opts files getBNFCRules bnfc2cf
|
||||||
".ebnf" -> fmap Just $ importCF opts files getEBNFRules ebnf2cf
|
".ebnf" -> importCF opts files getEBNFRules ebnf2cf
|
||||||
".gfm" -> do
|
".gfm" -> do
|
||||||
ascss <- mapM readMulti files
|
ascss <- mapM readMulti files
|
||||||
let cs = concatMap snd ascss
|
let cs = concatMap snd ascss
|
||||||
@@ -38,15 +36,14 @@ importGrammar pgf0 opts files =
|
|||||||
Bad msg -> do putStrLn ('\n':'\n':msg)
|
Bad msg -> do putStrLn ('\n':'\n':msg)
|
||||||
return pgf0
|
return pgf0
|
||||||
".pgf" -> do
|
".pgf" -> do
|
||||||
mapM readPGF files >>= foldM ioUnionPGF pgf0
|
pgf2 <- mapM readPGF files >>= return . foldl1 unionPGF
|
||||||
|
ioUnionPGF pgf0 pgf2
|
||||||
ext -> die $ "Unknown filename extension: " ++ show ext
|
ext -> die $ "Unknown filename extension: " ++ show ext
|
||||||
|
|
||||||
ioUnionPGF :: Maybe PGF -> PGF -> IO (Maybe PGF)
|
ioUnionPGF :: PGF -> PGF -> IO PGF
|
||||||
ioUnionPGF Nothing two = return (Just two)
|
ioUnionPGF one two = case msgUnionPGF one two of
|
||||||
ioUnionPGF (Just one) two =
|
(pgf, Just msg) -> putStrLn msg >> return pgf
|
||||||
case unionPGF one two of
|
(pgf,_) -> return pgf
|
||||||
Nothing -> putStrLn "Abstract changed, previous concretes discarded." >> return (Just two)
|
|
||||||
Just pgf -> return (Just pgf)
|
|
||||||
|
|
||||||
importSource :: Options -> [FilePath] -> IO SourceGrammar
|
importSource :: Options -> [FilePath] -> IO SourceGrammar
|
||||||
importSource opts files = fmap (snd.snd) (batchCompile opts files)
|
importSource opts files = fmap (snd.snd) (batchCompile opts files)
|
||||||
@@ -59,6 +56,7 @@ importCF opts files get convert = impCF
|
|||||||
startCat <- case rules of
|
startCat <- case rules of
|
||||||
(Rule cat _ _ : _) -> return cat
|
(Rule cat _ _ : _) -> return cat
|
||||||
_ -> fail "empty CFG"
|
_ -> fail "empty CFG"
|
||||||
probs <- maybe (return Map.empty) readProbabilitiesFromFile (flag optProbsFile opts)
|
let pgf = cf2pgf (last files) (mkCFG startCat Set.empty rules)
|
||||||
let pgf = cf2pgf opts (last files) (mkCFG startCat Set.empty rules) probs
|
probs <- maybe (return . defaultProbabilities) readProbabilitiesFromFile (flag optProbsFile opts) pgf
|
||||||
return pgf
|
return $ setProbabilities probs
|
||||||
|
$ if flag optOptimizePGF opts then optimizePGF pgf else pgf
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ module GF.Command.Interpreter (
|
|||||||
import GF.Command.CommandInfo
|
import GF.Command.CommandInfo
|
||||||
import GF.Command.Abstract
|
import GF.Command.Abstract
|
||||||
import GF.Command.Parse
|
import GF.Command.Parse
|
||||||
|
import PGF.Internal(Expr(..))
|
||||||
import GF.Infra.UseIO(putStrLnE)
|
import GF.Infra.UseIO(putStrLnE)
|
||||||
import PGF2
|
|
||||||
|
|
||||||
import Control.Monad(when)
|
import Control.Monad(when)
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
@@ -56,8 +56,17 @@ interpretPipe env cs = do
|
|||||||
-- | macro definition applications: replace ?i by (exps !! i)
|
-- | macro definition applications: replace ?i by (exps !! i)
|
||||||
appCommand :: CommandArguments -> Command -> Command
|
appCommand :: CommandArguments -> Command -> Command
|
||||||
appCommand args c@(Command i os arg) = case arg of
|
appCommand args c@(Command i os arg) = case arg of
|
||||||
AExpr e -> Command i os (AExpr (exprSubstitute e (toExprs args)))
|
AExpr e -> Command i os (AExpr (app e))
|
||||||
_ -> c
|
_ -> c
|
||||||
|
where
|
||||||
|
xs = toExprs args
|
||||||
|
|
||||||
|
app e = case e of
|
||||||
|
EAbs b x e -> EAbs b x (app e)
|
||||||
|
EApp e1 e2 -> EApp (app e1) (app e2)
|
||||||
|
ELit l -> ELit l
|
||||||
|
EMeta i -> xs !! i
|
||||||
|
EFun x -> EFun x
|
||||||
|
|
||||||
-- | return the trees to be sent in pipe, and the output possibly printed
|
-- | return the trees to be sent in pipe, and the output possibly printed
|
||||||
--interpret :: CommandEnv -> [Expr] -> Command -> SIO CommandOutput
|
--interpret :: CommandEnv -> [Expr] -> Command -> SIO CommandOutput
|
||||||
@@ -104,4 +113,4 @@ getCommandTrees env needsTypeCheck a args =
|
|||||||
ATerm t -> return (Term t)
|
ATerm t -> return (Term t)
|
||||||
ANoArg -> return args -- use piped
|
ANoArg -> return args -- use piped
|
||||||
where
|
where
|
||||||
one e = return (Exprs [(e,0)]) -- ignore piped
|
one e = return (Exprs [e]) -- ignore piped
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
module GF.Command.Parse(readCommandLine, pCommand) where
|
module GF.Command.Parse(readCommandLine, pCommand) where
|
||||||
|
|
||||||
import PGF2(pExpr,pIdent)
|
import PGF(pExpr,pIdent)
|
||||||
import GF.Grammar.Parser(runPartial,pTerm)
|
import GF.Grammar.Parser(runPartial,pTerm)
|
||||||
import GF.Command.Abstract
|
import GF.Command.Abstract
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ pCommandLine =
|
|||||||
pPipe = sepBy1 (skipSpaces >> pCommand) (skipSpaces >> char '|')
|
pPipe = sepBy1 (skipSpaces >> pCommand) (skipSpaces >> char '|')
|
||||||
|
|
||||||
pCommand = (do
|
pCommand = (do
|
||||||
cmd <- readS_to_P pIdent <++ (char '%' >> fmap ('%':) (readS_to_P pIdent))
|
cmd <- pIdent <++ (char '%' >> fmap ('%':) pIdent)
|
||||||
skipSpaces
|
skipSpaces
|
||||||
opts <- sepBy pOption skipSpaces
|
opts <- sepBy pOption skipSpaces
|
||||||
arg <- if getCommandOp cmd == "cc" then pArgTerm else pArgument
|
arg <- if getCommandOp cmd == "cc" then pArgTerm else pArgument
|
||||||
@@ -37,7 +37,7 @@ pCommand = (do
|
|||||||
|
|
||||||
pOption = do
|
pOption = do
|
||||||
char '-'
|
char '-'
|
||||||
flg <- readS_to_P pIdent
|
flg <- pIdent
|
||||||
option (OOpt flg) (fmap (OFlag flg) (char '=' >> pValue))
|
option (OOpt flg) (fmap (OFlag flg) (char '=' >> pValue))
|
||||||
|
|
||||||
pValue = do
|
pValue = do
|
||||||
@@ -52,9 +52,9 @@ pFilename = liftM2 (:) (satisfy isFileFirst) (munch (not . isSpace)) where
|
|||||||
|
|
||||||
pArgument =
|
pArgument =
|
||||||
option ANoArg
|
option ANoArg
|
||||||
(fmap AExpr (readS_to_P pExpr)
|
(fmap AExpr pExpr
|
||||||
<++
|
<++
|
||||||
(skipSpaces >> char '%' >> fmap AMacro (readS_to_P pIdent)))
|
(skipSpaces >> char '%' >> fmap AMacro pIdent))
|
||||||
|
|
||||||
pArgTerm = ATerm `fmap` readS_to_P sTerm
|
pArgTerm = ATerm `fmap` readS_to_P sTerm
|
||||||
where
|
where
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ import GF.Grammar.Parser (runP, pExp)
|
|||||||
import GF.Grammar.ShowTerm
|
import GF.Grammar.ShowTerm
|
||||||
import GF.Grammar.Lookup (allOpers,allOpersTo)
|
import GF.Grammar.Lookup (allOpers,allOpersTo)
|
||||||
import GF.Compile.Rename(renameSourceTerm)
|
import GF.Compile.Rename(renameSourceTerm)
|
||||||
import GF.Compile.Compute.Concrete(normalForm,resourceValues)
|
import qualified GF.Compile.Compute.ConcreteNew as CN(normalForm,resourceValues)
|
||||||
import GF.Compile.TypeCheck.Concrete as TC(inferLType,ppType)
|
import GF.Compile.TypeCheck.RConcrete as TC(inferLType,ppType)
|
||||||
import GF.Infra.Dependencies(depGraph)
|
import GF.Infra.Dependencies(depGraph)
|
||||||
import GF.Infra.CheckM(runCheck)
|
import GF.Infra.CheckM(runCheck)
|
||||||
|
|
||||||
@@ -259,7 +259,7 @@ checkComputeTerm os sgr t =
|
|||||||
((t,_),_) <- runCheck $ do t <- renameSourceTerm sgr mo t
|
((t,_),_) <- runCheck $ do t <- renameSourceTerm sgr mo t
|
||||||
inferLType sgr [] t
|
inferLType sgr [] t
|
||||||
let opts = modifyFlags (\fs->fs{optTrace=isOpt "trace" os})
|
let opts = modifyFlags (\fs->fs{optTrace=isOpt "trace" os})
|
||||||
t1 = normalForm (resourceValues opts sgr) (L NoLoc identW) t
|
t1 = CN.normalForm (CN.resourceValues opts sgr) (L NoLoc identW) t
|
||||||
t2 = evalStr t1
|
t2 = evalStr t1
|
||||||
checkPredefError t2
|
checkPredefError t2
|
||||||
where
|
where
|
||||||
|
|||||||
@@ -1,17 +1,18 @@
|
|||||||
module GF.Command.TreeOperations (
|
module GF.Command.TreeOperations (
|
||||||
treeOp,
|
treeOp,
|
||||||
allTreeOps,
|
allTreeOps,
|
||||||
|
treeChunks
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import PGF2(Expr,PGF,Fun,compute,mkApp,unApp,unMeta,exprSize,exprFunctions)
|
import PGF(Expr,PGF,CId,compute,mkApp,unApp,unapply,unMeta,exprSize,exprFunctions)
|
||||||
import Data.List
|
import Data.List
|
||||||
|
|
||||||
type TreeOp = [Expr] -> [Expr]
|
type TreeOp = [Expr] -> [Expr]
|
||||||
|
|
||||||
treeOp :: PGF -> String -> Maybe (Either TreeOp (Fun -> TreeOp))
|
treeOp :: PGF -> String -> Maybe (Either TreeOp (CId -> TreeOp))
|
||||||
treeOp pgf f = fmap snd $ lookup f $ allTreeOps pgf
|
treeOp pgf f = fmap snd $ lookup f $ allTreeOps pgf
|
||||||
|
|
||||||
allTreeOps :: PGF -> [(String,(String,Either TreeOp (Fun -> TreeOp)))]
|
allTreeOps :: PGF -> [(String,(String,Either TreeOp (CId -> TreeOp)))]
|
||||||
allTreeOps pgf = [
|
allTreeOps pgf = [
|
||||||
("compute",("compute by using semantic definitions (def)",
|
("compute",("compute by using semantic definitions (def)",
|
||||||
Left $ map (compute pgf))),
|
Left $ map (compute pgf))),
|
||||||
@@ -33,6 +34,16 @@ largest = reverse . smallest
|
|||||||
smallest :: [Expr] -> [Expr]
|
smallest :: [Expr] -> [Expr]
|
||||||
smallest = sortBy (\t u -> compare (exprSize t) (exprSize u))
|
smallest = sortBy (\t u -> compare (exprSize t) (exprSize u))
|
||||||
|
|
||||||
|
treeChunks :: Expr -> [Expr]
|
||||||
|
treeChunks = snd . cks where
|
||||||
|
cks t =
|
||||||
|
case unapply t of
|
||||||
|
(t, ts) -> case unMeta t of
|
||||||
|
Just _ -> (False,concatMap (snd . cks) ts)
|
||||||
|
Nothing -> case unzip (map cks ts) of
|
||||||
|
(bs,_) | and bs -> (True, [t])
|
||||||
|
(_,cts) -> (False,concat cts)
|
||||||
|
|
||||||
subtrees :: Expr -> [Expr]
|
subtrees :: Expr -> [Expr]
|
||||||
subtrees t = t : case unApp t of
|
subtrees t = t : case unApp t of
|
||||||
Just (f,ts) -> concatMap subtrees ts
|
Just (f,ts) -> concatMap subtrees ts
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
module GF.Compile (compileToPGF, link, batchCompile, srcAbsName) where
|
module GF.Compile (compileToPGF, compileToLPGF, link, linkl, batchCompile, srcAbsName) where
|
||||||
|
|
||||||
import GF.Compile.GrammarToPGF(grammar2PGF)
|
import GF.Compile.GrammarToPGF(mkCanon2pgf)
|
||||||
|
import GF.Compile.GrammarToLPGF(mkCanon2lpgf)
|
||||||
import GF.Compile.ReadFiles(ModEnv,getOptionsFromFile,getAllFiles,
|
import GF.Compile.ReadFiles(ModEnv,getOptionsFromFile,getAllFiles,
|
||||||
importsOfModule)
|
importsOfModule)
|
||||||
import GF.CompileOne(compileOne)
|
import GF.CompileOne(compileOne)
|
||||||
@@ -14,7 +15,7 @@ import GF.Infra.UseIO(IOE,FullPath,liftIO,getLibraryDirectory,putIfVerb,
|
|||||||
justModuleName,extendPathEnv,putStrE,putPointE)
|
justModuleName,extendPathEnv,putStrE,putPointE)
|
||||||
import GF.Data.Operations(raise,(+++),err)
|
import GF.Data.Operations(raise,(+++),err)
|
||||||
|
|
||||||
import Control.Monad(foldM,when,(<=<))
|
import Control.Monad(foldM,when,(<=<),filterM)
|
||||||
import GF.System.Directory(doesFileExist,getModificationTime)
|
import GF.System.Directory(doesFileExist,getModificationTime)
|
||||||
import System.FilePath((</>),isRelative,dropFileName)
|
import System.FilePath((</>),isRelative,dropFileName)
|
||||||
import qualified Data.Map as Map(empty,insert,elems) --lookup
|
import qualified Data.Map as Map(empty,insert,elems) --lookup
|
||||||
@@ -22,23 +23,37 @@ import Data.List(nub)
|
|||||||
import Data.Time(UTCTime)
|
import Data.Time(UTCTime)
|
||||||
import GF.Text.Pretty(render,($$),(<+>),nest)
|
import GF.Text.Pretty(render,($$),(<+>),nest)
|
||||||
|
|
||||||
import PGF2(PGF,readProbabilitiesFromFile)
|
import PGF.Internal(optimizePGF)
|
||||||
|
import PGF(PGF,defaultProbabilities,setProbabilities,readProbabilitiesFromFile)
|
||||||
|
import LPGF(LPGF)
|
||||||
|
|
||||||
-- | Compiles a number of source files and builds a 'PGF' structure for them.
|
-- | Compiles a number of source files and builds a 'PGF' structure for them.
|
||||||
-- This is a composition of 'link' and 'batchCompile'.
|
-- This is a composition of 'link' and 'batchCompile'.
|
||||||
compileToPGF :: Options -> [FilePath] -> IOE PGF
|
compileToPGF :: Options -> [FilePath] -> IOE PGF
|
||||||
compileToPGF opts fs = link opts . snd =<< batchCompile opts fs
|
compileToPGF opts fs = link opts . snd =<< batchCompile opts fs
|
||||||
|
|
||||||
|
compileToLPGF :: Options -> [FilePath] -> IOE LPGF
|
||||||
|
compileToLPGF opts fs = linkl opts . snd =<< batchCompile opts fs
|
||||||
|
|
||||||
-- | Link a grammar into a 'PGF' that can be used to 'PGF.linearize' and
|
-- | Link a grammar into a 'PGF' that can be used to 'PGF.linearize' and
|
||||||
-- 'PGF.parse' with the "PGF" run-time system.
|
-- 'PGF.parse' with the "PGF" run-time system.
|
||||||
link :: Options -> (ModuleName,Grammar) -> IOE PGF
|
link :: Options -> (ModuleName,Grammar) -> IOE PGF
|
||||||
link opts (cnc,gr) =
|
link opts (cnc,gr) =
|
||||||
putPointE Normal opts "linking ... " $ do
|
putPointE Normal opts "linking ... " $ do
|
||||||
let abs = srcAbsName gr cnc
|
let abs = srcAbsName gr cnc
|
||||||
probs <- liftIO (maybe (return Map.empty) readProbabilitiesFromFile (flag optProbsFile opts))
|
pgf <- mkCanon2pgf opts gr abs
|
||||||
pgf <- grammar2PGF opts gr abs probs
|
probs <- liftIO (maybe (return . defaultProbabilities) readProbabilitiesFromFile (flag optProbsFile opts) pgf)
|
||||||
when (verbAtLeast opts Normal) $ putStrE "OK"
|
when (verbAtLeast opts Normal) $ putStrE "OK"
|
||||||
return pgf
|
return $ setProbabilities probs
|
||||||
|
$ if flag optOptimizePGF opts then optimizePGF pgf else pgf
|
||||||
|
|
||||||
|
-- | Link a grammar into a 'LPGF' that can be used for linearization only.
|
||||||
|
linkl :: Options -> (ModuleName,Grammar) -> IOE LPGF
|
||||||
|
linkl opts (cnc,gr) =
|
||||||
|
putPointE Normal opts "linking ... " $ do
|
||||||
|
let abs = srcAbsName gr cnc
|
||||||
|
lpgf <- mkCanon2lpgf opts gr abs
|
||||||
|
return lpgf
|
||||||
|
|
||||||
-- | Returns the name of the abstract syntax corresponding to the named concrete syntax
|
-- | Returns the name of the abstract syntax corresponding to the named concrete syntax
|
||||||
srcAbsName gr cnc = err (const cnc) id $ abstractOfConcrete gr cnc
|
srcAbsName gr cnc = err (const cnc) id $ abstractOfConcrete gr cnc
|
||||||
@@ -76,10 +91,14 @@ compileModule opts1 env@(_,rfs) file =
|
|||||||
do file <- getRealFile file
|
do file <- getRealFile file
|
||||||
opts0 <- getOptionsFromFile file
|
opts0 <- getOptionsFromFile file
|
||||||
let curr_dir = dropFileName file
|
let curr_dir = dropFileName file
|
||||||
lib_dir <- getLibraryDirectory (addOptions opts0 opts1)
|
lib_dirs <- getLibraryDirectory (addOptions opts0 opts1)
|
||||||
let opts = addOptions (fixRelativeLibPaths curr_dir lib_dir opts0) opts1
|
let opts = addOptions (fixRelativeLibPaths curr_dir lib_dirs opts0) opts1
|
||||||
|
-- putIfVerb opts $ "curr_dir:" +++ show curr_dir ----
|
||||||
|
-- putIfVerb opts $ "lib_dir:" +++ show lib_dirs ----
|
||||||
ps0 <- extendPathEnv opts
|
ps0 <- extendPathEnv opts
|
||||||
let ps = nub (curr_dir : ps0)
|
let ps = nub (curr_dir : ps0)
|
||||||
|
-- putIfVerb opts $ "options from file: " ++ show opts0
|
||||||
|
-- putIfVerb opts $ "augmented options: " ++ show opts
|
||||||
putIfVerb opts $ "module search path:" +++ show ps ----
|
putIfVerb opts $ "module search path:" +++ show ps ----
|
||||||
files <- getAllFiles opts ps rfs file
|
files <- getAllFiles opts ps rfs file
|
||||||
putIfVerb opts $ "files to read:" +++ show files ----
|
putIfVerb opts $ "files to read:" +++ show files ----
|
||||||
@@ -92,13 +111,17 @@ compileModule opts1 env@(_,rfs) file =
|
|||||||
if exists
|
if exists
|
||||||
then return file
|
then return file
|
||||||
else if isRelative file
|
else if isRelative file
|
||||||
then do lib_dir <- getLibraryDirectory opts1
|
then do
|
||||||
let file1 = lib_dir </> file
|
lib_dirs <- getLibraryDirectory opts1
|
||||||
exists <- doesFileExist file1
|
let candidates = [ lib_dir </> file | lib_dir <- lib_dirs ]
|
||||||
if exists
|
putIfVerb opts1 (render ("looking for: " $$ nest 2 candidates))
|
||||||
then return file1
|
file1s <- filterM doesFileExist candidates
|
||||||
else raise (render ("None of these files exists:" $$ nest 2 (file $$ file1)))
|
case length file1s of
|
||||||
else raise (render ("File" <+> file <+> "does not exist."))
|
0 -> raise (render ("Unable to find: " $$ nest 2 candidates))
|
||||||
|
1 -> do return $ head file1s
|
||||||
|
_ -> do putIfVerb opts1 ("matched multiple candidates: " +++ show file1s)
|
||||||
|
return $ head file1s
|
||||||
|
else raise (render ("File" <+> file <+> "does not exist"))
|
||||||
|
|
||||||
compileOne' :: Options -> CompileEnv -> FullPath -> IOE CompileEnv
|
compileOne' :: Options -> CompileEnv -> FullPath -> IOE CompileEnv
|
||||||
compileOne' opts env@(gr,_) = extendCompileEnv env <=< compileOne opts gr
|
compileOne' opts env@(gr,_) = extendCompileEnv env <=< compileOne opts gr
|
||||||
|
|||||||
@@ -1,110 +1,99 @@
|
|||||||
{-# LANGUAGE FlexibleContexts, ImplicitParams #-}
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
module GF.Compile.CFGtoPGF (cf2pgf) where
|
module GF.Compile.CFGtoPGF (cf2pgf) where
|
||||||
|
|
||||||
import GF.Grammar.CFG
|
import GF.Grammar.CFG
|
||||||
import GF.Infra.UseIO
|
import GF.Infra.UseIO
|
||||||
import GF.Infra.Option
|
|
||||||
import GF.Compile.OptimizePGF
|
|
||||||
|
|
||||||
import PGF2
|
import PGF
|
||||||
import PGF2.Internal
|
import PGF.Internal
|
||||||
|
|
||||||
import qualified Data.Set as Set
|
import qualified Data.Set as Set
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
import qualified Data.IntMap as IntMap
|
import qualified Data.IntMap as IntMap
|
||||||
import Data.Array.IArray
|
import Data.Array.IArray
|
||||||
import Data.List
|
import Data.List
|
||||||
import Data.Maybe(fromMaybe)
|
|
||||||
|
|
||||||
--------------------------
|
--------------------------
|
||||||
-- the compiler ----------
|
-- the compiler ----------
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
cf2pgf :: Options -> FilePath -> ParamCFG -> Map.Map Fun Double -> PGF
|
cf2pgf :: FilePath -> ParamCFG -> PGF
|
||||||
cf2pgf opts fpath cf probs =
|
cf2pgf fpath cf =
|
||||||
build (let abstr = cf2abstr cf probs
|
let pgf = PGF Map.empty aname (cf2abstr cf) (Map.singleton cname (cf2concr cf))
|
||||||
in newPGF [] aname abstr [(cname, cf2concr opts abstr cf)])
|
in updateProductionIndices pgf
|
||||||
where
|
where
|
||||||
name = justModuleName fpath
|
name = justModuleName fpath
|
||||||
aname = name ++ "Abs"
|
aname = mkCId (name ++ "Abs")
|
||||||
cname = name
|
cname = mkCId name
|
||||||
|
|
||||||
cf2abstr :: (?builder :: Builder s) => ParamCFG -> Map.Map Fun Double -> B s AbstrInfo
|
cf2abstr :: ParamCFG -> Abstr
|
||||||
cf2abstr cfg probs = newAbstr aflags acats afuns
|
cf2abstr cfg = Abstr aflags afuns acats
|
||||||
where
|
where
|
||||||
aflags = [("startcat", LStr (fst (cfgStartCat cfg)))]
|
aflags = Map.singleton (mkCId "startcat") (LStr (fst (cfgStartCat cfg)))
|
||||||
|
|
||||||
acats = [(c', [], toLogProb (fromMaybe 0 (Map.lookup c' probs))) | cat <- allCats' cfg, let c' = cat2id cat]
|
acats = Map.fromList [(cat, ([], [(0,mkRuleName rule) | rule <- rules], 0))
|
||||||
afuns = [(f', dTyp [hypo Explicit "_" (dTyp [] (cat2id c) []) | NonTerminal c <- ruleRhs rule] (cat2id (ruleLhs rule)) [], 0, [], toLogProb (fromMaybe 0 (Map.lookup f' funs_probs)))
|
| (cat,rules) <- (Map.toList . Map.fromListWith (++))
|
||||||
| rule <- allRules cfg
|
[(cat2id cat, catRules cfg cat) |
|
||||||
, let f' = mkRuleName rule]
|
cat <- allCats' cfg]]
|
||||||
|
afuns = Map.fromList [(mkRuleName rule, (cftype [cat2id c | NonTerminal c <- ruleRhs rule] (cat2id (ruleLhs rule)), 0, Nothing, 0))
|
||||||
|
| rule <- allRules cfg]
|
||||||
|
|
||||||
funs_probs = (Map.fromList . concat . Map.elems . fmap pad . Map.fromListWith (++))
|
cat2id = mkCId . fst
|
||||||
[(cat,[(f',Map.lookup f' probs)]) | rule <- allRules cfg,
|
|
||||||
let cat = cat2id (ruleLhs rule),
|
|
||||||
let f' = mkRuleName rule]
|
|
||||||
where
|
|
||||||
pad :: [(a,Maybe Double)] -> [(a,Double)]
|
|
||||||
pad pfs = [(f,fromMaybe deflt mb_p) | (f,mb_p) <- pfs]
|
|
||||||
where
|
|
||||||
deflt = case length [f | (f,Nothing) <- pfs] of
|
|
||||||
0 -> 0
|
|
||||||
n -> max 0 ((1 - sum [d | (f,Just d) <- pfs]) / fromIntegral n)
|
|
||||||
|
|
||||||
toLogProb = realToFrac . negate . log
|
cf2concr :: ParamCFG -> Concr
|
||||||
|
cf2concr cfg = Concr Map.empty Map.empty
|
||||||
cat2id = fst
|
cncfuns lindefsrefs lindefsrefs
|
||||||
|
sequences productions
|
||||||
cf2concr :: (?builder :: Builder s) => Options -> B s AbstrInfo -> ParamCFG -> B s ConcrInfo
|
IntMap.empty Map.empty
|
||||||
cf2concr opts abstr cfg =
|
cnccats
|
||||||
let (lindefs',linrefs',productions',cncfuns',sequences',cnccats') =
|
IntMap.empty
|
||||||
(if flag optOptimizePGF opts then optimizePGF (fst (cfgStartCat cfg)) else id)
|
totalCats
|
||||||
(lindefsrefs,lindefsrefs,IntMap.toList productions,cncfuns,sequences,cnccats)
|
|
||||||
in newConcr abstr [] []
|
|
||||||
lindefs' linrefs'
|
|
||||||
productions' cncfuns'
|
|
||||||
sequences' cnccats' totalCats
|
|
||||||
where
|
where
|
||||||
cats = allCats' cfg
|
cats = allCats' cfg
|
||||||
rules = allRules cfg
|
rules = allRules cfg
|
||||||
|
|
||||||
idSeq = [SymCat 0 0]
|
sequences0 = Set.fromList (listArray (0,0) [SymCat 0 0] :
|
||||||
|
|
||||||
sequences0 = Set.fromList (idSeq :
|
|
||||||
map mkSequence rules)
|
map mkSequence rules)
|
||||||
sequences = Set.toList sequences0
|
sequences = listArray (0,Set.size sequences0-1) (Set.toList sequences0)
|
||||||
|
|
||||||
idFun = ("_",[Set.findIndex idSeq sequences0])
|
idFun = CncFun wildCId (listArray (0,0) [seqid])
|
||||||
|
where
|
||||||
|
seq = listArray (0,0) [SymCat 0 0]
|
||||||
|
seqid = binSearch seq sequences (bounds sequences)
|
||||||
((fun_cnt,cncfuns0),productions0) = mapAccumL (convertRule cs) (1,[idFun]) rules
|
((fun_cnt,cncfuns0),productions0) = mapAccumL (convertRule cs) (1,[idFun]) rules
|
||||||
productions = foldl addProd IntMap.empty (concat (productions0++coercions))
|
productions = foldl addProd IntMap.empty (concat (productions0++coercions))
|
||||||
cncfuns = reverse cncfuns0
|
cncfuns = listArray (0,fun_cnt-1) (reverse cncfuns0)
|
||||||
|
|
||||||
lbls = ["s"]
|
lbls = listArray (0,0) ["s"]
|
||||||
(fid,cnccats) = (mapAccumL mkCncCat 0 . Map.toList . Map.fromListWith max)
|
(fid,cnccats0) = (mapAccumL mkCncCat 0 . Map.toList . Map.fromListWith max)
|
||||||
[(c,p) | (c,ps) <- cats, p <- ps]
|
[(c,p) | (c,ps) <- cats, p <- ps]
|
||||||
((totalCats,cs), coercions) = mapAccumL mkCoercions (fid,Map.empty) cats
|
((totalCats,cs), coercions) = mapAccumL mkCoercions (fid,Map.empty) cats
|
||||||
|
cnccats = Map.fromList cnccats0
|
||||||
|
|
||||||
lindefsrefs = map mkLinDefRef cats
|
lindefsrefs =
|
||||||
|
IntMap.fromList (map mkLinDefRef cats)
|
||||||
|
|
||||||
convertRule cs (funid,funs) rule =
|
convertRule cs (funid,funs) rule =
|
||||||
let args = [PArg [] (cat2arg c) | NonTerminal c <- ruleRhs rule]
|
let args = [PArg [] (cat2arg c) | NonTerminal c <- ruleRhs rule]
|
||||||
prod = PApply funid args
|
prod = PApply funid args
|
||||||
seqid = Set.findIndex (mkSequence rule) sequences0
|
seqid = binSearch (mkSequence rule) sequences (bounds sequences)
|
||||||
fun = (mkRuleName rule, [seqid])
|
fun = CncFun (mkRuleName rule) (listArray (0,0) [seqid])
|
||||||
funid' = funid+1
|
funid' = funid+1
|
||||||
in funid' `seq` ((funid',fun:funs),let (c,ps) = ruleLhs rule in [(cat2fid c p, prod) | p <- ps])
|
in funid' `seq` ((funid',fun:funs),let (c,ps) = ruleLhs rule in [(cat2fid c p, prod) | p <- ps])
|
||||||
|
|
||||||
mkSequence rule = snd $ mapAccumL convertSymbol 0 (ruleRhs rule)
|
mkSequence rule = listArray (0,length syms-1) syms
|
||||||
where
|
where
|
||||||
|
syms = snd $ mapAccumL convertSymbol 0 (ruleRhs rule)
|
||||||
|
|
||||||
convertSymbol d (NonTerminal (c,_)) = (d+1,if c `elem` ["Int","Float","String"] then SymLit d 0 else SymCat d 0)
|
convertSymbol d (NonTerminal (c,_)) = (d+1,if c `elem` ["Int","Float","String"] then SymLit d 0 else SymCat d 0)
|
||||||
convertSymbol d (Terminal t) = (d, SymKS t)
|
convertSymbol d (Terminal t) = (d, SymKS t)
|
||||||
|
|
||||||
mkCncCat fid (cat,n)
|
mkCncCat fid (cat,n)
|
||||||
| cat == "Int" = (fid, (cat, fidInt, fidInt, lbls))
|
| cat == "Int" = (fid, (mkCId cat, CncCat fidInt fidInt lbls))
|
||||||
| cat == "Float" = (fid, (cat, fidFloat, fidFloat, lbls))
|
| cat == "Float" = (fid, (mkCId cat, CncCat fidFloat fidFloat lbls))
|
||||||
| cat == "String" = (fid, (cat, fidString, fidString, lbls))
|
| cat == "String" = (fid, (mkCId cat, CncCat fidString fidString lbls))
|
||||||
| otherwise = let fid' = fid+n+1
|
| otherwise = let fid' = fid+n+1
|
||||||
in fid' `seq` (fid', (cat, fid, fid+n, lbls))
|
in fid' `seq` (fid', (mkCId cat,CncCat fid (fid+n) lbls))
|
||||||
|
|
||||||
mkCoercions (fid,cs) c@(cat,[p]) = ((fid,cs),[])
|
mkCoercions (fid,cs) c@(cat,[p]) = ((fid,cs),[])
|
||||||
mkCoercions (fid,cs) c@(cat,ps ) =
|
mkCoercions (fid,cs) c@(cat,ps ) =
|
||||||
@@ -113,16 +102,25 @@ cf2concr opts abstr cfg =
|
|||||||
|
|
||||||
mkLinDefRef (cat,_) =
|
mkLinDefRef (cat,_) =
|
||||||
(cat2fid cat 0,[0])
|
(cat2fid cat 0,[0])
|
||||||
|
|
||||||
addProd prods (fid,prod) =
|
addProd prods (fid,prod) =
|
||||||
case IntMap.lookup fid prods of
|
case IntMap.lookup fid prods of
|
||||||
Just set -> IntMap.insert fid (prod:set) prods
|
Just set -> IntMap.insert fid (Set.insert prod set) prods
|
||||||
Nothing -> IntMap.insert fid [prod] prods
|
Nothing -> IntMap.insert fid (Set.singleton prod) prods
|
||||||
|
|
||||||
|
binSearch v arr (i,j)
|
||||||
|
| i <= j = case compare v (arr ! k) of
|
||||||
|
LT -> binSearch v arr (i,k-1)
|
||||||
|
EQ -> k
|
||||||
|
GT -> binSearch v arr (k+1,j)
|
||||||
|
| otherwise = error "binSearch"
|
||||||
|
where
|
||||||
|
k = (i+j) `div` 2
|
||||||
|
|
||||||
cat2fid cat p =
|
cat2fid cat p =
|
||||||
case [start | (cat',start,_,_) <- cnccats, cat == cat'] of
|
case Map.lookup (mkCId cat) cnccats of
|
||||||
(start:_) -> fid+p
|
Just (CncCat fid _ _) -> fid+p
|
||||||
_ -> error "cat2fid"
|
_ -> error "cat2fid"
|
||||||
|
|
||||||
cat2arg c@(cat,[p]) = cat2fid cat p
|
cat2arg c@(cat,[p]) = cat2fid cat p
|
||||||
cat2arg c@(cat,ps ) =
|
cat2arg c@(cat,ps ) =
|
||||||
@@ -133,4 +131,4 @@ cf2concr opts abstr cfg =
|
|||||||
mkRuleName rule =
|
mkRuleName rule =
|
||||||
case ruleName rule of
|
case ruleName rule of
|
||||||
CFObj n _ -> n
|
CFObj n _ -> n
|
||||||
_ -> "_"
|
_ -> wildCId
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
-- Stability : (stable)
|
-- Stability : (stable)
|
||||||
-- Portability : (portable)
|
-- Portability : (portable)
|
||||||
--
|
--
|
||||||
-- > CVS $Date: 2005/11/11 23:24:33 $
|
-- > CVS $Date: 2005/11/11 23:24:33 $
|
||||||
-- > CVS $Author: aarne $
|
-- > CVS $Author: aarne $
|
||||||
-- > CVS $Revision: 1.31 $
|
-- > CVS $Revision: 1.31 $
|
||||||
--
|
--
|
||||||
@@ -21,15 +21,15 @@
|
|||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
|
|
||||||
module GF.Compile.CheckGrammar(checkModule) where
|
module GF.Compile.CheckGrammar(checkModule) where
|
||||||
|
import Prelude hiding ((<>)) -- GHC 8.4.1 clash with Text.PrettyPrint
|
||||||
|
|
||||||
import Prelude hiding ((<>))
|
|
||||||
import GF.Infra.Ident
|
import GF.Infra.Ident
|
||||||
import GF.Infra.Option
|
import GF.Infra.Option
|
||||||
|
|
||||||
import GF.Compile.TypeCheck.Abstract
|
import GF.Compile.TypeCheck.Abstract
|
||||||
import GF.Compile.TypeCheck.Concrete(computeLType,checkLType,inferLType,ppType)
|
import GF.Compile.TypeCheck.RConcrete
|
||||||
import qualified GF.Compile.TypeCheck.ConcreteNew as CN(checkLType,inferLType)
|
import qualified GF.Compile.TypeCheck.ConcreteNew as CN
|
||||||
import qualified GF.Compile.Compute.Concrete as CN(normalForm,resourceValues)
|
import qualified GF.Compile.Compute.ConcreteNew as CN
|
||||||
|
|
||||||
import GF.Grammar
|
import GF.Grammar
|
||||||
import GF.Grammar.Lexer
|
import GF.Grammar.Lexer
|
||||||
@@ -74,9 +74,9 @@ checkRestrictedInheritance cwd sgr (name,mo) = checkInModule cwd mo NoLoc empty
|
|||||||
let (incl,excl) = partition (isInherited mi) (Map.keys (jments m))
|
let (incl,excl) = partition (isInherited mi) (Map.keys (jments m))
|
||||||
let incld c = Set.member c (Set.fromList incl)
|
let incld c = Set.member c (Set.fromList incl)
|
||||||
let illegal c = Set.member c (Set.fromList excl)
|
let illegal c = Set.member c (Set.fromList excl)
|
||||||
let illegals = [(f,is) |
|
let illegals = [(f,is) |
|
||||||
(f,cs) <- allDeps, incld f, let is = filter illegal cs, not (null is)]
|
(f,cs) <- allDeps, incld f, let is = filter illegal cs, not (null is)]
|
||||||
case illegals of
|
case illegals of
|
||||||
[] -> return ()
|
[] -> return ()
|
||||||
cs -> checkWarn ("In inherited module" <+> i <> ", dependence of excluded constants:" $$
|
cs -> checkWarn ("In inherited module" <+> i <> ", dependence of excluded constants:" $$
|
||||||
nest 2 (vcat [f <+> "on" <+> fsep is | (f,is) <- cs]))
|
nest 2 (vcat [f <+> "on" <+> fsep is | (f,is) <- cs]))
|
||||||
@@ -92,12 +92,12 @@ checkCompleteGrammar opts cwd gr (am,abs) (cm,cnc) = checkInModule cwd cnc NoLoc
|
|||||||
|
|
||||||
-- check that all abstract constants are in concrete; build default lin and lincats
|
-- check that all abstract constants are in concrete; build default lin and lincats
|
||||||
jsc <- foldM checkAbs jsc (Map.toList jsa)
|
jsc <- foldM checkAbs jsc (Map.toList jsa)
|
||||||
|
|
||||||
return (cm,cnc{jments=jsc})
|
return (cm,cnc{jments=jsc})
|
||||||
where
|
where
|
||||||
checkAbs js i@(c,info) =
|
checkAbs js i@(c,info) =
|
||||||
case info of
|
case info of
|
||||||
AbsFun (Just (L loc ty)) _ _ _
|
AbsFun (Just (L loc ty)) _ _ _
|
||||||
-> do let mb_def = do
|
-> do let mb_def = do
|
||||||
let (cxt,(_,i),_) = typeForm ty
|
let (cxt,(_,i),_) = typeForm ty
|
||||||
info <- lookupIdent i js
|
info <- lookupIdent i js
|
||||||
@@ -136,11 +136,11 @@ checkCompleteGrammar opts cwd gr (am,abs) (cm,cnc) = checkInModule cwd cnc NoLoc
|
|||||||
checkWarn ("no linearization type for" <+> c <> ", inserting default {s : Str}")
|
checkWarn ("no linearization type for" <+> c <> ", inserting default {s : Str}")
|
||||||
return $ Map.insert c (CncCat (Just (L NoLoc defLinType)) Nothing Nothing Nothing Nothing) js
|
return $ Map.insert c (CncCat (Just (L NoLoc defLinType)) Nothing Nothing Nothing Nothing) js
|
||||||
_ -> return js
|
_ -> return js
|
||||||
|
|
||||||
checkCnc js (c,info) =
|
checkCnc js (c,info) =
|
||||||
case info of
|
case info of
|
||||||
CncFun _ d mn mf -> case lookupOrigInfo gr (am,c) of
|
CncFun _ d mn mf -> case lookupOrigInfo gr (am,c) of
|
||||||
Ok (_,AbsFun (Just (L _ ty)) _ _ _) ->
|
Ok (_,AbsFun (Just (L _ ty)) _ _ _) ->
|
||||||
do (cont,val) <- linTypeOfType gr cm ty
|
do (cont,val) <- linTypeOfType gr cm ty
|
||||||
let linty = (snd (valCat ty),cont,val)
|
let linty = (snd (valCat ty),cont,val)
|
||||||
return $ Map.insert c (CncFun (Just linty) d mn mf) js
|
return $ Map.insert c (CncFun (Just linty) d mn mf) js
|
||||||
@@ -159,14 +159,14 @@ checkCompleteGrammar opts cwd gr (am,abs) (cm,cnc) = checkInModule cwd cnc NoLoc
|
|||||||
_ -> return $ Map.insert c info js
|
_ -> return $ Map.insert c info js
|
||||||
|
|
||||||
|
|
||||||
-- | General Principle: only Just-values are checked.
|
-- | General Principle: only Just-values are checked.
|
||||||
-- A May-value has always been checked in its origin module.
|
-- A May-value has always been checked in its origin module.
|
||||||
checkInfo :: Options -> FilePath -> SourceGrammar -> SourceModule -> Ident -> Info -> Check Info
|
checkInfo :: Options -> FilePath -> SourceGrammar -> SourceModule -> Ident -> Info -> Check Info
|
||||||
checkInfo opts cwd sgr (m,mo) c info = checkInModule cwd mo NoLoc empty $ do
|
checkInfo opts cwd sgr (m,mo) c info = checkInModule cwd mo NoLoc empty $ do
|
||||||
checkReservedId c
|
checkReservedId c
|
||||||
case info of
|
case info of
|
||||||
AbsCat (Just (L loc cont)) ->
|
AbsCat (Just (L loc cont)) ->
|
||||||
mkCheck loc "the category" $
|
mkCheck loc "the category" $
|
||||||
checkContext gr cont
|
checkContext gr cont
|
||||||
|
|
||||||
AbsFun (Just (L loc typ0)) ma md moper -> do
|
AbsFun (Just (L loc typ0)) ma md moper -> do
|
||||||
@@ -175,13 +175,13 @@ checkInfo opts cwd sgr (m,mo) c info = checkInModule cwd mo NoLoc empty $ do
|
|||||||
checkTyp gr typ
|
checkTyp gr typ
|
||||||
case md of
|
case md of
|
||||||
Just eqs -> mapM_ (\(L loc eq) -> mkCheck loc "the definition of function" $
|
Just eqs -> mapM_ (\(L loc eq) -> mkCheck loc "the definition of function" $
|
||||||
checkDef gr (m,c) typ eq) eqs
|
checkDef gr (m,c) typ eq) eqs
|
||||||
Nothing -> return ()
|
Nothing -> return ()
|
||||||
return (AbsFun (Just (L loc typ)) ma md moper)
|
return (AbsFun (Just (L loc typ)) ma md moper)
|
||||||
|
|
||||||
CncCat mty mdef mref mpr mpmcfg -> do
|
CncCat mty mdef mref mpr mpmcfg -> do
|
||||||
mty <- case mty of
|
mty <- case mty of
|
||||||
Just (L loc typ) -> chIn loc "linearization type of" $
|
Just (L loc typ) -> chIn loc "linearization type of" $
|
||||||
(if False --flag optNewComp opts
|
(if False --flag optNewComp opts
|
||||||
then do (typ,_) <- CN.checkLType (CN.resourceValues opts gr) typ typeType
|
then do (typ,_) <- CN.checkLType (CN.resourceValues opts gr) typ typeType
|
||||||
typ <- computeLType gr [] typ
|
typ <- computeLType gr [] typ
|
||||||
@@ -191,19 +191,19 @@ checkInfo opts cwd sgr (m,mo) c info = checkInModule cwd mo NoLoc empty $ do
|
|||||||
return (Just (L loc typ)))
|
return (Just (L loc typ)))
|
||||||
Nothing -> return Nothing
|
Nothing -> return Nothing
|
||||||
mdef <- case (mty,mdef) of
|
mdef <- case (mty,mdef) of
|
||||||
(Just (L _ typ),Just (L loc def)) ->
|
(Just (L _ typ),Just (L loc def)) ->
|
||||||
chIn loc "default linearization of" $ do
|
chIn loc "default linearization of" $ do
|
||||||
(def,_) <- checkLType gr [] def (mkFunType [typeStr] typ)
|
(def,_) <- checkLType gr [] def (mkFunType [typeStr] typ)
|
||||||
return (Just (L loc def))
|
return (Just (L loc def))
|
||||||
_ -> return Nothing
|
_ -> return Nothing
|
||||||
mref <- case (mty,mref) of
|
mref <- case (mty,mref) of
|
||||||
(Just (L _ typ),Just (L loc ref)) ->
|
(Just (L _ typ),Just (L loc ref)) ->
|
||||||
chIn loc "reference linearization of" $ do
|
chIn loc "reference linearization of" $ do
|
||||||
(ref,_) <- checkLType gr [] ref (mkFunType [typ] typeStr)
|
(ref,_) <- checkLType gr [] ref (mkFunType [typ] typeStr)
|
||||||
return (Just (L loc ref))
|
return (Just (L loc ref))
|
||||||
_ -> return Nothing
|
_ -> return Nothing
|
||||||
mpr <- case mpr of
|
mpr <- case mpr of
|
||||||
(Just (L loc t)) ->
|
(Just (L loc t)) ->
|
||||||
chIn loc "print name of" $ do
|
chIn loc "print name of" $ do
|
||||||
(t,_) <- checkLType gr [] t typeStr
|
(t,_) <- checkLType gr [] t typeStr
|
||||||
return (Just (L loc t))
|
return (Just (L loc t))
|
||||||
@@ -212,13 +212,13 @@ checkInfo opts cwd sgr (m,mo) c info = checkInModule cwd mo NoLoc empty $ do
|
|||||||
|
|
||||||
CncFun mty mt mpr mpmcfg -> do
|
CncFun mty mt mpr mpmcfg -> do
|
||||||
mt <- case (mty,mt) of
|
mt <- case (mty,mt) of
|
||||||
(Just (cat,cont,val),Just (L loc trm)) ->
|
(Just (cat,cont,val),Just (L loc trm)) ->
|
||||||
chIn loc "linearization of" $ do
|
chIn loc "linearization of" $ do
|
||||||
(trm,_) <- checkLType gr [] trm (mkFunType (map (\(_,_,ty) -> ty) cont) val) -- erases arg vars
|
(trm,_) <- checkLType gr [] trm (mkFunType (map (\(_,_,ty) -> ty) cont) val) -- erases arg vars
|
||||||
return (Just (L loc trm))
|
return (Just (L loc trm))
|
||||||
_ -> return mt
|
_ -> return mt
|
||||||
mpr <- case mpr of
|
mpr <- case mpr of
|
||||||
(Just (L loc t)) ->
|
(Just (L loc t)) ->
|
||||||
chIn loc "print name of" $ do
|
chIn loc "print name of" $ do
|
||||||
(t,_) <- checkLType gr [] t typeStr
|
(t,_) <- checkLType gr [] t typeStr
|
||||||
return (Just (L loc t))
|
return (Just (L loc t))
|
||||||
@@ -251,16 +251,16 @@ checkInfo opts cwd sgr (m,mo) c info = checkInModule cwd mo NoLoc empty $ do
|
|||||||
ResOverload os tysts -> chIn NoLoc "overloading" $ do
|
ResOverload os tysts -> chIn NoLoc "overloading" $ do
|
||||||
tysts' <- mapM (uncurry $ flip (\(L loc1 t) (L loc2 ty) -> checkLType gr [] t ty >>= \(t,ty) -> return (L loc1 t, L loc2 ty))) tysts -- return explicit ones
|
tysts' <- mapM (uncurry $ flip (\(L loc1 t) (L loc2 ty) -> checkLType gr [] t ty >>= \(t,ty) -> return (L loc1 t, L loc2 ty))) tysts -- return explicit ones
|
||||||
tysts0 <- lookupOverload gr (m,c) -- check against inherited ones too
|
tysts0 <- lookupOverload gr (m,c) -- check against inherited ones too
|
||||||
tysts1 <- mapM (uncurry $ flip (checkLType gr []))
|
tysts1 <- mapM (uncurry $ flip (checkLType gr []))
|
||||||
[(mkFunType args val,tr) | (args,(val,tr)) <- tysts0]
|
[(mkFunType args val,tr) | (args,(val,tr)) <- tysts0]
|
||||||
--- this can only be a partial guarantee, since matching
|
--- this can only be a partial guarantee, since matching
|
||||||
--- with value type is only possible if expected type is given
|
--- with value type is only possible if expected type is given
|
||||||
checkUniq $
|
checkUniq $
|
||||||
sort [let (xs,t) = typeFormCnc x in t : map (\(b,x,t) -> t) xs | (_,x) <- tysts1]
|
sort [let (xs,t) = typeFormCnc x in t : map (\(b,x,t) -> t) xs | (_,x) <- tysts1]
|
||||||
return (ResOverload os [(y,x) | (x,y) <- tysts'])
|
return (ResOverload os [(y,x) | (x,y) <- tysts'])
|
||||||
|
|
||||||
ResParam (Just (L loc pcs)) _ -> do
|
ResParam (Just (L loc pcs)) _ -> do
|
||||||
ts <- chIn loc "parameter type" $
|
ts <- chIn loc "parameter type" $
|
||||||
liftM concat $ mapM mkPar pcs
|
liftM concat $ mapM mkPar pcs
|
||||||
return (ResParam (Just (L loc pcs)) (Just ts))
|
return (ResParam (Just (L loc pcs)) (Just ts))
|
||||||
|
|
||||||
@@ -274,9 +274,9 @@ checkInfo opts cwd sgr (m,mo) c info = checkInModule cwd mo NoLoc empty $ do
|
|||||||
return $ map (mkApp (QC (m,f))) vs
|
return $ map (mkApp (QC (m,f))) vs
|
||||||
|
|
||||||
checkUniq xss = case xss of
|
checkUniq xss = case xss of
|
||||||
x:y:xs
|
x:y:xs
|
||||||
| x == y -> checkError $ "ambiguous for type" <+>
|
| x == y -> checkError $ "ambiguous for type" <+>
|
||||||
ppType (mkFunType (tail x) (head x))
|
ppType (mkFunType (tail x) (head x))
|
||||||
| otherwise -> checkUniq $ y:xs
|
| otherwise -> checkUniq $ y:xs
|
||||||
_ -> return ()
|
_ -> return ()
|
||||||
|
|
||||||
@@ -294,7 +294,7 @@ checkInfo opts cwd sgr (m,mo) c info = checkInModule cwd mo NoLoc empty $ do
|
|||||||
t' <- compAbsTyp ((x,Vr x):g) t
|
t' <- compAbsTyp ((x,Vr x):g) t
|
||||||
return $ Prod b x a' t'
|
return $ Prod b x a' t'
|
||||||
Abs _ _ _ -> return t
|
Abs _ _ _ -> return t
|
||||||
_ -> composOp (compAbsTyp g) t
|
_ -> composOp (compAbsTyp g) t
|
||||||
|
|
||||||
|
|
||||||
-- | for grammars obtained otherwise than by parsing ---- update!!
|
-- | for grammars obtained otherwise than by parsing ---- update!!
|
||||||
@@ -316,7 +316,7 @@ linTypeOfType cnc m typ = do
|
|||||||
mkLinArg (i,(n,mc@(m,cat))) = do
|
mkLinArg (i,(n,mc@(m,cat))) = do
|
||||||
val <- lookLin mc
|
val <- lookLin mc
|
||||||
let vars = mkRecType varLabel $ replicate n typeStr
|
let vars = mkRecType varLabel $ replicate n typeStr
|
||||||
symb = argIdent n cat i
|
symb = argIdent n cat i
|
||||||
rec <- if n==0 then return val else
|
rec <- if n==0 then return val else
|
||||||
errIn (render ("extending" $$
|
errIn (render ("extending" $$
|
||||||
nest 2 vars $$
|
nest 2 vars $$
|
||||||
|
|||||||
@@ -1,590 +1,3 @@
|
|||||||
-- | Functions for computing the values of terms in the concrete syntax, in
|
module GF.Compile.Compute.Concrete{-(module M)-} where
|
||||||
-- | preparation for PMCFG generation.
|
--import GF.Compile.Compute.ConcreteLazy as M -- New
|
||||||
module GF.Compile.Compute.Concrete
|
--import GF.Compile.Compute.ConcreteStrict as M -- Old, inefficient
|
||||||
(GlobalEnv, GLocation, resourceValues, geLoc, geGrammar,
|
|
||||||
normalForm,
|
|
||||||
Value(..), Bind(..), Env, value2term, eval, vapply
|
|
||||||
) where
|
|
||||||
import Prelude hiding ((<>)) -- GHC 8.4.1 clash with Text.PrettyPrint
|
|
||||||
|
|
||||||
import GF.Grammar hiding (Env, VGen, VApp, VRecType)
|
|
||||||
import GF.Grammar.Lookup(lookupResDefLoc,allParamValues)
|
|
||||||
import GF.Grammar.Predef(cPredef,cErrorType,cTok,cStr,cTrace,cPBool)
|
|
||||||
import GF.Grammar.PatternMatch(matchPattern,measurePatt)
|
|
||||||
import GF.Grammar.Lockfield(isLockLabel,lockRecType) --unlockRecord,lockLabel
|
|
||||||
import GF.Compile.Compute.Value hiding (Error)
|
|
||||||
import GF.Compile.Compute.Predef(predef,predefName,delta)
|
|
||||||
import GF.Data.Str(Str,glueStr,str2strings,str,sstr,plusStr,strTok)
|
|
||||||
import GF.Data.Operations(Err,err,errIn,maybeErr,mapPairsM)
|
|
||||||
import GF.Data.Utilities(mapFst,mapSnd)
|
|
||||||
import GF.Infra.Option
|
|
||||||
import Control.Monad(ap,liftM,liftM2) -- ,unless,mplus
|
|
||||||
import Data.List (findIndex,intersect,nub,elemIndex,(\\)) --,isInfixOf
|
|
||||||
--import Data.Char (isUpper,toUpper,toLower)
|
|
||||||
import GF.Text.Pretty
|
|
||||||
import qualified Data.Map as Map
|
|
||||||
import Debug.Trace(trace)
|
|
||||||
|
|
||||||
-- * Main entry points
|
|
||||||
|
|
||||||
normalForm :: GlobalEnv -> L Ident -> Term -> Term
|
|
||||||
normalForm (GE gr rv opts _) loc = err (bugloc loc) id . nfx (GE gr rv opts loc)
|
|
||||||
|
|
||||||
nfx :: GlobalEnv -> Term -> Err Term
|
|
||||||
nfx env@(GE _ _ _ loc) t = do
|
|
||||||
v <- eval env [] t
|
|
||||||
return (value2term loc [] v)
|
|
||||||
-- Old value2term error message:
|
|
||||||
-- Left i -> fail ("variable #"++show i++" is out of scope")
|
|
||||||
|
|
||||||
eval :: GlobalEnv -> Env -> Term -> Err Value
|
|
||||||
eval (GE gr rvs opts loc) env t = ($ (map snd env)) # value cenv t
|
|
||||||
where
|
|
||||||
cenv = CE gr rvs opts loc (map fst env)
|
|
||||||
|
|
||||||
--apply env = apply' env
|
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
-- * Environments
|
|
||||||
|
|
||||||
type ResourceValues = Map.Map ModuleName (Map.Map Ident (Err Value))
|
|
||||||
|
|
||||||
data GlobalEnv = GE Grammar ResourceValues Options GLocation
|
|
||||||
data CompleteEnv = CE {srcgr::Grammar,rvs::ResourceValues,
|
|
||||||
opts::Options,
|
|
||||||
gloc::GLocation,local::LocalScope}
|
|
||||||
type GLocation = L Ident
|
|
||||||
type LocalScope = [Ident]
|
|
||||||
type Stack = [Value]
|
|
||||||
type OpenValue = Stack->Value
|
|
||||||
|
|
||||||
geLoc (GE _ _ _ loc) = loc
|
|
||||||
geGrammar (GE gr _ _ _) = gr
|
|
||||||
|
|
||||||
ext b env = env{local=b:local env}
|
|
||||||
extend bs env = env{local=bs++local env}
|
|
||||||
global env = GE (srcgr env) (rvs env) (opts env) (gloc env)
|
|
||||||
|
|
||||||
var :: CompleteEnv -> Ident -> Err OpenValue
|
|
||||||
var env x = maybe unbound pick' (elemIndex x (local env))
|
|
||||||
where
|
|
||||||
unbound = fail ("Unknown variable: "++showIdent x)
|
|
||||||
pick' i = return $ \ vs -> maybe (err i vs) ok (pick i vs)
|
|
||||||
err i vs = bug $ "Stack problem: "++showIdent x++": "
|
|
||||||
++unwords (map showIdent (local env))
|
|
||||||
++" => "++show (i,length vs)
|
|
||||||
ok v = --trace ("var "++show x++" = "++show v) $
|
|
||||||
v
|
|
||||||
|
|
||||||
pick :: Int -> Stack -> Maybe Value
|
|
||||||
pick 0 (v:_) = Just v
|
|
||||||
pick i (_:vs) = pick (i-1) vs
|
|
||||||
pick i vs = Nothing -- bug $ "pick "++show (i,vs)
|
|
||||||
|
|
||||||
resource env (m,c) =
|
|
||||||
-- err bug id $
|
|
||||||
if isPredefCat c
|
|
||||||
then value0 env =<< lockRecType c defLinType -- hmm
|
|
||||||
else maybe e id $ Map.lookup c =<< Map.lookup m (rvs env)
|
|
||||||
where e = fail $ "Not found: "++render m++"."++showIdent c
|
|
||||||
|
|
||||||
-- | Convert operators once, not every time they are looked up
|
|
||||||
resourceValues :: Options -> SourceGrammar -> GlobalEnv
|
|
||||||
resourceValues opts gr = env
|
|
||||||
where
|
|
||||||
env = GE gr rvs opts (L NoLoc identW)
|
|
||||||
rvs = Map.mapWithKey moduleResources (moduleMap gr)
|
|
||||||
moduleResources m = Map.mapWithKey (moduleResource m) . jments
|
|
||||||
moduleResource m c _info = do L l t <- lookupResDefLoc gr (m,c)
|
|
||||||
let loc = L l c
|
|
||||||
qloc = L l (Q (m,c))
|
|
||||||
eval (GE gr rvs opts loc) [] (traceRes qloc t)
|
|
||||||
|
|
||||||
traceRes = if flag optTrace opts
|
|
||||||
then traceResource
|
|
||||||
else const id
|
|
||||||
|
|
||||||
-- * Tracing
|
|
||||||
|
|
||||||
-- | Insert a call to the trace function under the top-level lambdas
|
|
||||||
traceResource (L l q) t =
|
|
||||||
case termFormCnc t of
|
|
||||||
(abs,body) -> mkAbs abs (mkApp traceQ [args,body])
|
|
||||||
where
|
|
||||||
args = R $ tuple2record (K lstr:[Vr x|(bt,x)<-abs,bt==Explicit])
|
|
||||||
lstr = render (l<>":"<>ppTerm Qualified 0 q)
|
|
||||||
traceQ = Q (cPredef,cTrace)
|
|
||||||
|
|
||||||
-- * Computing values
|
|
||||||
|
|
||||||
-- | Computing the value of a top-level term
|
|
||||||
value0 :: CompleteEnv -> Term -> Err Value
|
|
||||||
value0 env = eval (global env) []
|
|
||||||
|
|
||||||
-- | Computing the value of a term
|
|
||||||
value :: CompleteEnv -> Term -> Err OpenValue
|
|
||||||
value env t0 =
|
|
||||||
-- Each terms is traversed only once by this function, using only statically
|
|
||||||
-- available information. Notably, the values of lambda bound variables
|
|
||||||
-- will be unknown during the term traversal phase.
|
|
||||||
-- The result is an OpenValue, which is a function that may be applied many
|
|
||||||
-- times to different dynamic values, but without the term traversal overhead
|
|
||||||
-- and without recomputing other statically known information.
|
|
||||||
-- For this to work, there should be no recursive calls under lambdas here.
|
|
||||||
-- Whenever we need to construct the OpenValue function with an explicit
|
|
||||||
-- lambda, we have to lift the recursive calls outside the lambda.
|
|
||||||
-- (See e.g. the rules for Let, Prod and Abs)
|
|
||||||
{-
|
|
||||||
trace (render $ text "value"<+>sep [ppL (gloc env)<>text ":",
|
|
||||||
brackets (fsep (map ppIdent (local env))),
|
|
||||||
ppTerm Unqualified 10 t0]) $
|
|
||||||
--}
|
|
||||||
errIn (render t0) $
|
|
||||||
case t0 of
|
|
||||||
Vr x -> var env x
|
|
||||||
Q x@(m,f)
|
|
||||||
| m == cPredef -> if f==cErrorType -- to be removed
|
|
||||||
then let p = identS "P"
|
|
||||||
in const # value0 env (mkProd [(Implicit,p,typeType)] (Vr p) [])
|
|
||||||
else if f==cPBool
|
|
||||||
then const # resource env x
|
|
||||||
else const . flip VApp [] # predef f
|
|
||||||
| otherwise -> const # resource env x --valueResDef (fst env) x
|
|
||||||
QC x -> return $ const (VCApp x [])
|
|
||||||
App e1 e2 -> apply' env e1 . (:[]) =<< value env e2
|
|
||||||
Let (x,(oty,t)) body -> do vb <- value (ext x env) body
|
|
||||||
vt <- value env t
|
|
||||||
return $ \ vs -> vb (vt vs:vs)
|
|
||||||
Meta i -> return $ \ vs -> VMeta i (zip (local env) vs) []
|
|
||||||
Prod bt x t1 t2 ->
|
|
||||||
do vt1 <- value env t1
|
|
||||||
vt2 <- value (ext x env) t2
|
|
||||||
return $ \ vs -> VProd bt (vt1 vs) x $ Bind $ \ vx -> vt2 (vx:vs)
|
|
||||||
Abs bt x t -> do vt <- value (ext x env) t
|
|
||||||
return $ VAbs bt x . Bind . \ vs vx -> vt (vx:vs)
|
|
||||||
EInt n -> return $ const (VInt n)
|
|
||||||
EFloat f -> return $ const (VFloat f)
|
|
||||||
K s -> return $ const (VString s)
|
|
||||||
Empty -> return $ const (VString "")
|
|
||||||
Sort s | s == cTok -> return $ const (VSort cStr) -- to be removed
|
|
||||||
| otherwise -> return $ const (VSort s)
|
|
||||||
ImplArg t -> (VImplArg.) # value env t
|
|
||||||
Table p res -> liftM2 VTblType # value env p <# value env res
|
|
||||||
RecType rs -> do lovs <- mapPairsM (value env) rs
|
|
||||||
return $ \vs->VRecType $ mapSnd ($vs) lovs
|
|
||||||
t@(ExtR t1 t2) -> ((extR t.)# both id) # both (value env) (t1,t2)
|
|
||||||
FV ts -> ((vfv .) # sequence) # mapM (value env) ts
|
|
||||||
R as -> do lovs <- mapPairsM (value env.snd) as
|
|
||||||
return $ \ vs->VRec $ mapSnd ($vs) lovs
|
|
||||||
T i cs -> valueTable env i cs
|
|
||||||
V ty ts -> do pvs <- paramValues env ty
|
|
||||||
((VV ty pvs .) . sequence) # mapM (value env) ts
|
|
||||||
C t1 t2 -> ((ok2p vconcat.) # both id) # both (value env) (t1,t2)
|
|
||||||
S t1 t2 -> ((select env.) # both id) # both (value env) (t1,t2)
|
|
||||||
P t l -> --maybe (bug $ "project "++show l++" from "++show v) id $
|
|
||||||
do ov <- value env t
|
|
||||||
return $ \ vs -> let v = ov vs
|
|
||||||
in maybe (VP v l) id (proj l v)
|
|
||||||
Alts t tts -> (\v vts -> VAlts # v <# mapM (both id) vts) # value env t <# mapM (both (value env)) tts
|
|
||||||
Strs ts -> ((VStrs.) # sequence) # mapM (value env) ts
|
|
||||||
Glue t1 t2 -> ((ok2p (glue env).) # both id) # both (value env) (t1,t2)
|
|
||||||
ELin c r -> (unlockVRec (gloc env) c.) # value env r
|
|
||||||
EPatt p -> return $ const (VPatt p) -- hmm
|
|
||||||
EPattType ty -> do vt <- value env ty
|
|
||||||
return (VPattType . vt)
|
|
||||||
Typed t ty -> value env t
|
|
||||||
t -> fail.render $ "value"<+>ppTerm Unqualified 10 t $$ show t
|
|
||||||
|
|
||||||
vconcat vv@(v1,v2) =
|
|
||||||
case vv of
|
|
||||||
(VString "",_) -> v2
|
|
||||||
(_,VString "") -> v1
|
|
||||||
(VApp NonExist _,_) -> v1
|
|
||||||
(_,VApp NonExist _) -> v2
|
|
||||||
_ -> VC v1 v2
|
|
||||||
|
|
||||||
proj l v | isLockLabel l = return (VRec [])
|
|
||||||
---- a workaround 18/2/2005: take this away and find the reason
|
|
||||||
---- why earlier compilation destroys the lock field
|
|
||||||
proj l v =
|
|
||||||
case v of
|
|
||||||
VFV vs -> liftM vfv (mapM (proj l) vs)
|
|
||||||
VRec rs -> lookup l rs
|
|
||||||
-- VExtR v1 v2 -> proj l v2 `mplus` proj l v1 -- hmm
|
|
||||||
VS (VV pty pvs rs) v2 -> flip VS v2 . VV pty pvs # mapM (proj l) rs
|
|
||||||
_ -> return (ok1 VP v l)
|
|
||||||
|
|
||||||
ok1 f v1@(VError {}) _ = v1
|
|
||||||
ok1 f v1 v2 = f v1 v2
|
|
||||||
|
|
||||||
ok2 f v1@(VError {}) _ = v1
|
|
||||||
ok2 f _ v2@(VError {}) = v2
|
|
||||||
ok2 f v1 v2 = f v1 v2
|
|
||||||
|
|
||||||
ok2p f (v1@VError {},_) = v1
|
|
||||||
ok2p f (_,v2@VError {}) = v2
|
|
||||||
ok2p f vv = f vv
|
|
||||||
|
|
||||||
unlockVRec loc c0 v0 = v0
|
|
||||||
{-
|
|
||||||
unlockVRec loc c0 v0 = unlockVRec' c0 v0
|
|
||||||
where
|
|
||||||
unlockVRec' ::Ident -> Value -> Value
|
|
||||||
unlockVRec' c v =
|
|
||||||
case v of
|
|
||||||
-- VClosure env t -> err bug (VClosure env) (unlockRecord c t)
|
|
||||||
VAbs bt x (Bind f) -> VAbs bt x (Bind $ \ v -> unlockVRec' c (f v))
|
|
||||||
VRec rs -> plusVRec rs lock
|
|
||||||
-- _ -> VExtR v (VRec lock) -- hmm
|
|
||||||
_ -> {-trace (render $ ppL loc $ "unlock non-record "++show v0)-} v -- hmm
|
|
||||||
-- _ -> bugloc loc $ "unlock non-record "++show v0
|
|
||||||
where
|
|
||||||
lock = [(lockLabel c,VRec [])]
|
|
||||||
-}
|
|
||||||
|
|
||||||
-- suspicious, but backwards compatible
|
|
||||||
plusVRec rs1 rs2 = VRec ([(l,v)|(l,v)<-rs1,l `notElem` ls2] ++ rs2)
|
|
||||||
where ls2 = map fst rs2
|
|
||||||
|
|
||||||
extR t vv =
|
|
||||||
case vv of
|
|
||||||
(VFV vs,v2) -> vfv [extR t (v1,v2)|v1<-vs]
|
|
||||||
(v1,VFV vs) -> vfv [extR t (v1,v2)|v2<-vs]
|
|
||||||
(VRecType rs1, VRecType rs2) ->
|
|
||||||
case intersect (map fst rs1) (map fst rs2) of
|
|
||||||
[] -> VRecType (rs1 ++ rs2)
|
|
||||||
ls -> error $ "clash"<+>show ls
|
|
||||||
(VRec rs1, VRec rs2) -> plusVRec rs1 rs2
|
|
||||||
(v1 , VRec [(l,_)]) | isLockLabel l -> v1 -- hmm
|
|
||||||
(VS (VV t pvs vs) s,v2) -> VS (VV t pvs [extR t (v1,v2)|v1<-vs]) s
|
|
||||||
-- (v1,v2) -> ok2 VExtR v1 v2 -- hmm
|
|
||||||
(v1,v2) -> error $ "not records" $$ show v1 $$ show v2
|
|
||||||
where
|
|
||||||
error explain = ppbug $ "The term" <+> t
|
|
||||||
<+> "is not reducible" $$ explain
|
|
||||||
|
|
||||||
glue env (v1,v2) = glu v1 v2
|
|
||||||
where
|
|
||||||
glu v1 v2 =
|
|
||||||
case (v1,v2) of
|
|
||||||
(VFV vs,v2) -> vfv [glu v1 v2|v1<-vs]
|
|
||||||
(v1,VFV vs) -> vfv [glu v1 v2|v2<-vs]
|
|
||||||
(VString s1,VString s2) -> VString (s1++s2)
|
|
||||||
(v1,VAlts d vs) -> VAlts (glx d) [(glx v,c) | (v,c) <- vs]
|
|
||||||
where glx v2 = glu v1 v2
|
|
||||||
(v1@(VAlts {}),v2) ->
|
|
||||||
--err (const (ok2 VGlue v1 v2)) id $
|
|
||||||
err bug id $
|
|
||||||
do y' <- strsFromValue v2
|
|
||||||
x' <- strsFromValue v1
|
|
||||||
return $ vfv [foldr1 VC (map VString (str2strings (glueStr v u))) | v <- x', u <- y']
|
|
||||||
(VC va vb,v2) -> VC va (glu vb v2)
|
|
||||||
(v1,VC va vb) -> VC (glu v1 va) vb
|
|
||||||
(VS (VV ty pvs vs) vb,v2) -> VS (VV ty pvs [glu v v2|v<-vs]) vb
|
|
||||||
(v1,VS (VV ty pvs vs) vb) -> VS (VV ty pvs [glu v1 v|v<-vs]) vb
|
|
||||||
(v1@(VApp NonExist _),_) -> v1
|
|
||||||
(_,v2@(VApp NonExist _)) -> v2
|
|
||||||
-- (v1,v2) -> ok2 VGlue v1 v2
|
|
||||||
(v1,v2) -> if flag optPlusAsBind (opts env)
|
|
||||||
then VC v1 (VC (VApp BIND []) v2)
|
|
||||||
else let loc = gloc env
|
|
||||||
vt v = value2term loc (local env) v
|
|
||||||
-- Old value2term error message:
|
|
||||||
-- Left i -> Error ('#':show i)
|
|
||||||
originalMsg = render $ ppL loc (hang "unsupported token gluing" 4
|
|
||||||
(Glue (vt v1) (vt v2)))
|
|
||||||
term = render $ pp $ Glue (vt v1) (vt v2)
|
|
||||||
in error $ unlines
|
|
||||||
[originalMsg
|
|
||||||
,""
|
|
||||||
,"There was a problem in the expression `"++term++"`, either:"
|
|
||||||
,"1) You are trying to use + on runtime arguments, possibly via an oper."
|
|
||||||
,"2) One of the arguments in `"++term++"` is a bound variable from pattern matching a string, but the cases are non-exhaustive."
|
|
||||||
,"For more help see https://github.com/GrammaticalFramework/gf-core/tree/master/doc/errors/gluing.md"
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
-- | to get a string from a value that represents a sequence of terminals
|
|
||||||
strsFromValue :: Value -> Err [Str]
|
|
||||||
strsFromValue t = case t of
|
|
||||||
VString s -> return [str s]
|
|
||||||
VC s t -> do
|
|
||||||
s' <- strsFromValue s
|
|
||||||
t' <- strsFromValue t
|
|
||||||
return [plusStr x y | x <- s', y <- t']
|
|
||||||
{-
|
|
||||||
VGlue s t -> do
|
|
||||||
s' <- strsFromValue s
|
|
||||||
t' <- strsFromValue t
|
|
||||||
return [glueStr x y | x <- s', y <- t']
|
|
||||||
-}
|
|
||||||
VAlts d vs -> do
|
|
||||||
d0 <- strsFromValue d
|
|
||||||
v0 <- mapM (strsFromValue . fst) vs
|
|
||||||
c0 <- mapM (strsFromValue . snd) vs
|
|
||||||
--let vs' = zip v0 c0
|
|
||||||
return [strTok (str2strings def) vars |
|
|
||||||
def <- d0,
|
|
||||||
vars <- [[(str2strings v, map sstr c) | (v,c) <- zip vv c0] |
|
|
||||||
vv <- sequence v0]
|
|
||||||
]
|
|
||||||
VFV ts -> concat # mapM strsFromValue ts
|
|
||||||
VStrs ts -> concat # mapM strsFromValue ts
|
|
||||||
|
|
||||||
_ -> fail ("cannot get Str from value " ++ show t)
|
|
||||||
|
|
||||||
vfv vs = case nub vs of
|
|
||||||
[v] -> v
|
|
||||||
vs -> VFV vs
|
|
||||||
|
|
||||||
select env vv =
|
|
||||||
case vv of
|
|
||||||
(v1,VFV vs) -> vfv [select env (v1,v2)|v2<-vs]
|
|
||||||
(VFV vs,v2) -> vfv [select env (v1,v2)|v1<-vs]
|
|
||||||
(v1@(VV pty vs rs),v2) ->
|
|
||||||
err (const (VS v1 v2)) id $
|
|
||||||
do --ats <- allParamValues (srcgr env) pty
|
|
||||||
--let vs = map (value0 env) ats
|
|
||||||
i <- maybeErr "no match" $ findIndex (==v2) vs
|
|
||||||
return (ix (gloc env) "select" rs i)
|
|
||||||
(VT _ _ [(PW,Bind b)],_) -> {-trace "eliminate wild card table" $-} b []
|
|
||||||
(v1@(VT _ _ cs),v2) ->
|
|
||||||
err (\_->ok2 VS v1 v2) (err bug id . valueMatch env) $
|
|
||||||
match (gloc env) cs v2
|
|
||||||
(VS (VV pty pvs rs) v12,v2) -> VS (VV pty pvs [select env (v11,v2)|v11<-rs]) v12
|
|
||||||
(v1,v2) -> ok2 VS v1 v2
|
|
||||||
|
|
||||||
match loc cs v =
|
|
||||||
err bad return (matchPattern cs (value2term loc [] v))
|
|
||||||
-- Old value2term error message:
|
|
||||||
-- Left i -> bad ("variable #"++show i++" is out of scope")
|
|
||||||
where
|
|
||||||
bad = fail . ("In pattern matching: "++)
|
|
||||||
|
|
||||||
valueMatch :: CompleteEnv -> (Bind Env,Substitution) -> Err Value
|
|
||||||
valueMatch env (Bind f,env') = f # mapPairsM (value0 env) env'
|
|
||||||
|
|
||||||
valueTable :: CompleteEnv -> TInfo -> [Case] -> Err OpenValue
|
|
||||||
valueTable env i cs =
|
|
||||||
case i of
|
|
||||||
TComp ty -> do pvs <- paramValues env ty
|
|
||||||
((VV ty pvs .) # sequence) # mapM (value env.snd) cs
|
|
||||||
_ -> do ty <- getTableType i
|
|
||||||
cs' <- mapM valueCase cs
|
|
||||||
err (dynamic cs' ty) return (convert cs' ty)
|
|
||||||
where
|
|
||||||
dynamic cs' ty _ = cases cs' # value env ty
|
|
||||||
|
|
||||||
cases cs' vty vs = err keep ($vs) (convertv cs' (vty vs))
|
|
||||||
where
|
|
||||||
keep msg = --trace (msg++"\n"++render (ppTerm Unqualified 0 (T i cs))) $
|
|
||||||
VT wild (vty vs) (mapSnd ($vs) cs')
|
|
||||||
|
|
||||||
wild = case i of TWild _ -> True; _ -> False
|
|
||||||
|
|
||||||
convertv cs' vty =
|
|
||||||
convert' cs' =<< paramValues'' env (value2term (gloc env) [] vty)
|
|
||||||
-- Old value2term error message: Left i -> fail ("variable #"++show i++" is out of scope")
|
|
||||||
|
|
||||||
convert cs' ty = convert' cs' =<< paramValues' env ty
|
|
||||||
|
|
||||||
convert' cs' ((pty,vs),pvs) =
|
|
||||||
do sts <- mapM (matchPattern cs') vs
|
|
||||||
return $ \ vs -> VV pty pvs $ map (err bug id . valueMatch env)
|
|
||||||
(mapFst ($vs) sts)
|
|
||||||
|
|
||||||
valueCase (p,t) = do p' <- measurePatt # inlinePattMacro p
|
|
||||||
pvs <- linPattVars p'
|
|
||||||
vt <- value (extend pvs env) t
|
|
||||||
return (p',\vs-> Bind $ \bs-> vt (push' p' bs pvs vs))
|
|
||||||
|
|
||||||
inlinePattMacro p =
|
|
||||||
case p of
|
|
||||||
PM qc -> do r <- resource env qc
|
|
||||||
case r of
|
|
||||||
VPatt p' -> inlinePattMacro p'
|
|
||||||
_ -> ppbug $ hang "Expected pattern macro:" 4
|
|
||||||
(show r)
|
|
||||||
_ -> composPattOp inlinePattMacro p
|
|
||||||
|
|
||||||
|
|
||||||
paramValues env ty = snd # paramValues' env ty
|
|
||||||
|
|
||||||
paramValues' env ty = paramValues'' env =<< nfx (global env) ty
|
|
||||||
|
|
||||||
paramValues'' env pty = do ats <- allParamValues (srcgr env) pty
|
|
||||||
pvs <- mapM (eval (global env) []) ats
|
|
||||||
return ((pty,ats),pvs)
|
|
||||||
|
|
||||||
push' p bs xs = if length bs/=length xs
|
|
||||||
then bug $ "push "++show (p,bs,xs)
|
|
||||||
else push bs xs
|
|
||||||
|
|
||||||
push :: Env -> LocalScope -> Stack -> Stack
|
|
||||||
push bs [] vs = vs
|
|
||||||
push bs (x:xs) vs = maybe err id (lookup x bs):push bs xs vs
|
|
||||||
where err = bug $ "Unbound pattern variable "++showIdent x
|
|
||||||
|
|
||||||
apply' :: CompleteEnv -> Term -> [OpenValue] -> Err OpenValue
|
|
||||||
apply' env t [] = value env t
|
|
||||||
apply' env t vs =
|
|
||||||
case t of
|
|
||||||
QC x -> return $ \ svs -> VCApp x (map ($svs) vs)
|
|
||||||
{-
|
|
||||||
Q x@(m,f) | m==cPredef -> return $
|
|
||||||
let constr = --trace ("predef "++show x) .
|
|
||||||
VApp x
|
|
||||||
in \ svs -> maybe constr id (Map.lookup f predefs)
|
|
||||||
$ map ($svs) vs
|
|
||||||
| otherwise -> do r <- resource env x
|
|
||||||
return $ \ svs -> vapply (gloc env) r (map ($svs) vs)
|
|
||||||
-}
|
|
||||||
App t1 t2 -> apply' env t1 . (:vs) =<< value env t2
|
|
||||||
_ -> do fv <- value env t
|
|
||||||
return $ \ svs -> vapply (gloc env) (fv svs) (map ($svs) vs)
|
|
||||||
|
|
||||||
vapply :: GLocation -> Value -> [Value] -> Value
|
|
||||||
vapply loc v [] = v
|
|
||||||
vapply loc v vs =
|
|
||||||
case v of
|
|
||||||
VError {} -> v
|
|
||||||
-- VClosure env (Abs b x t) -> beta gr env b x t vs
|
|
||||||
VAbs bt _ (Bind f) -> vbeta loc bt f vs
|
|
||||||
VApp pre vs1 -> delta' pre (vs1++vs)
|
|
||||||
where
|
|
||||||
delta' Trace (v1:v2:vs) = let vr = vapply loc v2 vs
|
|
||||||
in vtrace loc v1 vr
|
|
||||||
delta' pre vs = err msg vfv $ mapM (delta pre) (varyList vs)
|
|
||||||
--msg = const (VApp pre (vs1++vs))
|
|
||||||
msg = bug . (("Applying Predef."++showIdent (predefName pre)++": ")++)
|
|
||||||
VS (VV t pvs fs) s -> VS (VV t pvs [vapply loc f vs|f<-fs]) s
|
|
||||||
VFV fs -> vfv [vapply loc f vs|f<-fs]
|
|
||||||
VCApp f vs0 -> VCApp f (vs0++vs)
|
|
||||||
VMeta i env vs0 -> VMeta i env (vs0++vs)
|
|
||||||
VGen i vs0 -> VGen i (vs0++vs)
|
|
||||||
v -> bug $ "vapply "++show v++" "++show vs
|
|
||||||
|
|
||||||
vbeta loc bt f (v:vs) =
|
|
||||||
case (bt,v) of
|
|
||||||
(Implicit,VImplArg v) -> ap v
|
|
||||||
(Explicit, v) -> ap v
|
|
||||||
where
|
|
||||||
ap (VFV avs) = vfv [vapply loc (f v) vs|v<-avs]
|
|
||||||
ap v = vapply loc (f v) vs
|
|
||||||
|
|
||||||
vary (VFV vs) = vs
|
|
||||||
vary v = [v]
|
|
||||||
varyList = mapM vary
|
|
||||||
|
|
||||||
{-
|
|
||||||
beta env b x t (v:vs) =
|
|
||||||
case (b,v) of
|
|
||||||
(Implicit,VImplArg v) -> apply' (ext (x,v) env) t vs
|
|
||||||
(Explicit, v) -> apply' (ext (x,v) env) t vs
|
|
||||||
-}
|
|
||||||
|
|
||||||
vtrace loc arg res = trace (render (hang (pv arg) 4 ("->"<+>pv res))) res
|
|
||||||
where
|
|
||||||
pv v = case v of
|
|
||||||
VRec (f:as) -> hang (pf f) 4 (fsep (map pa as))
|
|
||||||
_ -> ppV v
|
|
||||||
pf (_,VString n) = pp n
|
|
||||||
pf (_,v) = ppV v
|
|
||||||
pa (_,v) = ppV v
|
|
||||||
ppV v = ppTerm Unqualified 10 (value2term' True loc [] v)
|
|
||||||
-- Old value2term error message:
|
|
||||||
-- Left i -> "variable #" <> pp i <+> "is out of scope"
|
|
||||||
|
|
||||||
-- | Convert a value back to a term
|
|
||||||
value2term :: GLocation -> [Ident] -> Value -> Term
|
|
||||||
value2term = value2term' False
|
|
||||||
|
|
||||||
value2term' :: Bool -> p -> [Ident] -> Value -> Term
|
|
||||||
value2term' stop loc xs v0 =
|
|
||||||
case v0 of
|
|
||||||
VApp pre vs -> applyMany (Q (cPredef,predefName pre)) vs
|
|
||||||
VCApp f vs -> applyMany (QC f) vs
|
|
||||||
VGen j vs -> applyMany (var j) vs
|
|
||||||
VMeta j env vs -> applyMany (Meta j) vs
|
|
||||||
VProd bt v x f -> Prod bt x (v2t v) (v2t' x f)
|
|
||||||
VAbs bt x f -> Abs bt x (v2t' x f)
|
|
||||||
VInt n -> EInt n
|
|
||||||
VFloat f -> EFloat f
|
|
||||||
VString s -> if null s then Empty else K s
|
|
||||||
VSort s -> Sort s
|
|
||||||
VImplArg v -> ImplArg (v2t v)
|
|
||||||
VTblType p res -> Table (v2t p) (v2t res)
|
|
||||||
VRecType rs -> RecType [(l, v2t v) | (l,v) <- rs]
|
|
||||||
VRec as -> R [(l, (Nothing, v2t v)) | (l,v) <- as]
|
|
||||||
VV t _ vs -> V t (map v2t vs)
|
|
||||||
VT wild v cs -> T ((if wild then TWild else TTyped) (v2t v)) (map nfcase cs)
|
|
||||||
VFV vs -> FV (map v2t vs)
|
|
||||||
VC v1 v2 -> C (v2t v1) (v2t v2)
|
|
||||||
VS v1 v2 -> S (v2t v1) (v2t v2)
|
|
||||||
VP v l -> P (v2t v) l
|
|
||||||
VPatt p -> EPatt p
|
|
||||||
VPattType v -> EPattType $ v2t v
|
|
||||||
VAlts v vvs -> Alts (v2t v) [(v2t x, v2t y) | (x,y) <- vvs]
|
|
||||||
VStrs vs -> Strs (map v2t vs)
|
|
||||||
-- VGlue v1 v2 -> Glue (v2t v1) (v2t v2)
|
|
||||||
-- VExtR v1 v2 -> ExtR (v2t v1) (v2t v2)
|
|
||||||
VError err -> Error err
|
|
||||||
where
|
|
||||||
applyMany f vs = foldl App f (map v2t vs)
|
|
||||||
v2t = v2txs xs
|
|
||||||
v2txs = value2term' stop loc
|
|
||||||
v2t' x f = v2txs (x:xs) (bind f (gen xs))
|
|
||||||
|
|
||||||
var j
|
|
||||||
| j<length xs = Vr (reverse xs !! j)
|
|
||||||
| otherwise = error ("variable #"++show j++" is out of scope")
|
|
||||||
|
|
||||||
|
|
||||||
pushs xs e = foldr push e xs
|
|
||||||
push x (env,xs) = ((x,gen xs):env,x:xs)
|
|
||||||
gen xs = VGen (length xs) []
|
|
||||||
|
|
||||||
nfcase (p,f) = (,) p (v2txs xs' (bind f env'))
|
|
||||||
where (env',xs') = pushs (pattVars p) ([],xs)
|
|
||||||
|
|
||||||
bind (Bind f) x = if stop
|
|
||||||
then VSort (identS "...") -- hmm
|
|
||||||
else f x
|
|
||||||
|
|
||||||
|
|
||||||
linPattVars p =
|
|
||||||
if null dups
|
|
||||||
then return pvs
|
|
||||||
else fail.render $ hang "Pattern is not linear. All variable names on the left-hand side must be distinct." 4 (ppPatt Unqualified 0 p)
|
|
||||||
where
|
|
||||||
allpvs = allPattVars p
|
|
||||||
pvs = nub allpvs
|
|
||||||
dups = allpvs \\ pvs
|
|
||||||
|
|
||||||
pattVars = nub . allPattVars
|
|
||||||
allPattVars p =
|
|
||||||
case p of
|
|
||||||
PV i -> [i]
|
|
||||||
PAs i p -> i:allPattVars p
|
|
||||||
_ -> collectPattOp allPattVars p
|
|
||||||
|
|
||||||
---
|
|
||||||
ix loc fn xs i =
|
|
||||||
if i<n
|
|
||||||
then xs !! i
|
|
||||||
else bugloc loc $ "(!!): index too large in "++fn++", "++show i++"<"++show n
|
|
||||||
where n = length xs
|
|
||||||
|
|
||||||
infixl 1 #,<# --,@@
|
|
||||||
|
|
||||||
f # x = fmap f x
|
|
||||||
mf <# mx = ap mf mx
|
|
||||||
--m1 @@ m2 = (m1 =<<) . m2
|
|
||||||
|
|
||||||
both f (x,y) = (,) # f x <# f y
|
|
||||||
|
|
||||||
bugloc loc s = ppbug $ ppL loc s
|
|
||||||
|
|
||||||
bug msg = ppbug msg
|
|
||||||
ppbug doc = error $ render $ hang "Internal error in Compute.Concrete:" 4 doc
|
|
||||||
|
|||||||
588
src/compiler/GF/Compile/Compute/ConcreteNew.hs
Normal file
588
src/compiler/GF/Compile/Compute/ConcreteNew.hs
Normal file
@@ -0,0 +1,588 @@
|
|||||||
|
-- | Functions for computing the values of terms in the concrete syntax, in
|
||||||
|
-- | preparation for PMCFG generation.
|
||||||
|
module GF.Compile.Compute.ConcreteNew
|
||||||
|
(GlobalEnv, GLocation, resourceValues, geLoc, geGrammar,
|
||||||
|
normalForm,
|
||||||
|
Value(..), Bind(..), Env, value2term, eval, vapply
|
||||||
|
) where
|
||||||
|
import Prelude hiding ((<>)) -- GHC 8.4.1 clash with Text.PrettyPrint
|
||||||
|
|
||||||
|
import GF.Grammar hiding (Env, VGen, VApp, VRecType)
|
||||||
|
import GF.Grammar.Lookup(lookupResDefLoc,allParamValues)
|
||||||
|
import GF.Grammar.Predef(cPredef,cErrorType,cTok,cStr,cTrace,cPBool)
|
||||||
|
import GF.Grammar.PatternMatch(matchPattern,measurePatt)
|
||||||
|
import GF.Grammar.Lockfield(isLockLabel,lockRecType) --unlockRecord,lockLabel
|
||||||
|
import GF.Compile.Compute.Value hiding (Error)
|
||||||
|
import GF.Compile.Compute.Predef(predef,predefName,delta)
|
||||||
|
import GF.Data.Str(Str,glueStr,str2strings,str,sstr,plusStr,strTok)
|
||||||
|
import GF.Data.Operations(Err,err,errIn,maybeErr,mapPairsM)
|
||||||
|
import GF.Data.Utilities(mapFst,mapSnd)
|
||||||
|
import GF.Infra.Option
|
||||||
|
import Control.Monad(ap,liftM,liftM2) -- ,unless,mplus
|
||||||
|
import Data.List (findIndex,intersect,nub,elemIndex,(\\)) --,isInfixOf
|
||||||
|
--import Data.Char (isUpper,toUpper,toLower)
|
||||||
|
import GF.Text.Pretty
|
||||||
|
import qualified Data.Map as Map
|
||||||
|
import Debug.Trace(trace)
|
||||||
|
|
||||||
|
-- * Main entry points
|
||||||
|
|
||||||
|
normalForm :: GlobalEnv -> L Ident -> Term -> Term
|
||||||
|
normalForm (GE gr rv opts _) loc = err (bugloc loc) id . nfx (GE gr rv opts loc)
|
||||||
|
|
||||||
|
nfx env@(GE _ _ _ loc) t = do
|
||||||
|
v <- eval env [] t
|
||||||
|
case value2term loc [] v of
|
||||||
|
Left i -> fail ("variable #"++show i++" is out of scope")
|
||||||
|
Right t -> return t
|
||||||
|
|
||||||
|
eval :: GlobalEnv -> Env -> Term -> Err Value
|
||||||
|
eval (GE gr rvs opts loc) env t = ($ (map snd env)) # value cenv t
|
||||||
|
where
|
||||||
|
cenv = CE gr rvs opts loc (map fst env)
|
||||||
|
|
||||||
|
--apply env = apply' env
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- * Environments
|
||||||
|
|
||||||
|
type ResourceValues = Map.Map ModuleName (Map.Map Ident (Err Value))
|
||||||
|
|
||||||
|
data GlobalEnv = GE Grammar ResourceValues Options GLocation
|
||||||
|
data CompleteEnv = CE {srcgr::Grammar,rvs::ResourceValues,
|
||||||
|
opts::Options,
|
||||||
|
gloc::GLocation,local::LocalScope}
|
||||||
|
type GLocation = L Ident
|
||||||
|
type LocalScope = [Ident]
|
||||||
|
type Stack = [Value]
|
||||||
|
type OpenValue = Stack->Value
|
||||||
|
|
||||||
|
geLoc (GE _ _ _ loc) = loc
|
||||||
|
geGrammar (GE gr _ _ _) = gr
|
||||||
|
|
||||||
|
ext b env = env{local=b:local env}
|
||||||
|
extend bs env = env{local=bs++local env}
|
||||||
|
global env = GE (srcgr env) (rvs env) (opts env) (gloc env)
|
||||||
|
|
||||||
|
var :: CompleteEnv -> Ident -> Err OpenValue
|
||||||
|
var env x = maybe unbound pick' (elemIndex x (local env))
|
||||||
|
where
|
||||||
|
unbound = fail ("Unknown variable: "++showIdent x)
|
||||||
|
pick' i = return $ \ vs -> maybe (err i vs) ok (pick i vs)
|
||||||
|
err i vs = bug $ "Stack problem: "++showIdent x++": "
|
||||||
|
++unwords (map showIdent (local env))
|
||||||
|
++" => "++show (i,length vs)
|
||||||
|
ok v = --trace ("var "++show x++" = "++show v) $
|
||||||
|
v
|
||||||
|
|
||||||
|
pick :: Int -> Stack -> Maybe Value
|
||||||
|
pick 0 (v:_) = Just v
|
||||||
|
pick i (_:vs) = pick (i-1) vs
|
||||||
|
pick i vs = Nothing -- bug $ "pick "++show (i,vs)
|
||||||
|
|
||||||
|
resource env (m,c) =
|
||||||
|
-- err bug id $
|
||||||
|
if isPredefCat c
|
||||||
|
then value0 env =<< lockRecType c defLinType -- hmm
|
||||||
|
else maybe e id $ Map.lookup c =<< Map.lookup m (rvs env)
|
||||||
|
where e = fail $ "Not found: "++render m++"."++showIdent c
|
||||||
|
|
||||||
|
-- | Convert operators once, not every time they are looked up
|
||||||
|
resourceValues :: Options -> SourceGrammar -> GlobalEnv
|
||||||
|
resourceValues opts gr = env
|
||||||
|
where
|
||||||
|
env = GE gr rvs opts (L NoLoc identW)
|
||||||
|
rvs = Map.mapWithKey moduleResources (moduleMap gr)
|
||||||
|
moduleResources m = Map.mapWithKey (moduleResource m) . jments
|
||||||
|
moduleResource m c _info = do L l t <- lookupResDefLoc gr (m,c)
|
||||||
|
let loc = L l c
|
||||||
|
qloc = L l (Q (m,c))
|
||||||
|
eval (GE gr rvs opts loc) [] (traceRes qloc t)
|
||||||
|
|
||||||
|
traceRes = if flag optTrace opts
|
||||||
|
then traceResource
|
||||||
|
else const id
|
||||||
|
|
||||||
|
-- * Tracing
|
||||||
|
|
||||||
|
-- | Insert a call to the trace function under the top-level lambdas
|
||||||
|
traceResource (L l q) t =
|
||||||
|
case termFormCnc t of
|
||||||
|
(abs,body) -> mkAbs abs (mkApp traceQ [args,body])
|
||||||
|
where
|
||||||
|
args = R $ tuple2record (K lstr:[Vr x|(bt,x)<-abs,bt==Explicit])
|
||||||
|
lstr = render (l<>":"<>ppTerm Qualified 0 q)
|
||||||
|
traceQ = Q (cPredef,cTrace)
|
||||||
|
|
||||||
|
-- * Computing values
|
||||||
|
|
||||||
|
-- | Computing the value of a top-level term
|
||||||
|
value0 :: CompleteEnv -> Term -> Err Value
|
||||||
|
value0 env = eval (global env) []
|
||||||
|
|
||||||
|
-- | Computing the value of a term
|
||||||
|
value :: CompleteEnv -> Term -> Err OpenValue
|
||||||
|
value env t0 =
|
||||||
|
-- Each terms is traversed only once by this function, using only statically
|
||||||
|
-- available information. Notably, the values of lambda bound variables
|
||||||
|
-- will be unknown during the term traversal phase.
|
||||||
|
-- The result is an OpenValue, which is a function that may be applied many
|
||||||
|
-- times to different dynamic values, but without the term traversal overhead
|
||||||
|
-- and without recomputing other statically known information.
|
||||||
|
-- For this to work, there should be no recursive calls under lambdas here.
|
||||||
|
-- Whenever we need to construct the OpenValue function with an explicit
|
||||||
|
-- lambda, we have to lift the recursive calls outside the lambda.
|
||||||
|
-- (See e.g. the rules for Let, Prod and Abs)
|
||||||
|
{-
|
||||||
|
trace (render $ text "value"<+>sep [ppL (gloc env)<>text ":",
|
||||||
|
brackets (fsep (map ppIdent (local env))),
|
||||||
|
ppTerm Unqualified 10 t0]) $
|
||||||
|
--}
|
||||||
|
errIn (render t0) $
|
||||||
|
case t0 of
|
||||||
|
Vr x -> var env x
|
||||||
|
Q x@(m,f)
|
||||||
|
| m == cPredef -> if f==cErrorType -- to be removed
|
||||||
|
then let p = identS "P"
|
||||||
|
in const # value0 env (mkProd [(Implicit,p,typeType)] (Vr p) [])
|
||||||
|
else if f==cPBool
|
||||||
|
then const # resource env x
|
||||||
|
else const . flip VApp [] # predef f
|
||||||
|
| otherwise -> const # resource env x --valueResDef (fst env) x
|
||||||
|
QC x -> return $ const (VCApp x [])
|
||||||
|
App e1 e2 -> apply' env e1 . (:[]) =<< value env e2
|
||||||
|
Let (x,(oty,t)) body -> do vb <- value (ext x env) body
|
||||||
|
vt <- value env t
|
||||||
|
return $ \ vs -> vb (vt vs:vs)
|
||||||
|
Meta i -> return $ \ vs -> VMeta i (zip (local env) vs) []
|
||||||
|
Prod bt x t1 t2 ->
|
||||||
|
do vt1 <- value env t1
|
||||||
|
vt2 <- value (ext x env) t2
|
||||||
|
return $ \ vs -> VProd bt (vt1 vs) x $ Bind $ \ vx -> vt2 (vx:vs)
|
||||||
|
Abs bt x t -> do vt <- value (ext x env) t
|
||||||
|
return $ VAbs bt x . Bind . \ vs vx -> vt (vx:vs)
|
||||||
|
EInt n -> return $ const (VInt n)
|
||||||
|
EFloat f -> return $ const (VFloat f)
|
||||||
|
K s -> return $ const (VString s)
|
||||||
|
Empty -> return $ const (VString "")
|
||||||
|
Sort s | s == cTok -> return $ const (VSort cStr) -- to be removed
|
||||||
|
| otherwise -> return $ const (VSort s)
|
||||||
|
ImplArg t -> (VImplArg.) # value env t
|
||||||
|
Table p res -> liftM2 VTblType # value env p <# value env res
|
||||||
|
RecType rs -> do lovs <- mapPairsM (value env) rs
|
||||||
|
return $ \vs->VRecType $ mapSnd ($vs) lovs
|
||||||
|
t@(ExtR t1 t2) -> ((extR t.)# both id) # both (value env) (t1,t2)
|
||||||
|
FV ts -> ((vfv .) # sequence) # mapM (value env) ts
|
||||||
|
R as -> do lovs <- mapPairsM (value env.snd) as
|
||||||
|
return $ \ vs->VRec $ mapSnd ($vs) lovs
|
||||||
|
T i cs -> valueTable env i cs
|
||||||
|
V ty ts -> do pvs <- paramValues env ty
|
||||||
|
((VV ty pvs .) . sequence) # mapM (value env) ts
|
||||||
|
C t1 t2 -> ((ok2p vconcat.) # both id) # both (value env) (t1,t2)
|
||||||
|
S t1 t2 -> ((select env.) # both id) # both (value env) (t1,t2)
|
||||||
|
P t l -> --maybe (bug $ "project "++show l++" from "++show v) id $
|
||||||
|
do ov <- value env t
|
||||||
|
return $ \ vs -> let v = ov vs
|
||||||
|
in maybe (VP v l) id (proj l v)
|
||||||
|
Alts t tts -> (\v vts -> VAlts # v <# mapM (both id) vts) # value env t <# mapM (both (value env)) tts
|
||||||
|
Strs ts -> ((VStrs.) # sequence) # mapM (value env) ts
|
||||||
|
Glue t1 t2 -> ((ok2p (glue env).) # both id) # both (value env) (t1,t2)
|
||||||
|
ELin c r -> (unlockVRec (gloc env) c.) # value env r
|
||||||
|
EPatt p -> return $ const (VPatt p) -- hmm
|
||||||
|
EPattType ty -> do vt <- value env ty
|
||||||
|
return (VPattType . vt)
|
||||||
|
Typed t ty -> value env t
|
||||||
|
t -> fail.render $ "value"<+>ppTerm Unqualified 10 t $$ show t
|
||||||
|
|
||||||
|
vconcat vv@(v1,v2) =
|
||||||
|
case vv of
|
||||||
|
(VString "",_) -> v2
|
||||||
|
(_,VString "") -> v1
|
||||||
|
(VApp NonExist _,_) -> v1
|
||||||
|
(_,VApp NonExist _) -> v2
|
||||||
|
_ -> VC v1 v2
|
||||||
|
|
||||||
|
proj l v | isLockLabel l = return (VRec [])
|
||||||
|
---- a workaround 18/2/2005: take this away and find the reason
|
||||||
|
---- why earlier compilation destroys the lock field
|
||||||
|
proj l v =
|
||||||
|
case v of
|
||||||
|
VFV vs -> liftM vfv (mapM (proj l) vs)
|
||||||
|
VRec rs -> lookup l rs
|
||||||
|
-- VExtR v1 v2 -> proj l v2 `mplus` proj l v1 -- hmm
|
||||||
|
VS (VV pty pvs rs) v2 -> flip VS v2 . VV pty pvs # mapM (proj l) rs
|
||||||
|
_ -> return (ok1 VP v l)
|
||||||
|
|
||||||
|
ok1 f v1@(VError {}) _ = v1
|
||||||
|
ok1 f v1 v2 = f v1 v2
|
||||||
|
|
||||||
|
ok2 f v1@(VError {}) _ = v1
|
||||||
|
ok2 f _ v2@(VError {}) = v2
|
||||||
|
ok2 f v1 v2 = f v1 v2
|
||||||
|
|
||||||
|
ok2p f (v1@VError {},_) = v1
|
||||||
|
ok2p f (_,v2@VError {}) = v2
|
||||||
|
ok2p f vv = f vv
|
||||||
|
|
||||||
|
unlockVRec loc c0 v0 = v0
|
||||||
|
{-
|
||||||
|
unlockVRec loc c0 v0 = unlockVRec' c0 v0
|
||||||
|
where
|
||||||
|
unlockVRec' ::Ident -> Value -> Value
|
||||||
|
unlockVRec' c v =
|
||||||
|
case v of
|
||||||
|
-- VClosure env t -> err bug (VClosure env) (unlockRecord c t)
|
||||||
|
VAbs bt x (Bind f) -> VAbs bt x (Bind $ \ v -> unlockVRec' c (f v))
|
||||||
|
VRec rs -> plusVRec rs lock
|
||||||
|
-- _ -> VExtR v (VRec lock) -- hmm
|
||||||
|
_ -> {-trace (render $ ppL loc $ "unlock non-record "++show v0)-} v -- hmm
|
||||||
|
-- _ -> bugloc loc $ "unlock non-record "++show v0
|
||||||
|
where
|
||||||
|
lock = [(lockLabel c,VRec [])]
|
||||||
|
-}
|
||||||
|
|
||||||
|
-- suspicious, but backwards compatible
|
||||||
|
plusVRec rs1 rs2 = VRec ([(l,v)|(l,v)<-rs1,l `notElem` ls2] ++ rs2)
|
||||||
|
where ls2 = map fst rs2
|
||||||
|
|
||||||
|
extR t vv =
|
||||||
|
case vv of
|
||||||
|
(VFV vs,v2) -> vfv [extR t (v1,v2)|v1<-vs]
|
||||||
|
(v1,VFV vs) -> vfv [extR t (v1,v2)|v2<-vs]
|
||||||
|
(VRecType rs1, VRecType rs2) ->
|
||||||
|
case intersect (map fst rs1) (map fst rs2) of
|
||||||
|
[] -> VRecType (rs1 ++ rs2)
|
||||||
|
ls -> error $ "clash"<+>show ls
|
||||||
|
(VRec rs1, VRec rs2) -> plusVRec rs1 rs2
|
||||||
|
(v1 , VRec [(l,_)]) | isLockLabel l -> v1 -- hmm
|
||||||
|
(VS (VV t pvs vs) s,v2) -> VS (VV t pvs [extR t (v1,v2)|v1<-vs]) s
|
||||||
|
-- (v1,v2) -> ok2 VExtR v1 v2 -- hmm
|
||||||
|
(v1,v2) -> error $ "not records" $$ show v1 $$ show v2
|
||||||
|
where
|
||||||
|
error explain = ppbug $ "The term" <+> t
|
||||||
|
<+> "is not reducible" $$ explain
|
||||||
|
|
||||||
|
glue env (v1,v2) = glu v1 v2
|
||||||
|
where
|
||||||
|
glu v1 v2 =
|
||||||
|
case (v1,v2) of
|
||||||
|
(VFV vs,v2) -> vfv [glu v1 v2|v1<-vs]
|
||||||
|
(v1,VFV vs) -> vfv [glu v1 v2|v2<-vs]
|
||||||
|
(VString s1,VString s2) -> VString (s1++s2)
|
||||||
|
(v1,VAlts d vs) -> VAlts (glx d) [(glx v,c) | (v,c) <- vs]
|
||||||
|
where glx v2 = glu v1 v2
|
||||||
|
(v1@(VAlts {}),v2) ->
|
||||||
|
--err (const (ok2 VGlue v1 v2)) id $
|
||||||
|
err bug id $
|
||||||
|
do y' <- strsFromValue v2
|
||||||
|
x' <- strsFromValue v1
|
||||||
|
return $ vfv [foldr1 VC (map VString (str2strings (glueStr v u))) | v <- x', u <- y']
|
||||||
|
(VC va vb,v2) -> VC va (glu vb v2)
|
||||||
|
(v1,VC va vb) -> VC (glu v1 va) vb
|
||||||
|
(VS (VV ty pvs vs) vb,v2) -> VS (VV ty pvs [glu v v2|v<-vs]) vb
|
||||||
|
(v1,VS (VV ty pvs vs) vb) -> VS (VV ty pvs [glu v1 v|v<-vs]) vb
|
||||||
|
(v1@(VApp NonExist _),_) -> v1
|
||||||
|
(_,v2@(VApp NonExist _)) -> v2
|
||||||
|
-- (v1,v2) -> ok2 VGlue v1 v2
|
||||||
|
(v1,v2) -> if flag optPlusAsBind (opts env)
|
||||||
|
then VC v1 (VC (VApp BIND []) v2)
|
||||||
|
else let loc = gloc env
|
||||||
|
vt v = case value2term loc (local env) v of
|
||||||
|
Left i -> Error ('#':show i)
|
||||||
|
Right t -> t
|
||||||
|
originalMsg = render $ ppL loc (hang "unsupported token gluing" 4
|
||||||
|
(Glue (vt v1) (vt v2)))
|
||||||
|
term = render $ pp $ Glue (vt v1) (vt v2)
|
||||||
|
in error $ unlines
|
||||||
|
[originalMsg
|
||||||
|
,""
|
||||||
|
,"There was a problem in the expression `"++term++"`, either:"
|
||||||
|
,"1) You are trying to use + on runtime arguments, possibly via an oper."
|
||||||
|
,"2) One of the arguments in `"++term++"` is a bound variable from pattern matching a string, but the cases are non-exhaustive."
|
||||||
|
,"For more help see https://github.com/GrammaticalFramework/gf-core/tree/master/doc/errors/gluing.md"
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
-- | to get a string from a value that represents a sequence of terminals
|
||||||
|
strsFromValue :: Value -> Err [Str]
|
||||||
|
strsFromValue t = case t of
|
||||||
|
VString s -> return [str s]
|
||||||
|
VC s t -> do
|
||||||
|
s' <- strsFromValue s
|
||||||
|
t' <- strsFromValue t
|
||||||
|
return [plusStr x y | x <- s', y <- t']
|
||||||
|
{-
|
||||||
|
VGlue s t -> do
|
||||||
|
s' <- strsFromValue s
|
||||||
|
t' <- strsFromValue t
|
||||||
|
return [glueStr x y | x <- s', y <- t']
|
||||||
|
-}
|
||||||
|
VAlts d vs -> do
|
||||||
|
d0 <- strsFromValue d
|
||||||
|
v0 <- mapM (strsFromValue . fst) vs
|
||||||
|
c0 <- mapM (strsFromValue . snd) vs
|
||||||
|
--let vs' = zip v0 c0
|
||||||
|
return [strTok (str2strings def) vars |
|
||||||
|
def <- d0,
|
||||||
|
vars <- [[(str2strings v, map sstr c) | (v,c) <- zip vv c0] |
|
||||||
|
vv <- sequence v0]
|
||||||
|
]
|
||||||
|
VFV ts -> concat # mapM strsFromValue ts
|
||||||
|
VStrs ts -> concat # mapM strsFromValue ts
|
||||||
|
|
||||||
|
_ -> fail ("cannot get Str from value " ++ show t)
|
||||||
|
|
||||||
|
vfv vs = case nub vs of
|
||||||
|
[v] -> v
|
||||||
|
vs -> VFV vs
|
||||||
|
|
||||||
|
select env vv =
|
||||||
|
case vv of
|
||||||
|
(v1,VFV vs) -> vfv [select env (v1,v2)|v2<-vs]
|
||||||
|
(VFV vs,v2) -> vfv [select env (v1,v2)|v1<-vs]
|
||||||
|
(v1@(VV pty vs rs),v2) ->
|
||||||
|
err (const (VS v1 v2)) id $
|
||||||
|
do --ats <- allParamValues (srcgr env) pty
|
||||||
|
--let vs = map (value0 env) ats
|
||||||
|
i <- maybeErr "no match" $ findIndex (==v2) vs
|
||||||
|
return (ix (gloc env) "select" rs i)
|
||||||
|
(VT _ _ [(PW,Bind b)],_) -> {-trace "eliminate wild card table" $-} b []
|
||||||
|
(v1@(VT _ _ cs),v2) ->
|
||||||
|
err (\_->ok2 VS v1 v2) (err bug id . valueMatch env) $
|
||||||
|
match (gloc env) cs v2
|
||||||
|
(VS (VV pty pvs rs) v12,v2) -> VS (VV pty pvs [select env (v11,v2)|v11<-rs]) v12
|
||||||
|
(v1,v2) -> ok2 VS v1 v2
|
||||||
|
|
||||||
|
match loc cs v =
|
||||||
|
case value2term loc [] v of
|
||||||
|
Left i -> bad ("variable #"++show i++" is out of scope")
|
||||||
|
Right t -> err bad return (matchPattern cs t)
|
||||||
|
where
|
||||||
|
bad = fail . ("In pattern matching: "++)
|
||||||
|
|
||||||
|
valueMatch :: CompleteEnv -> (Bind Env,Substitution) -> Err Value
|
||||||
|
valueMatch env (Bind f,env') = f # mapPairsM (value0 env) env'
|
||||||
|
|
||||||
|
valueTable :: CompleteEnv -> TInfo -> [Case] -> Err OpenValue
|
||||||
|
valueTable env i cs =
|
||||||
|
case i of
|
||||||
|
TComp ty -> do pvs <- paramValues env ty
|
||||||
|
((VV ty pvs .) # sequence) # mapM (value env.snd) cs
|
||||||
|
_ -> do ty <- getTableType i
|
||||||
|
cs' <- mapM valueCase cs
|
||||||
|
err (dynamic cs' ty) return (convert cs' ty)
|
||||||
|
where
|
||||||
|
dynamic cs' ty _ = cases cs' # value env ty
|
||||||
|
|
||||||
|
cases cs' vty vs = err keep ($vs) (convertv cs' (vty vs))
|
||||||
|
where
|
||||||
|
keep msg = --trace (msg++"\n"++render (ppTerm Unqualified 0 (T i cs))) $
|
||||||
|
VT wild (vty vs) (mapSnd ($vs) cs')
|
||||||
|
|
||||||
|
wild = case i of TWild _ -> True; _ -> False
|
||||||
|
|
||||||
|
convertv cs' vty =
|
||||||
|
case value2term (gloc env) [] vty of
|
||||||
|
Left i -> fail ("variable #"++show i++" is out of scope")
|
||||||
|
Right pty -> convert' cs' =<< paramValues'' env pty
|
||||||
|
|
||||||
|
convert cs' ty = convert' cs' =<< paramValues' env ty
|
||||||
|
|
||||||
|
convert' cs' ((pty,vs),pvs) =
|
||||||
|
do sts <- mapM (matchPattern cs') vs
|
||||||
|
return $ \ vs -> VV pty pvs $ map (err bug id . valueMatch env)
|
||||||
|
(mapFst ($vs) sts)
|
||||||
|
|
||||||
|
valueCase (p,t) = do p' <- measurePatt # inlinePattMacro p
|
||||||
|
pvs <- linPattVars p'
|
||||||
|
vt <- value (extend pvs env) t
|
||||||
|
return (p',\vs-> Bind $ \bs-> vt (push' p' bs pvs vs))
|
||||||
|
|
||||||
|
inlinePattMacro p =
|
||||||
|
case p of
|
||||||
|
PM qc -> do r <- resource env qc
|
||||||
|
case r of
|
||||||
|
VPatt p' -> inlinePattMacro p'
|
||||||
|
_ -> ppbug $ hang "Expected pattern macro:" 4
|
||||||
|
(show r)
|
||||||
|
_ -> composPattOp inlinePattMacro p
|
||||||
|
|
||||||
|
|
||||||
|
paramValues env ty = snd # paramValues' env ty
|
||||||
|
|
||||||
|
paramValues' env ty = paramValues'' env =<< nfx (global env) ty
|
||||||
|
|
||||||
|
paramValues'' env pty = do ats <- allParamValues (srcgr env) pty
|
||||||
|
pvs <- mapM (eval (global env) []) ats
|
||||||
|
return ((pty,ats),pvs)
|
||||||
|
|
||||||
|
push' p bs xs = if length bs/=length xs
|
||||||
|
then bug $ "push "++show (p,bs,xs)
|
||||||
|
else push bs xs
|
||||||
|
|
||||||
|
push :: Env -> LocalScope -> Stack -> Stack
|
||||||
|
push bs [] vs = vs
|
||||||
|
push bs (x:xs) vs = maybe err id (lookup x bs):push bs xs vs
|
||||||
|
where err = bug $ "Unbound pattern variable "++showIdent x
|
||||||
|
|
||||||
|
apply' :: CompleteEnv -> Term -> [OpenValue] -> Err OpenValue
|
||||||
|
apply' env t [] = value env t
|
||||||
|
apply' env t vs =
|
||||||
|
case t of
|
||||||
|
QC x -> return $ \ svs -> VCApp x (map ($svs) vs)
|
||||||
|
{-
|
||||||
|
Q x@(m,f) | m==cPredef -> return $
|
||||||
|
let constr = --trace ("predef "++show x) .
|
||||||
|
VApp x
|
||||||
|
in \ svs -> maybe constr id (Map.lookup f predefs)
|
||||||
|
$ map ($svs) vs
|
||||||
|
| otherwise -> do r <- resource env x
|
||||||
|
return $ \ svs -> vapply (gloc env) r (map ($svs) vs)
|
||||||
|
-}
|
||||||
|
App t1 t2 -> apply' env t1 . (:vs) =<< value env t2
|
||||||
|
_ -> do fv <- value env t
|
||||||
|
return $ \ svs -> vapply (gloc env) (fv svs) (map ($svs) vs)
|
||||||
|
|
||||||
|
vapply :: GLocation -> Value -> [Value] -> Value
|
||||||
|
vapply loc v [] = v
|
||||||
|
vapply loc v vs =
|
||||||
|
case v of
|
||||||
|
VError {} -> v
|
||||||
|
-- VClosure env (Abs b x t) -> beta gr env b x t vs
|
||||||
|
VAbs bt _ (Bind f) -> vbeta loc bt f vs
|
||||||
|
VApp pre vs1 -> delta' pre (vs1++vs)
|
||||||
|
where
|
||||||
|
delta' Trace (v1:v2:vs) = let vr = vapply loc v2 vs
|
||||||
|
in vtrace loc v1 vr
|
||||||
|
delta' pre vs = err msg vfv $ mapM (delta pre) (varyList vs)
|
||||||
|
--msg = const (VApp pre (vs1++vs))
|
||||||
|
msg = bug . (("Applying Predef."++showIdent (predefName pre)++": ")++)
|
||||||
|
VS (VV t pvs fs) s -> VS (VV t pvs [vapply loc f vs|f<-fs]) s
|
||||||
|
VFV fs -> vfv [vapply loc f vs|f<-fs]
|
||||||
|
VCApp f vs0 -> VCApp f (vs0++vs)
|
||||||
|
VMeta i env vs0 -> VMeta i env (vs0++vs)
|
||||||
|
VGen i vs0 -> VGen i (vs0++vs)
|
||||||
|
v -> bug $ "vapply "++show v++" "++show vs
|
||||||
|
|
||||||
|
vbeta loc bt f (v:vs) =
|
||||||
|
case (bt,v) of
|
||||||
|
(Implicit,VImplArg v) -> ap v
|
||||||
|
(Explicit, v) -> ap v
|
||||||
|
where
|
||||||
|
ap (VFV avs) = vfv [vapply loc (f v) vs|v<-avs]
|
||||||
|
ap v = vapply loc (f v) vs
|
||||||
|
|
||||||
|
vary (VFV vs) = vs
|
||||||
|
vary v = [v]
|
||||||
|
varyList = mapM vary
|
||||||
|
|
||||||
|
{-
|
||||||
|
beta env b x t (v:vs) =
|
||||||
|
case (b,v) of
|
||||||
|
(Implicit,VImplArg v) -> apply' (ext (x,v) env) t vs
|
||||||
|
(Explicit, v) -> apply' (ext (x,v) env) t vs
|
||||||
|
-}
|
||||||
|
|
||||||
|
vtrace loc arg res = trace (render (hang (pv arg) 4 ("->"<+>pv res))) res
|
||||||
|
where
|
||||||
|
pv v = case v of
|
||||||
|
VRec (f:as) -> hang (pf f) 4 (fsep (map pa as))
|
||||||
|
_ -> ppV v
|
||||||
|
pf (_,VString n) = pp n
|
||||||
|
pf (_,v) = ppV v
|
||||||
|
pa (_,v) = ppV v
|
||||||
|
ppV v = case value2term' True loc [] v of
|
||||||
|
Left i -> "variable #" <> pp i <+> "is out of scope"
|
||||||
|
Right t -> ppTerm Unqualified 10 t
|
||||||
|
|
||||||
|
-- | Convert a value back to a term
|
||||||
|
value2term :: GLocation -> [Ident] -> Value -> Either Int Term
|
||||||
|
value2term = value2term' False
|
||||||
|
value2term' stop loc xs v0 =
|
||||||
|
case v0 of
|
||||||
|
VApp pre vs -> liftM (foldl App (Q (cPredef,predefName pre))) (mapM v2t vs)
|
||||||
|
VCApp f vs -> liftM (foldl App (QC f)) (mapM v2t vs)
|
||||||
|
VGen j vs -> liftM2 (foldl App) (var j) (mapM v2t vs)
|
||||||
|
VMeta j env vs -> liftM (foldl App (Meta j)) (mapM v2t vs)
|
||||||
|
VProd bt v x f -> liftM2 (Prod bt x) (v2t v) (v2t' x f)
|
||||||
|
VAbs bt x f -> liftM (Abs bt x) (v2t' x f)
|
||||||
|
VInt n -> return (EInt n)
|
||||||
|
VFloat f -> return (EFloat f)
|
||||||
|
VString s -> return (if null s then Empty else K s)
|
||||||
|
VSort s -> return (Sort s)
|
||||||
|
VImplArg v -> liftM ImplArg (v2t v)
|
||||||
|
VTblType p res -> liftM2 Table (v2t p) (v2t res)
|
||||||
|
VRecType rs -> liftM RecType (mapM (\(l,v) -> fmap ((,) l) (v2t v)) rs)
|
||||||
|
VRec as -> liftM R (mapM (\(l,v) -> v2t v >>= \t -> return (l,(Nothing,t))) as)
|
||||||
|
VV t _ vs -> liftM (V t) (mapM v2t vs)
|
||||||
|
VT wild v cs -> v2t v >>= \t -> liftM (T ((if wild then TWild else TTyped) t)) (mapM nfcase cs)
|
||||||
|
VFV vs -> liftM FV (mapM v2t vs)
|
||||||
|
VC v1 v2 -> liftM2 C (v2t v1) (v2t v2)
|
||||||
|
VS v1 v2 -> liftM2 S (v2t v1) (v2t v2)
|
||||||
|
VP v l -> v2t v >>= \t -> return (P t l)
|
||||||
|
VPatt p -> return (EPatt p)
|
||||||
|
VPattType v -> v2t v >>= return . EPattType
|
||||||
|
VAlts v vvs -> liftM2 Alts (v2t v) (mapM (\(x,y) -> liftM2 (,) (v2t x) (v2t y)) vvs)
|
||||||
|
VStrs vs -> liftM Strs (mapM v2t vs)
|
||||||
|
-- VGlue v1 v2 -> Glue (v2t v1) (v2t v2)
|
||||||
|
-- VExtR v1 v2 -> ExtR (v2t v1) (v2t v2)
|
||||||
|
VError err -> return (Error err)
|
||||||
|
_ -> bug ("value2term "++show loc++" : "++show v0)
|
||||||
|
where
|
||||||
|
v2t = v2txs xs
|
||||||
|
v2txs = value2term' stop loc
|
||||||
|
v2t' x f = v2txs (x:xs) (bind f (gen xs))
|
||||||
|
|
||||||
|
var j
|
||||||
|
| j<length xs = Right (Vr (reverse xs !! j))
|
||||||
|
| otherwise = Left j
|
||||||
|
|
||||||
|
|
||||||
|
pushs xs e = foldr push e xs
|
||||||
|
push x (env,xs) = ((x,gen xs):env,x:xs)
|
||||||
|
gen xs = VGen (length xs) []
|
||||||
|
|
||||||
|
nfcase (p,f) = liftM ((,) p) (v2txs xs' (bind f env'))
|
||||||
|
where (env',xs') = pushs (pattVars p) ([],xs)
|
||||||
|
|
||||||
|
bind (Bind f) x = if stop
|
||||||
|
then VSort (identS "...") -- hmm
|
||||||
|
else f x
|
||||||
|
|
||||||
|
|
||||||
|
linPattVars p =
|
||||||
|
if null dups
|
||||||
|
then return pvs
|
||||||
|
else fail.render $ hang "Pattern is not linear. All variable names on the left-hand side must be distinct." 4 (ppPatt Unqualified 0 p)
|
||||||
|
where
|
||||||
|
allpvs = allPattVars p
|
||||||
|
pvs = nub allpvs
|
||||||
|
dups = allpvs \\ pvs
|
||||||
|
|
||||||
|
pattVars = nub . allPattVars
|
||||||
|
allPattVars p =
|
||||||
|
case p of
|
||||||
|
PV i -> [i]
|
||||||
|
PAs i p -> i:allPattVars p
|
||||||
|
_ -> collectPattOp allPattVars p
|
||||||
|
|
||||||
|
---
|
||||||
|
ix loc fn xs i =
|
||||||
|
if i<n
|
||||||
|
then xs !! i
|
||||||
|
else bugloc loc $ "(!!): index too large in "++fn++", "++show i++"<"++show n
|
||||||
|
where n = length xs
|
||||||
|
|
||||||
|
infixl 1 #,<# --,@@
|
||||||
|
|
||||||
|
f # x = fmap f x
|
||||||
|
mf <# mx = ap mf mx
|
||||||
|
--m1 @@ m2 = (m1 =<<) . m2
|
||||||
|
|
||||||
|
both f (x,y) = (,) # f x <# f y
|
||||||
|
|
||||||
|
bugloc loc s = ppbug $ ppL loc s
|
||||||
|
|
||||||
|
bug msg = ppbug msg
|
||||||
|
ppbug doc = error $ render $ hang "Internal error in Compute.ConcreteNew:" 4 doc
|
||||||
@@ -27,10 +27,6 @@ instance Predef Int where
|
|||||||
|
|
||||||
instance Predef Bool where
|
instance Predef Bool where
|
||||||
toValue = boolV
|
toValue = boolV
|
||||||
fromValue v = case v of
|
|
||||||
VCApp (mn,i) [] | mn == cPredef && i == cPTrue -> return True
|
|
||||||
VCApp (mn,i) [] | mn == cPredef && i == cPFalse -> return False
|
|
||||||
_ -> verror "Bool" v
|
|
||||||
|
|
||||||
instance Predef String where
|
instance Predef String where
|
||||||
toValue = string
|
toValue = string
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
module GF.Compile.Compute.Value where
|
module GF.Compile.Compute.Value where
|
||||||
import GF.Grammar.Grammar(Label,Type,MetaId,Patt,QIdent)
|
import GF.Grammar.Grammar(Label,Type,MetaId,Patt,QIdent)
|
||||||
import PGF2(BindType)
|
import PGF.Internal(BindType)
|
||||||
import GF.Infra.Ident(Ident)
|
import GF.Infra.Ident(Ident)
|
||||||
import Text.Show.Functions()
|
import Text.Show.Functions()
|
||||||
import Data.Ix(Ix)
|
import Data.Ix(Ix)
|
||||||
@@ -12,8 +12,8 @@ data Value
|
|||||||
| VGen Int [Value] -- for lambda bound variables, possibly applied
|
| VGen Int [Value] -- for lambda bound variables, possibly applied
|
||||||
| VMeta MetaId Env [Value]
|
| VMeta MetaId Env [Value]
|
||||||
-- -- | VClosure Env Term -- used in Typecheck.ConcreteNew
|
-- -- | VClosure Env Term -- used in Typecheck.ConcreteNew
|
||||||
| VAbs BindType Ident Binding -- used in Compute.Concrete
|
| VAbs BindType Ident Binding -- used in Compute.ConcreteNew
|
||||||
| VProd BindType Value Ident Binding -- used in Compute.Concrete
|
| VProd BindType Value Ident Binding -- used in Compute.ConcreteNew
|
||||||
| VInt Int
|
| VInt Int
|
||||||
| VFloat Double
|
| VFloat Double
|
||||||
| VString String
|
| VString String
|
||||||
@@ -47,10 +47,10 @@ type Env = [(Ident,Value)]
|
|||||||
|
|
||||||
-- | Predefined functions
|
-- | Predefined functions
|
||||||
data Predefined = Drop | Take | Tk | Dp | EqStr | Occur | Occurs | ToUpper
|
data Predefined = Drop | Take | Tk | Dp | EqStr | Occur | Occurs | ToUpper
|
||||||
| ToLower | IsUpper | Length | Plus | EqInt | LessInt
|
| ToLower | IsUpper | Length | Plus | EqInt | LessInt
|
||||||
{- | Show | Read | ToStr | MapStr | EqVal -}
|
{- | Show | Read | ToStr | MapStr | EqVal -}
|
||||||
| Error | Trace
|
| Error | Trace
|
||||||
-- Canonical values below:
|
-- Canonical values below:
|
||||||
| PBool | PFalse | PTrue | Int | Float | Ints | NonExist
|
| PBool | PFalse | PTrue | Int | Float | Ints | NonExist
|
||||||
| BIND | SOFT_BIND | SOFT_SPACE | CAPIT | ALL_CAPIT
|
| BIND | SOFT_BIND | SOFT_SPACE | CAPIT | ALL_CAPIT
|
||||||
deriving (Show,Eq,Ord,Ix,Bounded,Enum)
|
deriving (Show,Eq,Ord,Ix,Bounded,Enum)
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import GF.Text.Pretty
|
|||||||
--import GF.Grammar.Predef(cPredef,cInts)
|
--import GF.Grammar.Predef(cPredef,cInts)
|
||||||
--import GF.Compile.Compute.Predef(predef)
|
--import GF.Compile.Compute.Predef(predef)
|
||||||
--import GF.Compile.Compute.Value(Predefined(..))
|
--import GF.Compile.Compute.Value(Predefined(..))
|
||||||
import GF.Infra.Ident(Ident,identC,identS,identW,prefixIdent,showRawIdent,rawIdentS)
|
import GF.Infra.Ident(Ident,identS,identW,prefixIdent)
|
||||||
import GF.Infra.Option
|
import GF.Infra.Option
|
||||||
import GF.Haskell as H
|
import GF.Haskell as H
|
||||||
import GF.Grammar.Canonical as C
|
import GF.Grammar.Canonical as C
|
||||||
@@ -21,7 +21,7 @@ concretes2haskell opts absname gr =
|
|||||||
| let Grammar abstr cncs = grammar2canonical opts absname gr,
|
| let Grammar abstr cncs = grammar2canonical opts absname gr,
|
||||||
cncmod<-cncs,
|
cncmod<-cncs,
|
||||||
let ModId name = concName cncmod
|
let ModId name = concName cncmod
|
||||||
filename = showRawIdent name ++ ".hs" :: FilePath
|
filename = name ++ ".hs" :: FilePath
|
||||||
]
|
]
|
||||||
|
|
||||||
-- | Generate Haskell code for the given concrete module.
|
-- | Generate Haskell code for the given concrete module.
|
||||||
@@ -53,7 +53,7 @@ concrete2haskell opts
|
|||||||
labels = S.difference (S.unions (map S.fromList recs)) common_labels
|
labels = S.difference (S.unions (map S.fromList recs)) common_labels
|
||||||
common_records = S.fromList [[label_s]]
|
common_records = S.fromList [[label_s]]
|
||||||
common_labels = S.fromList [label_s]
|
common_labels = S.fromList [label_s]
|
||||||
label_s = LabelId (rawIdentS "s")
|
label_s = LabelId "s"
|
||||||
|
|
||||||
signature (CatDef c _) = TypeSig lf (Fun abs (pure lin))
|
signature (CatDef c _) = TypeSig lf (Fun abs (pure lin))
|
||||||
where
|
where
|
||||||
@@ -69,7 +69,7 @@ concrete2haskell opts
|
|||||||
where
|
where
|
||||||
--funcats = S.fromList [c | FunDef f (C.Type _ (TypeApp c _))<-funs]
|
--funcats = S.fromList [c | FunDef f (C.Type _ (TypeApp c _))<-funs]
|
||||||
allcats = S.fromList [c | CatDef c _<-cats]
|
allcats = S.fromList [c | CatDef c _<-cats]
|
||||||
|
|
||||||
gId :: ToIdent i => i -> Ident
|
gId :: ToIdent i => i -> Ident
|
||||||
gId = (if haskellOption opts HaskellNoPrefix then id else prefixIdent "G")
|
gId = (if haskellOption opts HaskellNoPrefix then id else prefixIdent "G")
|
||||||
. toIdent
|
. toIdent
|
||||||
@@ -116,7 +116,7 @@ concrete2haskell opts
|
|||||||
where (ls,ts) = unzip $ sortOn fst [(l,t)|RecordRow l t<-rs]
|
where (ls,ts) = unzip $ sortOn fst [(l,t)|RecordRow l t<-rs]
|
||||||
StrType -> tcon0 (identS "Str")
|
StrType -> tcon0 (identS "Str")
|
||||||
TableType pt lt -> Fun (ppT pt) (ppT lt)
|
TableType pt lt -> Fun (ppT pt) (ppT lt)
|
||||||
-- TupleType lts ->
|
-- TupleType lts ->
|
||||||
|
|
||||||
lincatDef (LincatDef c t) = tsyn0 (lincatName c) (convLinType t)
|
lincatDef (LincatDef c t) = tsyn0 (lincatName c) (convLinType t)
|
||||||
|
|
||||||
@@ -126,7 +126,7 @@ concrete2haskell opts
|
|||||||
linDefs = map eqn . sortOn fst . map linDef
|
linDefs = map eqn . sortOn fst . map linDef
|
||||||
where eqn (cat,(f,(ps,rhs))) = (cat,Eqn (f,ps) rhs)
|
where eqn (cat,(f,(ps,rhs))) = (cat,Eqn (f,ps) rhs)
|
||||||
|
|
||||||
linDef (LinDef f xs rhs0) =
|
linDef (LinDef f xs rhs0) =
|
||||||
(cat,(linfunName cat,(lhs,rhs)))
|
(cat,(linfunName cat,(lhs,rhs)))
|
||||||
where
|
where
|
||||||
lhs = [ConP (aId f) (map VarP abs_args)]
|
lhs = [ConP (aId f) (map VarP abs_args)]
|
||||||
@@ -144,7 +144,7 @@ concrete2haskell opts
|
|||||||
where
|
where
|
||||||
vs = [(VarValueId (Unqual x),a)|(VarId x,a)<-zip xs args]
|
vs = [(VarValueId (Unqual x),a)|(VarId x,a)<-zip xs args]
|
||||||
env= [(VarValueId (Unqual x),lc)|(VarId x,lc)<-zip xs (map arglincat absctx)]
|
env= [(VarValueId (Unqual x),lc)|(VarId x,lc)<-zip xs (map arglincat absctx)]
|
||||||
|
|
||||||
letlin a (TypeBinding _ (C.Type _ (TypeApp acat _))) =
|
letlin a (TypeBinding _ (C.Type _ (TypeApp acat _))) =
|
||||||
(a,Ap (Var (linfunName acat)) (Var (abs_arg a)))
|
(a,Ap (Var (linfunName acat)) (Var (abs_arg a)))
|
||||||
|
|
||||||
@@ -187,7 +187,7 @@ concrete2haskell opts
|
|||||||
|
|
||||||
pId p@(ParamId s) =
|
pId p@(ParamId s) =
|
||||||
if "to_R_" `isPrefixOf` unqual s then toIdent p else gId p -- !! a hack
|
if "to_R_" `isPrefixOf` unqual s then toIdent p else gId p -- !! a hack
|
||||||
|
|
||||||
table cs =
|
table cs =
|
||||||
if all (null.patVars) ps
|
if all (null.patVars) ps
|
||||||
then lets ds (LambdaCase [(ppP p,t')|(p,t')<-zip ps ts'])
|
then lets ds (LambdaCase [(ppP p,t')|(p,t')<-zip ps ts'])
|
||||||
@@ -315,13 +315,13 @@ instance Records rhs => Records (TableRow rhs) where
|
|||||||
|
|
||||||
-- | Record subtyping is converted into explicit coercions in Haskell
|
-- | Record subtyping is converted into explicit coercions in Haskell
|
||||||
coerce env ty t =
|
coerce env ty t =
|
||||||
case (ty,t) of
|
case (ty,t) of
|
||||||
(_,VariantValue ts) -> VariantValue (map (coerce env ty) ts)
|
(_,VariantValue ts) -> VariantValue (map (coerce env ty) ts)
|
||||||
(TableType ti tv,TableValue _ cs) ->
|
(TableType ti tv,TableValue _ cs) ->
|
||||||
TableValue ti [TableRow p (coerce env tv t)|TableRow p t<-cs]
|
TableValue ti [TableRow p (coerce env tv t)|TableRow p t<-cs]
|
||||||
(RecordType rt,RecordValue r) ->
|
(RecordType rt,RecordValue r) ->
|
||||||
RecordValue [RecordRow l (coerce env ft f) |
|
RecordValue [RecordRow l (coerce env ft f) |
|
||||||
RecordRow l f<-r,ft<-[ft | RecordRow l' ft <- rt, l'==l]]
|
RecordRow l f<-r,ft<-[ft|RecordRow l' ft<-rt,l'==l]]
|
||||||
(RecordType rt,VarValue x)->
|
(RecordType rt,VarValue x)->
|
||||||
case lookup x env of
|
case lookup x env of
|
||||||
Just ty' | ty'/=ty -> -- better to compare to normal form of ty'
|
Just ty' | ty'/=ty -> -- better to compare to normal form of ty'
|
||||||
@@ -334,17 +334,18 @@ coerce env ty t =
|
|||||||
_ -> t
|
_ -> t
|
||||||
where
|
where
|
||||||
app f ts = ParamConstant (Param f ts) -- !! a hack
|
app f ts = ParamConstant (Param f ts) -- !! a hack
|
||||||
to_rcon = ParamId . Unqual . rawIdentS . to_rcon' . labels
|
to_rcon = ParamId . Unqual . to_rcon' . labels
|
||||||
|
|
||||||
patVars p = []
|
patVars p = []
|
||||||
|
|
||||||
labels r = [l | RecordRow l _ <- r]
|
labels r = [l|RecordRow l _<-r]
|
||||||
|
|
||||||
proj = Var . identS . proj'
|
proj = Var . identS . proj'
|
||||||
proj' (LabelId l) = "proj_" ++ showRawIdent l
|
proj' (LabelId l) = "proj_"++l
|
||||||
rcon = Var . rcon'
|
rcon = Var . rcon'
|
||||||
rcon' = identS . rcon_name
|
rcon' = identS . rcon_name
|
||||||
rcon_name ls = "R"++concat (sort ['_':showRawIdent l | LabelId l <- ls])
|
rcon_name ls = "R"++concat (sort ['_':l|LabelId l<-ls])
|
||||||
|
|
||||||
to_rcon' = ("to_"++) . rcon_name
|
to_rcon' = ("to_"++) . rcon_name
|
||||||
|
|
||||||
recordType ls =
|
recordType ls =
|
||||||
@@ -399,17 +400,17 @@ linfunName c = prefixIdent "lin" (toIdent c)
|
|||||||
|
|
||||||
class ToIdent i where toIdent :: i -> Ident
|
class ToIdent i where toIdent :: i -> Ident
|
||||||
|
|
||||||
instance ToIdent ParamId where toIdent (ParamId q) = qIdentC q
|
instance ToIdent ParamId where toIdent (ParamId q) = qIdentS q
|
||||||
instance ToIdent PredefId where toIdent (PredefId s) = identC s
|
instance ToIdent PredefId where toIdent (PredefId s) = identS s
|
||||||
instance ToIdent CatId where toIdent (CatId s) = identC s
|
instance ToIdent CatId where toIdent (CatId s) = identS s
|
||||||
instance ToIdent C.FunId where toIdent (FunId s) = identC s
|
instance ToIdent C.FunId where toIdent (FunId s) = identS s
|
||||||
instance ToIdent VarValueId where toIdent (VarValueId q) = qIdentC q
|
instance ToIdent VarValueId where toIdent (VarValueId q) = qIdentS q
|
||||||
|
|
||||||
qIdentC = identS . unqual
|
qIdentS = identS . unqual
|
||||||
|
|
||||||
unqual (Qual (ModId m) n) = showRawIdent m++"_"++ showRawIdent n
|
unqual (Qual (ModId m) n) = m++"_"++n
|
||||||
unqual (Unqual n) = showRawIdent n
|
unqual (Unqual n) = n
|
||||||
|
|
||||||
instance ToIdent VarId where
|
instance ToIdent VarId where
|
||||||
toIdent Anonymous = identW
|
toIdent Anonymous = identW
|
||||||
toIdent (VarId s) = identC s
|
toIdent (VarId s) = identS s
|
||||||
|
|||||||
@@ -3,7 +3,11 @@ module GF.Compile.ExampleBased (
|
|||||||
configureExBased
|
configureExBased
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import PGF2
|
import PGF
|
||||||
|
--import PGF.Probabilistic
|
||||||
|
--import PGF.Morphology
|
||||||
|
--import GF.Compile.ToAPI
|
||||||
|
|
||||||
import Data.List
|
import Data.List
|
||||||
|
|
||||||
parseExamplesInGrammar :: ExConfiguration -> FilePath -> IO (FilePath,[String])
|
parseExamplesInGrammar :: ExConfiguration -> FilePath -> IO (FilePath,[String])
|
||||||
@@ -33,38 +37,47 @@ convertFile conf src file = do
|
|||||||
(ex, end) = break (=='"') (tail exend)
|
(ex, end) = break (=='"') (tail exend)
|
||||||
in ((unwords (words cat),ex), tail end) -- quotes ignored
|
in ((unwords (words cat),ex), tail end) -- quotes ignored
|
||||||
pgf = resource_pgf conf
|
pgf = resource_pgf conf
|
||||||
|
morpho = resource_morpho conf
|
||||||
lang = language conf
|
lang = language conf
|
||||||
convEx (cat,ex) = do
|
convEx (cat,ex) = do
|
||||||
appn "("
|
appn "("
|
||||||
let typ = maybe (error "no valid cat") id $ readType cat
|
let typ = maybe (error "no valid cat") id $ readType cat
|
||||||
ws <- case parse lang typ ex of
|
ws <- case fst (parse_ pgf lang typ (Just 4) ex) of
|
||||||
ParseFailed _ _ -> do
|
ParseFailed _ -> do
|
||||||
|
let ws = morphoMissing morpho (words ex)
|
||||||
appv ("WARNING: cannot parse example " ++ ex)
|
appv ("WARNING: cannot parse example " ++ ex)
|
||||||
|
case ws of
|
||||||
|
[] -> return ()
|
||||||
|
_ -> appv (" missing words: " ++ unwords ws)
|
||||||
|
return ws
|
||||||
|
TypeError _ ->
|
||||||
return []
|
return []
|
||||||
ParseIncomplete ->
|
ParseIncomplete ->
|
||||||
return []
|
return []
|
||||||
ParseOk ts ->
|
ParseOk ts ->
|
||||||
case ts of
|
case rank ts of
|
||||||
(t:tt) -> do
|
(t:tt) -> do
|
||||||
if null tt
|
if null tt
|
||||||
then return ()
|
then return ()
|
||||||
else appv ("WARNING: ambiguous example " ++ ex)
|
else appv ("WARNING: ambiguous example " ++ ex)
|
||||||
appn (printExp conf (fst t))
|
appn t
|
||||||
mapM_ (appn . (" --- " ++) . printExp conf . fst) tt
|
mapM_ (appn . (" --- " ++)) tt
|
||||||
appn ")"
|
appn ")"
|
||||||
return []
|
return []
|
||||||
return ws
|
return ws
|
||||||
|
rank ts = [printExp conf t ++ " -- " ++ show p | (t,p) <- rankTreesByProbs pgf ts]
|
||||||
appf = appendFile file
|
appf = appendFile file
|
||||||
appn s = appf s >> appf "\n"
|
appn s = appf s >> appf "\n"
|
||||||
appv s = appn ("--- " ++ s) >> putStrLn s
|
appv s = appn ("--- " ++ s) >> putStrLn s
|
||||||
|
|
||||||
data ExConfiguration = ExConf {
|
data ExConfiguration = ExConf {
|
||||||
resource_pgf :: PGF,
|
resource_pgf :: PGF,
|
||||||
|
resource_morpho :: Morpho,
|
||||||
verbose :: Bool,
|
verbose :: Bool,
|
||||||
language :: Concr,
|
language :: Language,
|
||||||
printExp :: Expr -> String
|
printExp :: Tree -> String
|
||||||
}
|
}
|
||||||
|
|
||||||
configureExBased :: PGF -> Concr -> (Expr -> String) -> ExConfiguration
|
configureExBased :: PGF -> Morpho -> Language -> (Tree -> String) -> ExConfiguration
|
||||||
configureExBased pgf concr pr = ExConf pgf False concr pr
|
configureExBased pgf morpho lang pr = ExConf pgf morpho False lang pr
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,14 @@
|
|||||||
module GF.Compile.Export where
|
module GF.Compile.Export where
|
||||||
|
|
||||||
import PGF2
|
import PGF
|
||||||
|
import PGF.Internal(ppPGF)
|
||||||
import GF.Compile.PGFtoHaskell
|
import GF.Compile.PGFtoHaskell
|
||||||
--import GF.Compile.PGFtoAbstract
|
--import GF.Compile.PGFtoAbstract
|
||||||
import GF.Compile.PGFtoJava
|
import GF.Compile.PGFtoJava
|
||||||
|
import GF.Compile.PGFtoProlog
|
||||||
|
import GF.Compile.PGFtoJS
|
||||||
import GF.Compile.PGFtoJSON
|
import GF.Compile.PGFtoJSON
|
||||||
|
import GF.Compile.PGFtoPython
|
||||||
import GF.Infra.Option
|
import GF.Infra.Option
|
||||||
--import GF.Speech.CFG
|
--import GF.Speech.CFG
|
||||||
import GF.Speech.PGFToCFG
|
import GF.Speech.PGFToCFG
|
||||||
@@ -18,7 +22,6 @@ import GF.Speech.SLF
|
|||||||
import GF.Speech.PrRegExp
|
import GF.Speech.PrRegExp
|
||||||
|
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
import qualified Data.Map as Map
|
|
||||||
import System.FilePath
|
import System.FilePath
|
||||||
import GF.Text.Pretty
|
import GF.Text.Pretty
|
||||||
|
|
||||||
@@ -32,12 +35,15 @@ exportPGF :: Options
|
|||||||
-> [(FilePath,String)] -- ^ List of recommended file names and contents.
|
-> [(FilePath,String)] -- ^ List of recommended file names and contents.
|
||||||
exportPGF opts fmt pgf =
|
exportPGF opts fmt pgf =
|
||||||
case fmt of
|
case fmt of
|
||||||
FmtPGFPretty -> multi "txt" (showPGF)
|
FmtPGFPretty -> multi "txt" (render . ppPGF)
|
||||||
FmtCanonicalGF -> [] -- canon "gf" (render80 . abstract2canonical)
|
FmtCanonicalGF -> [] -- canon "gf" (render80 . abstract2canonical)
|
||||||
FmtCanonicalJson-> []
|
FmtCanonicalJson-> []
|
||||||
|
FmtJavaScript -> multi "js" pgf2js
|
||||||
FmtJSON -> multi "json" pgf2json
|
FmtJSON -> multi "json" pgf2json
|
||||||
|
FmtPython -> multi "py" pgf2python
|
||||||
FmtHaskell -> multi "hs" (grammar2haskell opts name)
|
FmtHaskell -> multi "hs" (grammar2haskell opts name)
|
||||||
FmtJava -> multi "java" (grammar2java opts name)
|
FmtJava -> multi "java" (grammar2java opts name)
|
||||||
|
FmtProlog -> multi "pl" grammar2prolog
|
||||||
FmtBNF -> single "bnf" bnfPrinter
|
FmtBNF -> single "bnf" bnfPrinter
|
||||||
FmtEBNF -> single "ebnf" (ebnfPrinter opts)
|
FmtEBNF -> single "ebnf" (ebnfPrinter opts)
|
||||||
FmtSRGS_XML -> single "grxml" (srgsXmlPrinter opts)
|
FmtSRGS_XML -> single "grxml" (srgsXmlPrinter opts)
|
||||||
@@ -51,13 +57,20 @@ exportPGF opts fmt pgf =
|
|||||||
FmtRegExp -> single "rexp" regexpPrinter
|
FmtRegExp -> single "rexp" regexpPrinter
|
||||||
FmtFA -> single "dot" slfGraphvizPrinter
|
FmtFA -> single "dot" slfGraphvizPrinter
|
||||||
where
|
where
|
||||||
name = fromMaybe (abstractName pgf) (flag optName opts)
|
name = fromMaybe (showCId (abstractName pgf)) (flag optName opts)
|
||||||
|
|
||||||
multi :: String -> (PGF -> String) -> [(FilePath,String)]
|
multi :: String -> (PGF -> String) -> [(FilePath,String)]
|
||||||
multi ext pr = [(name <.> ext, pr pgf)]
|
multi ext pr = [(name <.> ext, pr pgf)]
|
||||||
|
|
||||||
-- canon ext pr = [("canonical"</>name<.>ext,pr pgf)]
|
-- canon ext pr = [("canonical"</>name<.>ext,pr pgf)]
|
||||||
|
|
||||||
single :: String -> (PGF -> Concr -> String) -> [(FilePath,String)]
|
single :: String -> (PGF -> CId -> String) -> [(FilePath,String)]
|
||||||
single ext pr = [(concreteName cnc <.> ext, pr pgf cnc) | cnc <- Map.elems (languages pgf)]
|
single ext pr = [(showCId cnc <.> ext, pr pgf cnc) | cnc <- languages pgf]
|
||||||
|
|
||||||
|
|
||||||
|
-- | Get the name of the concrete syntax to generate output from.
|
||||||
|
-- FIXME: there should be an option to change this.
|
||||||
|
outputConcr :: PGF -> CId
|
||||||
|
outputConcr pgf = case languages pgf of
|
||||||
|
[] -> error "No concrete syntax."
|
||||||
|
cnc:_ -> cnc
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
{-# LANGUAGE CPP #-}
|
|
||||||
module GF.Compile.GenerateBC(generateByteCode) where
|
module GF.Compile.GenerateBC(generateByteCode) where
|
||||||
|
|
||||||
import GF.Grammar
|
import GF.Grammar
|
||||||
import GF.Grammar.Lookup(lookupAbsDef,lookupFunType)
|
import GF.Grammar.Lookup(lookupAbsDef,lookupFunType)
|
||||||
import GF.Data.Operations
|
import GF.Data.Operations
|
||||||
import PGF2.Internal(CodeLabel,Instr(..),IVal(..),TailInfo(..),Literal(..))
|
import PGF(CId,utf8CId)
|
||||||
|
import PGF.Internal(CodeLabel,Instr(..),IVal(..),TailInfo(..),Literal(..))
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
import Data.List(nub,mapAccumL)
|
import Data.List(nub,mapAccumL)
|
||||||
import Data.Maybe(fromMaybe)
|
import Data.Maybe(fromMaybe)
|
||||||
@@ -63,7 +63,7 @@ compileEquations gr arity st (i:is) eqs fl bs = whilePP eqs Map.empty
|
|||||||
|
|
||||||
case_instr t =
|
case_instr t =
|
||||||
case t of
|
case t of
|
||||||
(Q (_,id)) -> CASE (showIdent id)
|
(Q (_,id)) -> CASE (i2i id)
|
||||||
(EInt n) -> CASE_LIT (LInt n)
|
(EInt n) -> CASE_LIT (LInt n)
|
||||||
(K s) -> CASE_LIT (LStr s)
|
(K s) -> CASE_LIT (LStr s)
|
||||||
(EFloat d) -> CASE_LIT (LFlt d)
|
(EFloat d) -> CASE_LIT (LFlt d)
|
||||||
@@ -105,7 +105,7 @@ compileFun gr eval st vs (App e1 e2) h0 bs args =
|
|||||||
compileFun gr eval st vs (Q (m,id)) h0 bs args =
|
compileFun gr eval st vs (Q (m,id)) h0 bs args =
|
||||||
case lookupAbsDef gr m id of
|
case lookupAbsDef gr m id of
|
||||||
Ok (_,Just _)
|
Ok (_,Just _)
|
||||||
-> (h0,bs,eval st (GLOBAL (showIdent id)) args)
|
-> (h0,bs,eval st (GLOBAL (i2i id)) args)
|
||||||
_ -> let Ok ty = lookupFunType gr m id
|
_ -> let Ok ty = lookupFunType gr m id
|
||||||
(ctxt,_,_) = typeForm ty
|
(ctxt,_,_) = typeForm ty
|
||||||
c_arity = length ctxt
|
c_arity = length ctxt
|
||||||
@@ -114,14 +114,14 @@ compileFun gr eval st vs (Q (m,id)) h0 bs args =
|
|||||||
diff = c_arity-n_args
|
diff = c_arity-n_args
|
||||||
in if diff <= 0
|
in if diff <= 0
|
||||||
then if n_args == 0
|
then if n_args == 0
|
||||||
then (h0,bs,eval st (GLOBAL (showIdent id)) [])
|
then (h0,bs,eval st (GLOBAL (i2i id)) [])
|
||||||
else let h1 = h0 + 2 + n_args
|
else let h1 = h0 + 2 + n_args
|
||||||
in (h1,bs,PUT_CONSTR (showIdent id):is1++eval st (HEAP h0) [])
|
in (h1,bs,PUT_CONSTR (i2i id):is1++eval st (HEAP h0) [])
|
||||||
else let h1 = h0 + 1 + n_args
|
else let h1 = h0 + 1 + n_args
|
||||||
is2 = [SET (FREE_VAR i) | i <- [0..n_args-1]] ++ [SET (ARG_VAR (i+1)) | i <- [0..diff-1]]
|
is2 = [SET (FREE_VAR i) | i <- [0..n_args-1]] ++ [SET (ARG_VAR (i+1)) | i <- [0..diff-1]]
|
||||||
b = CHECK_ARGS diff :
|
b = CHECK_ARGS diff :
|
||||||
ALLOC (c_arity+2) :
|
ALLOC (c_arity+2) :
|
||||||
PUT_CONSTR (showIdent id) :
|
PUT_CONSTR (i2i id) :
|
||||||
is2 ++
|
is2 ++
|
||||||
TUCK (ARG_VAR 0) diff :
|
TUCK (ARG_VAR 0) diff :
|
||||||
EVAL (HEAP h0) (TailCall diff) :
|
EVAL (HEAP h0) (TailCall diff) :
|
||||||
@@ -167,16 +167,16 @@ compileFun gr eval st vs e _ _ _ = error (show e)
|
|||||||
|
|
||||||
compileArg gr st vs (Q(m,id)) h0 bs =
|
compileArg gr st vs (Q(m,id)) h0 bs =
|
||||||
case lookupAbsDef gr m id of
|
case lookupAbsDef gr m id of
|
||||||
Ok (_,Just _) -> (h0,bs,GLOBAL (showIdent id),[])
|
Ok (_,Just _) -> (h0,bs,GLOBAL (i2i id),[])
|
||||||
_ -> let Ok ty = lookupFunType gr m id
|
_ -> let Ok ty = lookupFunType gr m id
|
||||||
(ctxt,_,_) = typeForm ty
|
(ctxt,_,_) = typeForm ty
|
||||||
c_arity = length ctxt
|
c_arity = length ctxt
|
||||||
in if c_arity == 0
|
in if c_arity == 0
|
||||||
then (h0,bs,GLOBAL (showIdent id),[])
|
then (h0,bs,GLOBAL (i2i id),[])
|
||||||
else let is2 = [SET (ARG_VAR (i+1)) | i <- [0..c_arity-1]]
|
else let is2 = [SET (ARG_VAR (i+1)) | i <- [0..c_arity-1]]
|
||||||
b = CHECK_ARGS c_arity :
|
b = CHECK_ARGS c_arity :
|
||||||
ALLOC (c_arity+2) :
|
ALLOC (c_arity+2) :
|
||||||
PUT_CONSTR (showIdent id) :
|
PUT_CONSTR (i2i id) :
|
||||||
is2 ++
|
is2 ++
|
||||||
TUCK (ARG_VAR 0) c_arity :
|
TUCK (ARG_VAR 0) c_arity :
|
||||||
EVAL (HEAP h0) (TailCall c_arity) :
|
EVAL (HEAP h0) (TailCall c_arity) :
|
||||||
@@ -224,12 +224,12 @@ compileArg gr st vs e h0 bs =
|
|||||||
diff = c_arity-n_args
|
diff = c_arity-n_args
|
||||||
in if diff <= 0
|
in if diff <= 0
|
||||||
then let h2 = h1 + 2 + n_args
|
then let h2 = h1 + 2 + n_args
|
||||||
in (h2,bs1,HEAP h1,is1 ++ (PUT_CONSTR (showIdent id) : is2))
|
in (h2,bs1,HEAP h1,is1 ++ (PUT_CONSTR (i2i id) : is2))
|
||||||
else let h2 = h1 + 1 + n_args
|
else let h2 = h1 + 1 + n_args
|
||||||
is2 = [SET (FREE_VAR i) | i <- [0..n_args-1]] ++ [SET (ARG_VAR (i+1)) | i <- [0..diff-1]]
|
is2 = [SET (FREE_VAR i) | i <- [0..n_args-1]] ++ [SET (ARG_VAR (i+1)) | i <- [0..diff-1]]
|
||||||
b = CHECK_ARGS diff :
|
b = CHECK_ARGS diff :
|
||||||
ALLOC (c_arity+2) :
|
ALLOC (c_arity+2) :
|
||||||
PUT_CONSTR (showIdent id) :
|
PUT_CONSTR (i2i id) :
|
||||||
is2 ++
|
is2 ++
|
||||||
TUCK (ARG_VAR 0) diff :
|
TUCK (ARG_VAR 0) diff :
|
||||||
EVAL (HEAP h0) (TailCall diff) :
|
EVAL (HEAP h0) (TailCall diff) :
|
||||||
@@ -298,6 +298,9 @@ freeVars xs (Vr x)
|
|||||||
| not (elem x xs) = [x]
|
| not (elem x xs) = [x]
|
||||||
freeVars xs e = collectOp (freeVars xs) e
|
freeVars xs e = collectOp (freeVars xs) e
|
||||||
|
|
||||||
|
i2i :: Ident -> CId
|
||||||
|
i2i = utf8CId . ident2utf8
|
||||||
|
|
||||||
push_is :: Int -> Int -> [IVal] -> [IVal]
|
push_is :: Int -> Int -> [IVal] -> [IVal]
|
||||||
push_is i 0 is = is
|
push_is i 0 is = is
|
||||||
push_is i n is = ARG_VAR i : push_is (i-1) (n-1) is
|
push_is i n is = ARG_VAR i : push_is (i-1) (n-1) is
|
||||||
|
|||||||
@@ -13,9 +13,8 @@ module GF.Compile.GeneratePMCFG
|
|||||||
(generatePMCFG, pgfCncCat, addPMCFG, resourceValues
|
(generatePMCFG, pgfCncCat, addPMCFG, resourceValues
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import qualified PGF2 as PGF2
|
--import PGF.CId
|
||||||
import qualified PGF2.Internal as PGF2
|
import PGF.Internal as PGF(CncCat(..),Symbol(..),fidVar)
|
||||||
import PGF2.Internal(Symbol(..),fidVar)
|
|
||||||
|
|
||||||
import GF.Infra.Option
|
import GF.Infra.Option
|
||||||
import GF.Grammar hiding (Env, mkRecord, mkTable)
|
import GF.Grammar hiding (Env, mkRecord, mkTable)
|
||||||
@@ -26,7 +25,7 @@ import GF.Data.BacktrackM
|
|||||||
import GF.Data.Operations
|
import GF.Data.Operations
|
||||||
import GF.Infra.UseIO (ePutStr,ePutStrLn) -- IOE,
|
import GF.Infra.UseIO (ePutStr,ePutStrLn) -- IOE,
|
||||||
import GF.Data.Utilities (updateNthM) --updateNth
|
import GF.Data.Utilities (updateNthM) --updateNth
|
||||||
import GF.Compile.Compute.Concrete(normalForm,resourceValues)
|
import GF.Compile.Compute.ConcreteNew(normalForm,resourceValues)
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
import qualified Data.Set as Set
|
import qualified Data.Set as Set
|
||||||
import qualified Data.List as List
|
import qualified Data.List as List
|
||||||
@@ -70,7 +69,7 @@ mapAccumWithKeyM f a m = do let xs = Map.toAscList m
|
|||||||
|
|
||||||
|
|
||||||
--addPMCFG :: Options -> SourceGrammar -> GlobalEnv -> Maybe FilePath -> Ident -> Ident -> SeqSet -> Ident -> Info -> IOE (SeqSet, Info)
|
--addPMCFG :: Options -> SourceGrammar -> GlobalEnv -> Maybe FilePath -> Ident -> Ident -> SeqSet -> Ident -> Info -> IOE (SeqSet, Info)
|
||||||
addPMCFG opts gr cenv opath am cm seqs id (CncFun mty@(Just (cat,cont,val)) mlin@(Just (L loc term)) mprn Nothing) = do
|
addPMCFG opts gr cenv opath am cm seqs id (GF.Grammar.CncFun mty@(Just (cat,cont,val)) mlin@(Just (L loc term)) mprn Nothing) = do
|
||||||
--when (verbAtLeast opts Verbose) $ ePutStr ("\n+ "++showIdent id++" ...")
|
--when (verbAtLeast opts Verbose) $ ePutStr ("\n+ "++showIdent id++" ...")
|
||||||
let pres = protoFCat gr res val
|
let pres = protoFCat gr res val
|
||||||
pargs = [protoFCat gr (snd $ catSkeleton ty) lincat | ((_,_,ty),(_,_,lincat)) <- zip ctxt cont]
|
pargs = [protoFCat gr (snd $ catSkeleton ty) lincat | ((_,_,ty),(_,_,lincat)) <- zip ctxt cont]
|
||||||
@@ -83,7 +82,7 @@ addPMCFG opts gr cenv opath am cm seqs id (CncFun mty@(Just (cat,cont,val)) mlin
|
|||||||
(goB b1 CNil [])
|
(goB b1 CNil [])
|
||||||
(pres,pargs)
|
(pres,pargs)
|
||||||
pmcfg = getPMCFG pmcfgEnv1
|
pmcfg = getPMCFG pmcfgEnv1
|
||||||
|
|
||||||
stats = let PMCFG prods funs = pmcfg
|
stats = let PMCFG prods funs = pmcfg
|
||||||
(s,e) = bounds funs
|
(s,e) = bounds funs
|
||||||
!prods_cnt = length prods
|
!prods_cnt = length prods
|
||||||
@@ -94,7 +93,7 @@ addPMCFG opts gr cenv opath am cm seqs id (CncFun mty@(Just (cat,cont,val)) mlin
|
|||||||
ePutStr ("\n+ "++showIdent id++" "++show (product (map catFactor pargs)))
|
ePutStr ("\n+ "++showIdent id++" "++show (product (map catFactor pargs)))
|
||||||
seqs1 `seq` stats `seq` return ()
|
seqs1 `seq` stats `seq` return ()
|
||||||
when (verbAtLeast opts Verbose) $ ePutStr (" "++show stats)
|
when (verbAtLeast opts Verbose) $ ePutStr (" "++show stats)
|
||||||
return (seqs1,CncFun mty mlin mprn (Just pmcfg))
|
return (seqs1,GF.Grammar.CncFun mty mlin mprn (Just pmcfg))
|
||||||
where
|
where
|
||||||
(ctxt,res,_) = err bug typeForm (lookupFunType gr am id)
|
(ctxt,res,_) = err bug typeForm (lookupFunType gr am id)
|
||||||
|
|
||||||
@@ -104,11 +103,11 @@ addPMCFG opts gr cenv opath am cm seqs id (CncFun mty@(Just (cat,cont,val)) mlin
|
|||||||
newArgs = map getFIds newArgs'
|
newArgs = map getFIds newArgs'
|
||||||
in addFunction env0 newCat fun newArgs
|
in addFunction env0 newCat fun newArgs
|
||||||
|
|
||||||
addPMCFG opts gr cenv opath am cm seqs id (CncCat mty@(Just (L _ lincat))
|
addPMCFG opts gr cenv opath am cm seqs id (GF.Grammar.CncCat mty@(Just (L _ lincat))
|
||||||
mdef@(Just (L loc1 def))
|
mdef@(Just (L loc1 def))
|
||||||
mref@(Just (L loc2 ref))
|
mref@(Just (L loc2 ref))
|
||||||
mprn
|
mprn
|
||||||
Nothing) = do
|
Nothing) = do
|
||||||
let pcat = protoFCat gr (am,id) lincat
|
let pcat = protoFCat gr (am,id) lincat
|
||||||
pvar = protoFCat gr (MN identW,cVar) typeStr
|
pvar = protoFCat gr (MN identW,cVar) typeStr
|
||||||
|
|
||||||
@@ -133,7 +132,7 @@ addPMCFG opts gr cenv opath am cm seqs id (CncCat mty@(Just (L _ lincat))
|
|||||||
let pmcfg = getPMCFG pmcfgEnv2
|
let pmcfg = getPMCFG pmcfgEnv2
|
||||||
|
|
||||||
when (verbAtLeast opts Verbose) $ ePutStr ("\n+ "++showIdent id++" "++show (catFactor pcat))
|
when (verbAtLeast opts Verbose) $ ePutStr ("\n+ "++showIdent id++" "++show (catFactor pcat))
|
||||||
seqs2 `seq` pmcfg `seq` return (seqs2,CncCat mty mdef mref mprn (Just pmcfg))
|
seqs2 `seq` pmcfg `seq` return (seqs2,GF.Grammar.CncCat mty mdef mref mprn (Just pmcfg))
|
||||||
where
|
where
|
||||||
addLindef lins (newCat', newArgs') env0 =
|
addLindef lins (newCat', newArgs') env0 =
|
||||||
let [newCat] = getFIds newCat'
|
let [newCat] = getFIds newCat'
|
||||||
@@ -159,15 +158,12 @@ convert opts gr cenv loc term ty@(_,val) pargs =
|
|||||||
args = map Vr vars
|
args = map Vr vars
|
||||||
vars = map (\(bt,x,t) -> x) context
|
vars = map (\(bt,x,t) -> x) context
|
||||||
|
|
||||||
pgfCncCat :: SourceGrammar -> PGF2.Cat -> Type -> Int -> (PGF2.Cat,Int,Int,[String])
|
pgfCncCat :: SourceGrammar -> Type -> Int -> CncCat
|
||||||
pgfCncCat gr id lincat index =
|
pgfCncCat gr lincat index =
|
||||||
let ((_,size),schema) = computeCatRange gr lincat
|
let ((_,size),schema) = computeCatRange gr lincat
|
||||||
in ( id
|
in PGF.CncCat index (index+size-1)
|
||||||
, index
|
(mkArray (map (renderStyle style{mode=OneLineMode} . ppPath)
|
||||||
, index+size-1
|
(getStrPaths schema)))
|
||||||
, map (renderStyle style{mode=OneLineMode} . ppPath)
|
|
||||||
(getStrPaths schema)
|
|
||||||
)
|
|
||||||
where
|
where
|
||||||
getStrPaths :: Schema Identity s c -> [Path]
|
getStrPaths :: Schema Identity s c -> [Path]
|
||||||
getStrPaths = collect CNil []
|
getStrPaths = collect CNil []
|
||||||
@@ -247,7 +243,7 @@ choices nr path = do (args,_) <- get
|
|||||||
| (value,index) <- values])
|
| (value,index) <- values])
|
||||||
descend schema path rpath = bug $ "descend "++show (schema,path,rpath)
|
descend schema path rpath = bug $ "descend "++show (schema,path,rpath)
|
||||||
|
|
||||||
updateEnv path value gr c (args,seq) =
|
updateEnv path value gr c (args,seq) =
|
||||||
case updateNthM (restrictProtoFCat path value) nr args of
|
case updateNthM (restrictProtoFCat path value) nr args of
|
||||||
Just args -> c value (args,seq)
|
Just args -> c value (args,seq)
|
||||||
Nothing -> bug "conflict in updateEnv"
|
Nothing -> bug "conflict in updateEnv"
|
||||||
@@ -479,7 +475,7 @@ goV (CPar t) rpath ss = restrictHead (reversePath rpath) t >> return ss
|
|||||||
----------------------------------------------------------------------
|
----------------------------------------------------------------------
|
||||||
-- SeqSet
|
-- SeqSet
|
||||||
|
|
||||||
type SeqSet = Map.Map [Symbol] SeqId
|
type SeqSet = Map.Map Sequence SeqId
|
||||||
|
|
||||||
addSequencesB :: SeqSet -> Branch (Value [Symbol]) -> (SeqSet, Branch (Value SeqId))
|
addSequencesB :: SeqSet -> Branch (Value [Symbol]) -> (SeqSet, Branch (Value SeqId))
|
||||||
addSequencesB seqs (Case nr path bs) = let !(seqs1,bs1) = mapAccumL' (\seqs (trm,b) -> let !(seqs',b') = addSequencesB seqs b
|
addSequencesB seqs (Case nr path bs) = let !(seqs1,bs1) = mapAccumL' (\seqs (trm,b) -> let !(seqs',b') = addSequencesB seqs b
|
||||||
@@ -508,11 +504,13 @@ mapAccumL' f s (x:xs) = (s'',y:ys)
|
|||||||
!(s'',ys) = mapAccumL' f s' xs
|
!(s'',ys) = mapAccumL' f s' xs
|
||||||
|
|
||||||
addSequence :: SeqSet -> [Symbol] -> (SeqSet,SeqId)
|
addSequence :: SeqSet -> [Symbol] -> (SeqSet,SeqId)
|
||||||
addSequence seqs seq =
|
addSequence seqs lst =
|
||||||
case Map.lookup seq seqs of
|
case Map.lookup seq seqs of
|
||||||
Just id -> (seqs,id)
|
Just id -> (seqs,id)
|
||||||
Nothing -> let !last_seq = Map.size seqs
|
Nothing -> let !last_seq = Map.size seqs
|
||||||
in (Map.insert seq last_seq seqs, last_seq)
|
in (Map.insert seq last_seq seqs, last_seq)
|
||||||
|
where
|
||||||
|
seq = mkArray lst
|
||||||
|
|
||||||
|
|
||||||
------------------------------------------------------------
|
------------------------------------------------------------
|
||||||
@@ -608,7 +606,7 @@ restrictProtoFCat path v (PFCat cat f schema) = do
|
|||||||
Just index -> return (CPar (m,[(v,index)]))
|
Just index -> return (CPar (m,[(v,index)]))
|
||||||
Nothing -> mzero
|
Nothing -> mzero
|
||||||
addConstraint CNil v (CStr _) = bug "restrictProtoFCat: string path"
|
addConstraint CNil v (CStr _) = bug "restrictProtoFCat: string path"
|
||||||
|
|
||||||
update k0 f [] = return []
|
update k0 f [] = return []
|
||||||
update k0 f (x@(k,Identity v):xs)
|
update k0 f (x@(k,Identity v):xs)
|
||||||
| k0 == k = do v <- f v
|
| k0 == k = do v <- f v
|
||||||
|
|||||||
@@ -50,13 +50,20 @@ getSourceModule opts file0 =
|
|||||||
Right (i,mi0) ->
|
Right (i,mi0) ->
|
||||||
do liftIO $ removeTemp tmp
|
do liftIO $ removeTemp tmp
|
||||||
let mi =mi0 {mflags=mflags mi0 `addOptions` opts, msrc=file0}
|
let mi =mi0 {mflags=mflags mi0 `addOptions` opts, msrc=file0}
|
||||||
case renameEncoding `fmap` flag optEncoding (mflags mi0) of
|
optCoding' = renameEncoding `fmap` flag optEncoding (mflags mi0)
|
||||||
Just coding' ->
|
case (optCoding,optCoding') of
|
||||||
when (coding/=coding') $
|
{-
|
||||||
|
(Nothing,Nothing) ->
|
||||||
|
unless (BS.all isAscii raw) $
|
||||||
|
ePutStrLn $ file0++":\n Warning: default encoding has changed from Latin-1 to UTF-8"
|
||||||
|
-}
|
||||||
|
(_,Just coding') ->
|
||||||
|
when (coding/=coding') $
|
||||||
raise $ "Encoding mismatch: "++coding++" /= "++coding'
|
raise $ "Encoding mismatch: "++coding++" /= "++coding'
|
||||||
where coding = maybe defaultEncoding renameEncoding optCoding
|
where coding = maybe defaultEncoding renameEncoding optCoding
|
||||||
_ -> return ()
|
_ -> return ()
|
||||||
return (i,mi)
|
--liftIO $ transcodeModule' (i,mi) -- old lexer
|
||||||
|
return (i,mi) -- new lexer
|
||||||
|
|
||||||
getBNFCRules :: Options -> FilePath -> IOE [BNFCRule]
|
getBNFCRules :: Options -> FilePath -> IOE [BNFCRule]
|
||||||
getBNFCRules opts fpath = do
|
getBNFCRules opts fpath = do
|
||||||
|
|||||||
@@ -6,35 +6,31 @@ module GF.Compile.GrammarToCanonical(
|
|||||||
) where
|
) where
|
||||||
import Data.List(nub,partition)
|
import Data.List(nub,partition)
|
||||||
import qualified Data.Map as M
|
import qualified Data.Map as M
|
||||||
import Data.Maybe(fromMaybe)
|
|
||||||
import qualified Data.Set as S
|
import qualified Data.Set as S
|
||||||
import GF.Data.ErrM
|
import GF.Data.ErrM
|
||||||
import GF.Text.Pretty
|
import GF.Text.Pretty
|
||||||
import GF.Grammar.Grammar as G
|
import GF.Grammar.Grammar
|
||||||
import GF.Grammar.Lookup(lookupOrigInfo,allOrigInfos,allParamValues)
|
import GF.Grammar.Lookup(lookupOrigInfo,allOrigInfos,allParamValues)
|
||||||
import GF.Grammar.Macros(typeForm,collectOp,collectPattOp,composSafeOp,mkAbs,mkApp,term2patt,sortRec)
|
import GF.Grammar.Macros(typeForm,collectOp,collectPattOp,mkAbs,mkApp,term2patt)
|
||||||
import GF.Grammar.Lockfield(isLockLabel)
|
import GF.Grammar.Lockfield(isLockLabel)
|
||||||
import GF.Grammar.Predef(cPredef,cInts)
|
import GF.Grammar.Predef(cPredef,cInts)
|
||||||
import GF.Compile.Compute.Predef(predef)
|
import GF.Compile.Compute.Predef(predef)
|
||||||
import GF.Compile.Compute.Value(Predefined(..))
|
import GF.Compile.Compute.Value(Predefined(..))
|
||||||
import GF.Infra.Ident(ModuleName(..),Ident,ident2raw,rawIdentS,showIdent,isWildIdent)
|
import GF.Infra.Ident(ModuleName(..),Ident,prefixIdent,showIdent,isWildIdent)
|
||||||
import GF.Infra.Option(Options,optionsPGF)
|
import GF.Infra.Option(Options, optionsPGF)
|
||||||
import PGF2.Internal(Literal(..))
|
import PGF.Internal(Literal(..))
|
||||||
import GF.Compile.Compute.Concrete(GlobalEnv,normalForm,resourceValues)
|
import GF.Compile.Compute.ConcreteNew(normalForm,resourceValues)
|
||||||
import GF.Grammar.Canonical as C
|
import GF.Grammar.Canonical as C
|
||||||
import System.FilePath ((</>), (<.>))
|
import Debug.Trace
|
||||||
import qualified Debug.Trace as T
|
|
||||||
|
|
||||||
|
|
||||||
-- | Generate Canonical code for the named abstract syntax and all associated
|
-- | Generate Canonical code for the named abstract syntax and all associated
|
||||||
-- concrete syntaxes
|
-- concrete syntaxes
|
||||||
grammar2canonical :: Options -> ModuleName -> G.Grammar -> C.Grammar
|
grammar2canonical :: Options -> ModuleName -> SourceGrammar -> C.Grammar
|
||||||
grammar2canonical opts absname gr =
|
grammar2canonical opts absname gr =
|
||||||
Grammar (abstract2canonical absname gr)
|
Grammar (abstract2canonical absname gr)
|
||||||
(map snd (concretes2canonical opts absname gr))
|
(map snd (concretes2canonical opts absname gr))
|
||||||
|
|
||||||
-- | Generate Canonical code for the named abstract syntax
|
-- | Generate Canonical code for the named abstract syntax
|
||||||
abstract2canonical :: ModuleName -> G.Grammar -> Abstract
|
|
||||||
abstract2canonical absname gr =
|
abstract2canonical absname gr =
|
||||||
Abstract (modId absname) (convFlags gr absname) cats funs
|
Abstract (modId absname) (convFlags gr absname) cats funs
|
||||||
where
|
where
|
||||||
@@ -49,7 +45,6 @@ abstract2canonical absname gr =
|
|||||||
convHypo (bt,name,t) =
|
convHypo (bt,name,t) =
|
||||||
case typeForm t of
|
case typeForm t of
|
||||||
([],(_,cat),[]) -> gId cat -- !!
|
([],(_,cat),[]) -> gId cat -- !!
|
||||||
tf -> error $ "abstract2canonical convHypo: " ++ show tf
|
|
||||||
|
|
||||||
convType t =
|
convType t =
|
||||||
case typeForm t of
|
case typeForm t of
|
||||||
@@ -60,24 +55,23 @@ abstract2canonical absname gr =
|
|||||||
|
|
||||||
convHypo' (bt,name,t) = TypeBinding (gId name) (convType t)
|
convHypo' (bt,name,t) = TypeBinding (gId name) (convType t)
|
||||||
|
|
||||||
|
|
||||||
-- | Generate Canonical code for the all concrete syntaxes associated with
|
-- | Generate Canonical code for the all concrete syntaxes associated with
|
||||||
-- the named abstract syntax in given the grammar.
|
-- the named abstract syntax in given the grammar.
|
||||||
concretes2canonical :: Options -> ModuleName -> G.Grammar -> [(FilePath, Concrete)]
|
|
||||||
concretes2canonical opts absname gr =
|
concretes2canonical opts absname gr =
|
||||||
[(cncname,concrete2canonical gr cenv absname cnc cncmod)
|
[(cncname,concrete2canonical gr cenv absname cnc cncmod)
|
||||||
| let cenv = resourceValues opts gr,
|
| let cenv = resourceValues opts gr,
|
||||||
cnc<-allConcretes gr absname,
|
cnc<-allConcretes gr absname,
|
||||||
let cncname = "canonical" </> render cnc <.> "gf"
|
let cncname = "canonical/"++render cnc ++ ".gf" :: FilePath
|
||||||
Ok cncmod = lookupModule gr cnc
|
Ok cncmod = lookupModule gr cnc
|
||||||
]
|
]
|
||||||
|
|
||||||
-- | Generate Canonical GF for the given concrete module.
|
-- | Generate Canonical GF for the given concrete module.
|
||||||
concrete2canonical :: G.Grammar -> GlobalEnv -> ModuleName -> ModuleName -> ModuleInfo -> Concrete
|
|
||||||
concrete2canonical gr cenv absname cnc modinfo =
|
concrete2canonical gr cenv absname cnc modinfo =
|
||||||
Concrete (modId cnc) (modId absname) (convFlags gr cnc)
|
Concrete (modId cnc) (modId absname) (convFlags gr cnc)
|
||||||
(neededParamTypes S.empty (params defs))
|
(neededParamTypes S.empty (params defs))
|
||||||
[lincat | (_,Left lincat) <- defs]
|
[lincat|(_,Left lincat)<-defs]
|
||||||
[lin | (_,Right lin) <- defs]
|
[lin|(_,Right lin)<-defs]
|
||||||
where
|
where
|
||||||
defs = concatMap (toCanonical gr absname cenv) .
|
defs = concatMap (toCanonical gr absname cenv) .
|
||||||
M.toList $
|
M.toList $
|
||||||
@@ -92,7 +86,6 @@ concrete2canonical gr cenv absname cnc modinfo =
|
|||||||
else let ((got,need),def) = paramType gr q
|
else let ((got,need),def) = paramType gr q
|
||||||
in def++neededParamTypes (S.union got have) (S.toList need++qs)
|
in def++neededParamTypes (S.union got have) (S.toList need++qs)
|
||||||
|
|
||||||
-- toCanonical :: G.Grammar -> ModuleName -> GlobalEnv -> (Ident, Info) -> [(S.Set QIdent, Either LincatDef LinDef)]
|
|
||||||
toCanonical gr absname cenv (name,jment) =
|
toCanonical gr absname cenv (name,jment) =
|
||||||
case jment of
|
case jment of
|
||||||
CncCat (Just (L loc typ)) _ _ pprn _ ->
|
CncCat (Just (L loc typ)) _ _ pprn _ ->
|
||||||
@@ -105,8 +98,7 @@ toCanonical gr absname cenv (name,jment) =
|
|||||||
where
|
where
|
||||||
tts = tableTypes gr [e']
|
tts = tableTypes gr [e']
|
||||||
|
|
||||||
e' = cleanupRecordFields lincat $
|
e' = unAbs (length params) $
|
||||||
unAbs (length params) $
|
|
||||||
nf loc (mkAbs params (mkApp def (map Vr args)))
|
nf loc (mkAbs params (mkApp def (map Vr args)))
|
||||||
params = [(b,x)|(b,x,_)<-ctx]
|
params = [(b,x)|(b,x,_)<-ctx]
|
||||||
args = map snd params
|
args = map snd params
|
||||||
@@ -117,12 +109,12 @@ toCanonical gr absname cenv (name,jment) =
|
|||||||
_ -> []
|
_ -> []
|
||||||
where
|
where
|
||||||
nf loc = normalForm cenv (L loc name)
|
nf loc = normalForm cenv (L loc name)
|
||||||
|
-- aId n = prefixIdent "A." (gId n)
|
||||||
|
|
||||||
unAbs 0 t = t
|
unAbs 0 t = t
|
||||||
unAbs n (Abs _ _ t) = unAbs (n-1) t
|
unAbs n (Abs _ _ t) = unAbs (n-1) t
|
||||||
unAbs _ t = t
|
unAbs _ t = t
|
||||||
|
|
||||||
tableTypes :: G.Grammar -> [Term] -> S.Set QIdent
|
|
||||||
tableTypes gr ts = S.unions (map tabtys ts)
|
tableTypes gr ts = S.unions (map tabtys ts)
|
||||||
where
|
where
|
||||||
tabtys t =
|
tabtys t =
|
||||||
@@ -131,7 +123,6 @@ tableTypes gr ts = S.unions (map tabtys ts)
|
|||||||
T (TTyped t) cs -> S.union (paramTypes gr t) (tableTypes gr (map snd cs))
|
T (TTyped t) cs -> S.union (paramTypes gr t) (tableTypes gr (map snd cs))
|
||||||
_ -> collectOp tabtys t
|
_ -> collectOp tabtys t
|
||||||
|
|
||||||
paramTypes :: G.Grammar -> G.Type -> S.Set QIdent
|
|
||||||
paramTypes gr t =
|
paramTypes gr t =
|
||||||
case t of
|
case t of
|
||||||
RecType fs -> S.unions (map (paramTypes gr.snd) fs)
|
RecType fs -> S.unions (map (paramTypes gr.snd) fs)
|
||||||
@@ -150,26 +141,11 @@ paramTypes gr t =
|
|||||||
Ok (_,ResParam {}) -> S.singleton q
|
Ok (_,ResParam {}) -> S.singleton q
|
||||||
_ -> ignore
|
_ -> ignore
|
||||||
|
|
||||||
ignore = T.trace ("Ignore: " ++ show t) S.empty
|
ignore = trace ("Ignore: "++show t) S.empty
|
||||||
|
|
||||||
-- | Filter out record fields from definitions which don't appear in lincat.
|
|
||||||
cleanupRecordFields :: G.Type -> Term -> Term
|
|
||||||
cleanupRecordFields (RecType ls) (R as) =
|
|
||||||
let defnFields = M.fromList ls
|
|
||||||
in R
|
|
||||||
[ (lbl, (mty, t'))
|
|
||||||
| (lbl, (mty, t)) <- as
|
|
||||||
, M.member lbl defnFields
|
|
||||||
, let Just ty = M.lookup lbl defnFields
|
|
||||||
, let t' = cleanupRecordFields ty t
|
|
||||||
]
|
|
||||||
cleanupRecordFields ty t@(FV _) = composSafeOp (cleanupRecordFields ty) t
|
|
||||||
cleanupRecordFields _ t = t
|
|
||||||
|
|
||||||
convert :: G.Grammar -> Term -> LinValue
|
|
||||||
convert gr = convert' gr []
|
convert gr = convert' gr []
|
||||||
|
|
||||||
convert' :: G.Grammar -> [Ident] -> Term -> LinValue
|
|
||||||
convert' gr vs = ppT
|
convert' gr vs = ppT
|
||||||
where
|
where
|
||||||
ppT0 = convert' gr vs
|
ppT0 = convert' gr vs
|
||||||
@@ -187,20 +163,20 @@ convert' gr vs = ppT
|
|||||||
S t p -> selection (ppT t) (ppT p)
|
S t p -> selection (ppT t) (ppT p)
|
||||||
C t1 t2 -> concatValue (ppT t1) (ppT t2)
|
C t1 t2 -> concatValue (ppT t1) (ppT t2)
|
||||||
App f a -> ap (ppT f) (ppT a)
|
App f a -> ap (ppT f) (ppT a)
|
||||||
R r -> RecordValue (fields (sortRec r))
|
R r -> RecordValue (fields r)
|
||||||
P t l -> projection (ppT t) (lblId l)
|
P t l -> projection (ppT t) (lblId l)
|
||||||
Vr x -> VarValue (gId x)
|
Vr x -> VarValue (gId x)
|
||||||
Cn x -> VarValue (gId x) -- hmm
|
Cn x -> VarValue (gId x) -- hmm
|
||||||
Con c -> ParamConstant (Param (gId c) [])
|
Con c -> ParamConstant (Param (gId c) [])
|
||||||
Sort k -> VarValue (gId k)
|
Sort k -> VarValue (gId k)
|
||||||
EInt n -> LiteralValue (IntConstant n)
|
EInt n -> LiteralValue (IntConstant n)
|
||||||
Q (m,n) -> if m==cPredef then ppPredef n else VarValue (gQId m n)
|
Q (m,n) -> if m==cPredef then ppPredef n else VarValue ((gQId m n))
|
||||||
QC (m,n) -> ParamConstant (Param (gQId m n) [])
|
QC (m,n) -> ParamConstant (Param ((gQId m n)) [])
|
||||||
K s -> LiteralValue (StrConstant s)
|
K s -> LiteralValue (StrConstant s)
|
||||||
Empty -> LiteralValue (StrConstant "")
|
Empty -> LiteralValue (StrConstant "")
|
||||||
FV ts -> VariantValue (map ppT ts)
|
FV ts -> VariantValue (map ppT ts)
|
||||||
Alts t' vs -> alts vs (ppT t')
|
Alts t' vs -> alts vs (ppT t')
|
||||||
_ -> error $ "convert' ppT: " ++ show t
|
_ -> error $ "convert' "++show t
|
||||||
|
|
||||||
ppCase (p,t) = TableRow (ppP p) (ppTv (patVars p++vs) t)
|
ppCase (p,t) = TableRow (ppP p) (ppTv (patVars p++vs) t)
|
||||||
|
|
||||||
@@ -213,12 +189,12 @@ convert' gr vs = ppT
|
|||||||
Ok ALL_CAPIT -> p "ALL_CAPIT"
|
Ok ALL_CAPIT -> p "ALL_CAPIT"
|
||||||
_ -> VarValue (gQId cPredef n) -- hmm
|
_ -> VarValue (gQId cPredef n) -- hmm
|
||||||
where
|
where
|
||||||
p = PredefValue . PredefId . rawIdentS
|
p = PredefValue . PredefId
|
||||||
|
|
||||||
ppP p =
|
ppP p =
|
||||||
case p of
|
case p of
|
||||||
PC c ps -> ParamPattern (Param (gId c) (map ppP ps))
|
PC c ps -> ParamPattern (Param (gId c) (map ppP ps))
|
||||||
PP (m,c) ps -> ParamPattern (Param (gQId m c) (map ppP ps))
|
PP (m,c) ps -> ParamPattern (Param ((gQId m c)) (map ppP ps))
|
||||||
PR r -> RecordPattern (fields r) {-
|
PR r -> RecordPattern (fields r) {-
|
||||||
PW -> WildPattern
|
PW -> WildPattern
|
||||||
PV x -> VarP x
|
PV x -> VarP x
|
||||||
@@ -227,7 +203,6 @@ convert' gr vs = ppT
|
|||||||
PFloat x -> Lit (show x)
|
PFloat x -> Lit (show x)
|
||||||
PT _ p -> ppP p
|
PT _ p -> ppP p
|
||||||
PAs x p -> AsP x (ppP p) -}
|
PAs x p -> AsP x (ppP p) -}
|
||||||
_ -> error $ "convert' ppP: " ++ show p
|
|
||||||
where
|
where
|
||||||
fields = map field . filter (not.isLockLabel.fst)
|
fields = map field . filter (not.isLockLabel.fst)
|
||||||
field (l,p) = RecordRow (lblId l) (ppP p)
|
field (l,p) = RecordRow (lblId l) (ppP p)
|
||||||
@@ -244,12 +219,12 @@ convert' gr vs = ppT
|
|||||||
pre Empty = [""] -- Empty == K ""
|
pre Empty = [""] -- Empty == K ""
|
||||||
pre (Strs ts) = concatMap pre ts
|
pre (Strs ts) = concatMap pre ts
|
||||||
pre (EPatt p) = pat p
|
pre (EPatt p) = pat p
|
||||||
pre t = error $ "convert' alts pre: " ++ show t
|
pre t = error $ "pre "++show t
|
||||||
|
|
||||||
pat (PString s) = [s]
|
pat (PString s) = [s]
|
||||||
pat (PAlt p1 p2) = pat p1++pat p2
|
pat (PAlt p1 p2) = pat p1++pat p2
|
||||||
pat (PSeq p1 p2) = [s1++s2 | s1<-pat p1, s2<-pat p2]
|
pat (PSeq p1 p2) = [s1++s2 | s1<-pat p1, s2<-pat p2]
|
||||||
pat p = error $ "convert' alts pat: "++show p
|
pat p = error $ "pat "++show p
|
||||||
|
|
||||||
fields = map field . filter (not.isLockLabel.fst)
|
fields = map field . filter (not.isLockLabel.fst)
|
||||||
field (l,(_,t)) = RecordRow (lblId l) (ppT t)
|
field (l,(_,t)) = RecordRow (lblId l) (ppT t)
|
||||||
@@ -262,7 +237,6 @@ convert' gr vs = ppT
|
|||||||
ParamConstant (Param p (ps++[a]))
|
ParamConstant (Param p (ps++[a]))
|
||||||
_ -> error $ "convert' ap: "++render (ppA f <+> ppA a)
|
_ -> error $ "convert' ap: "++render (ppA f <+> ppA a)
|
||||||
|
|
||||||
concatValue :: LinValue -> LinValue -> LinValue
|
|
||||||
concatValue v1 v2 =
|
concatValue v1 v2 =
|
||||||
case (v1,v2) of
|
case (v1,v2) of
|
||||||
(LiteralValue (StrConstant ""),_) -> v2
|
(LiteralValue (StrConstant ""),_) -> v2
|
||||||
@@ -270,24 +244,21 @@ concatValue v1 v2 =
|
|||||||
_ -> ConcatValue v1 v2
|
_ -> ConcatValue v1 v2
|
||||||
|
|
||||||
-- | Smart constructor for projections
|
-- | Smart constructor for projections
|
||||||
projection :: LinValue -> LabelId -> LinValue
|
projection r l = maybe (Projection r l) id (proj r l)
|
||||||
projection r l = fromMaybe (Projection r l) (proj r l)
|
|
||||||
|
|
||||||
proj :: LinValue -> LabelId -> Maybe LinValue
|
|
||||||
proj r l =
|
proj r l =
|
||||||
case r of
|
case r of
|
||||||
RecordValue r -> case [v | RecordRow l' v <- r, l'==l] of
|
RecordValue r -> case [v|RecordRow l' v<-r,l'==l] of
|
||||||
[v] -> Just v
|
[v] -> Just v
|
||||||
_ -> Nothing
|
_ -> Nothing
|
||||||
_ -> Nothing
|
_ -> Nothing
|
||||||
|
|
||||||
-- | Smart constructor for selections
|
-- | Smart constructor for selections
|
||||||
selection :: LinValue -> LinValue -> LinValue
|
|
||||||
selection t v =
|
selection t v =
|
||||||
-- Note: impossible cases can become possible after grammar transformation
|
-- Note: impossible cases can become possible after grammar transformation
|
||||||
case t of
|
case t of
|
||||||
TableValue tt r ->
|
TableValue tt r ->
|
||||||
case nub [rv | TableRow _ rv <- keep] of
|
case nub [rv|TableRow _ rv<-keep] of
|
||||||
[rv] -> rv
|
[rv] -> rv
|
||||||
_ -> Selection (TableValue tt r') v
|
_ -> Selection (TableValue tt r') v
|
||||||
where
|
where
|
||||||
@@ -306,16 +277,13 @@ selection t v =
|
|||||||
(keep,discard) = partition (mightMatchRow v) r
|
(keep,discard) = partition (mightMatchRow v) r
|
||||||
_ -> Selection t v
|
_ -> Selection t v
|
||||||
|
|
||||||
impossible :: LinValue -> LinValue
|
|
||||||
impossible = CommentedValue "impossible"
|
impossible = CommentedValue "impossible"
|
||||||
|
|
||||||
mightMatchRow :: LinValue -> TableRow rhs -> Bool
|
|
||||||
mightMatchRow v (TableRow p _) =
|
mightMatchRow v (TableRow p _) =
|
||||||
case p of
|
case p of
|
||||||
WildPattern -> True
|
WildPattern -> True
|
||||||
_ -> mightMatch v p
|
_ -> mightMatch v p
|
||||||
|
|
||||||
mightMatch :: LinValue -> LinPattern -> Bool
|
|
||||||
mightMatch v p =
|
mightMatch v p =
|
||||||
case v of
|
case v of
|
||||||
ConcatValue _ _ -> False
|
ConcatValue _ _ -> False
|
||||||
@@ -327,18 +295,16 @@ mightMatch v p =
|
|||||||
RecordValue rv ->
|
RecordValue rv ->
|
||||||
case p of
|
case p of
|
||||||
RecordPattern rp ->
|
RecordPattern rp ->
|
||||||
and [maybe False (`mightMatch` p) (proj v l) | RecordRow l p<-rp]
|
and [maybe False (flip mightMatch p) (proj v l) | RecordRow l p<-rp]
|
||||||
_ -> False
|
_ -> False
|
||||||
_ -> True
|
_ -> True
|
||||||
|
|
||||||
patVars :: Patt -> [Ident]
|
|
||||||
patVars p =
|
patVars p =
|
||||||
case p of
|
case p of
|
||||||
PV x -> [x]
|
PV x -> [x]
|
||||||
PAs x p -> x:patVars p
|
PAs x p -> x:patVars p
|
||||||
_ -> collectPattOp patVars p
|
_ -> collectPattOp patVars p
|
||||||
|
|
||||||
convType :: Term -> LinType
|
|
||||||
convType = ppT
|
convType = ppT
|
||||||
where
|
where
|
||||||
ppT t =
|
ppT t =
|
||||||
@@ -350,9 +316,9 @@ convType = ppT
|
|||||||
Sort k -> convSort k
|
Sort k -> convSort k
|
||||||
-- EInt n -> tcon0 (identS ("({-"++show n++"-})")) -- type level numeric literal
|
-- EInt n -> tcon0 (identS ("({-"++show n++"-})")) -- type level numeric literal
|
||||||
FV (t:ts) -> ppT t -- !!
|
FV (t:ts) -> ppT t -- !!
|
||||||
QC (m,n) -> ParamType (ParamTypeId (gQId m n))
|
QC (m,n) -> ParamType (ParamTypeId ((gQId m n)))
|
||||||
Q (m,n) -> ParamType (ParamTypeId (gQId m n))
|
Q (m,n) -> ParamType (ParamTypeId ((gQId m n)))
|
||||||
_ -> error $ "convType ppT: " ++ show t
|
_ -> error $ "Missing case in convType for: "++show t
|
||||||
|
|
||||||
convFields = map convField . filter (not.isLockLabel.fst)
|
convFields = map convField . filter (not.isLockLabel.fst)
|
||||||
convField (l,r) = RecordRow (lblId l) (ppT r)
|
convField (l,r) = RecordRow (lblId l) (ppT r)
|
||||||
@@ -361,20 +327,15 @@ convType = ppT
|
|||||||
"Float" -> FloatType
|
"Float" -> FloatType
|
||||||
"Int" -> IntType
|
"Int" -> IntType
|
||||||
"Str" -> StrType
|
"Str" -> StrType
|
||||||
_ -> error $ "convType convSort: " ++ show k
|
_ -> error ("convSort "++show k)
|
||||||
|
|
||||||
toParamType :: Term -> ParamType
|
|
||||||
toParamType t = case convType t of
|
toParamType t = case convType t of
|
||||||
ParamType pt -> pt
|
ParamType pt -> pt
|
||||||
_ -> error $ "toParamType: " ++ show t
|
_ -> error ("toParamType "++show t)
|
||||||
|
|
||||||
toParamId :: Term -> ParamId
|
|
||||||
toParamId t = case toParamType t of
|
toParamId t = case toParamType t of
|
||||||
ParamTypeId p -> p
|
ParamTypeId p -> p
|
||||||
|
|
||||||
paramType :: G.Grammar
|
|
||||||
-> (ModuleName, Ident)
|
|
||||||
-> ((S.Set (ModuleName, Ident), S.Set QIdent), [ParamDef])
|
|
||||||
paramType gr q@(_,n) =
|
paramType gr q@(_,n) =
|
||||||
case lookupOrigInfo gr q of
|
case lookupOrigInfo gr q of
|
||||||
Ok (m,ResParam (Just (L _ ps)) _)
|
Ok (m,ResParam (Just (L _ ps)) _)
|
||||||
@@ -382,7 +343,7 @@ paramType gr q@(_,n) =
|
|||||||
((S.singleton (m,n),argTypes ps),
|
((S.singleton (m,n),argTypes ps),
|
||||||
[ParamDef name (map (param m) ps)]
|
[ParamDef name (map (param m) ps)]
|
||||||
)
|
)
|
||||||
where name = gQId m n
|
where name = (gQId m n)
|
||||||
Ok (m,ResOper _ (Just (L _ t)))
|
Ok (m,ResOper _ (Just (L _ t)))
|
||||||
| m==cPredef && n==cInts ->
|
| m==cPredef && n==cInts ->
|
||||||
((S.empty,S.empty),[]) {-
|
((S.empty,S.empty),[]) {-
|
||||||
@@ -390,46 +351,36 @@ paramType gr q@(_,n) =
|
|||||||
[Type (ConAp ((gQId m n)) [identS "n"]) (TId (identS "Int"))])-}
|
[Type (ConAp ((gQId m n)) [identS "n"]) (TId (identS "Int"))])-}
|
||||||
| otherwise ->
|
| otherwise ->
|
||||||
((S.singleton (m,n),paramTypes gr t),
|
((S.singleton (m,n),paramTypes gr t),
|
||||||
[ParamAliasDef (gQId m n) (convType t)])
|
[ParamAliasDef ((gQId m n)) (convType t)])
|
||||||
_ -> ((S.empty,S.empty),[])
|
_ -> ((S.empty,S.empty),[])
|
||||||
where
|
where
|
||||||
param m (n,ctx) = Param (gQId m n) [toParamId t|(_,_,t)<-ctx]
|
param m (n,ctx) = Param ((gQId m n)) [toParamId t|(_,_,t)<-ctx]
|
||||||
argTypes = S.unions . map argTypes1
|
argTypes = S.unions . map argTypes1
|
||||||
argTypes1 (n,ctx) = S.unions [paramTypes gr t|(_,_,t)<-ctx]
|
argTypes1 (n,ctx) = S.unions [paramTypes gr t|(_,_,t)<-ctx]
|
||||||
|
|
||||||
lblId :: Label -> C.LabelId
|
lblId = LabelId . render -- hmm
|
||||||
lblId (LIdent ri) = LabelId ri
|
modId (MN m) = ModId (showIdent m)
|
||||||
lblId (LVar i) = LabelId (rawIdentS (show i)) -- hmm
|
|
||||||
|
|
||||||
modId :: ModuleName -> C.ModId
|
class FromIdent i where gId :: Ident -> i
|
||||||
modId (MN m) = ModId (ident2raw m)
|
|
||||||
|
|
||||||
class FromIdent i where
|
|
||||||
gId :: Ident -> i
|
|
||||||
|
|
||||||
instance FromIdent VarId where
|
instance FromIdent VarId where
|
||||||
gId i = if isWildIdent i then Anonymous else VarId (ident2raw i)
|
gId i = if isWildIdent i then Anonymous else VarId (showIdent i)
|
||||||
|
|
||||||
instance FromIdent C.FunId where gId = C.FunId . ident2raw
|
instance FromIdent C.FunId where gId = C.FunId . showIdent
|
||||||
instance FromIdent CatId where gId = CatId . ident2raw
|
instance FromIdent CatId where gId = CatId . showIdent
|
||||||
instance FromIdent ParamId where gId = ParamId . unqual
|
instance FromIdent ParamId where gId = ParamId . unqual
|
||||||
instance FromIdent VarValueId where gId = VarValueId . unqual
|
instance FromIdent VarValueId where gId = VarValueId . unqual
|
||||||
|
|
||||||
class FromIdent i => QualIdent i where
|
class FromIdent i => QualIdent i where gQId :: ModuleName -> Ident -> i
|
||||||
gQId :: ModuleName -> Ident -> i
|
|
||||||
|
|
||||||
instance QualIdent ParamId where gQId m n = ParamId (qual m n)
|
instance QualIdent ParamId where gQId m n = ParamId (qual m n)
|
||||||
instance QualIdent VarValueId where gQId m n = VarValueId (qual m n)
|
instance QualIdent VarValueId where gQId m n = VarValueId (qual m n)
|
||||||
|
|
||||||
qual :: ModuleName -> Ident -> QualId
|
qual m n = Qual (modId m) (showIdent n)
|
||||||
qual m n = Qual (modId m) (ident2raw n)
|
unqual n = Unqual (showIdent n)
|
||||||
|
|
||||||
unqual :: Ident -> QualId
|
|
||||||
unqual n = Unqual (ident2raw n)
|
|
||||||
|
|
||||||
convFlags :: G.Grammar -> ModuleName -> Flags
|
|
||||||
convFlags gr mn =
|
convFlags gr mn =
|
||||||
Flags [(rawIdentS n,convLit v) |
|
Flags [(n,convLit v) |
|
||||||
(n,v)<-err (const []) (optionsPGF.mflags) (lookupModule gr mn)]
|
(n,v)<-err (const []) (optionsPGF.mflags) (lookupModule gr mn)]
|
||||||
where
|
where
|
||||||
convLit l =
|
convLit l =
|
||||||
|
|||||||
447
src/compiler/GF/Compile/GrammarToLPGF.hs
Normal file
447
src/compiler/GF/Compile/GrammarToLPGF.hs
Normal file
@@ -0,0 +1,447 @@
|
|||||||
|
module GF.Compile.GrammarToLPGF (mkCanon2lpgf) where
|
||||||
|
|
||||||
|
import LPGF (LPGF (..))
|
||||||
|
import qualified LPGF as L
|
||||||
|
|
||||||
|
import PGF.CId
|
||||||
|
import GF.Grammar.Grammar
|
||||||
|
import qualified GF.Grammar.Canonical as C
|
||||||
|
import GF.Compile.GrammarToCanonical (grammar2canonical)
|
||||||
|
|
||||||
|
import GF.Data.Operations (ErrorMonad (..))
|
||||||
|
import qualified GF.Data.IntMapBuilder as IntMapBuilder
|
||||||
|
import GF.Infra.Option (Options)
|
||||||
|
import GF.Infra.UseIO (IOE)
|
||||||
|
import GF.Text.Pretty (pp, render)
|
||||||
|
|
||||||
|
import Control.Applicative ((<|>))
|
||||||
|
import Control.Monad (when, unless, forM, forM_)
|
||||||
|
import qualified Control.Monad.State as CMS
|
||||||
|
import Data.Either (lefts, rights)
|
||||||
|
import qualified Data.IntMap as IntMap
|
||||||
|
import Data.List (elemIndex)
|
||||||
|
import qualified Data.List as L
|
||||||
|
import qualified Data.Map.Strict as Map
|
||||||
|
import Data.Maybe (fromJust, isJust)
|
||||||
|
import System.Environment (lookupEnv)
|
||||||
|
import System.FilePath ((</>), (<.>))
|
||||||
|
import Text.Printf (printf)
|
||||||
|
|
||||||
|
import qualified Debug.Trace
|
||||||
|
trace x = Debug.Trace.trace ("> " ++ show x) (return ())
|
||||||
|
|
||||||
|
mkCanon2lpgf :: Options -> SourceGrammar -> ModuleName -> IOE LPGF
|
||||||
|
mkCanon2lpgf opts gr am = do
|
||||||
|
debug <- isJust <$> lookupEnv "DEBUG"
|
||||||
|
when debug $ do
|
||||||
|
ppCanonical debugDir canon
|
||||||
|
dumpCanonical debugDir canon
|
||||||
|
(an,abs) <- mkAbstract ab
|
||||||
|
cncs <- mapM (mkConcrete debug) cncs
|
||||||
|
let lpgf = LPGF {
|
||||||
|
L.absname = an,
|
||||||
|
L.abstract = abs,
|
||||||
|
L.concretes = Map.fromList cncs
|
||||||
|
}
|
||||||
|
when debug $ ppLPGF debugDir lpgf
|
||||||
|
return lpgf
|
||||||
|
where
|
||||||
|
canon@(C.Grammar ab cncs) = grammar2canonical opts am gr
|
||||||
|
|
||||||
|
mkAbstract :: (ErrorMonad err) => C.Abstract -> err (CId, L.Abstract)
|
||||||
|
mkAbstract (C.Abstract modId flags cats funs) = return (mdi2i modId, L.Abstract {})
|
||||||
|
|
||||||
|
mkConcrete :: (ErrorMonad err) => Bool -> C.Concrete -> err (CId, L.Concrete)
|
||||||
|
mkConcrete debug (C.Concrete modId absModId flags params' lincats lindefs) = do
|
||||||
|
let
|
||||||
|
(C.Abstract _ _ _ funs) = ab
|
||||||
|
params = inlineParamAliases params'
|
||||||
|
|
||||||
|
-- Builds maps for lookups
|
||||||
|
|
||||||
|
paramValueMap :: Map.Map C.ParamId C.ParamDef -- constructor -> definition
|
||||||
|
paramValueMap = Map.fromList [ (v,d) | d@(C.ParamDef _ vs) <- params, (C.Param v _) <- vs ]
|
||||||
|
|
||||||
|
lincatMap :: Map.Map C.CatId C.LincatDef
|
||||||
|
lincatMap = Map.fromList [ (cid,d) | d@(C.LincatDef cid _) <- lincats ]
|
||||||
|
|
||||||
|
funMap :: Map.Map C.FunId C.FunDef
|
||||||
|
funMap = Map.fromList [ (fid,d) | d@(C.FunDef fid _) <- funs ]
|
||||||
|
|
||||||
|
-- | Lookup paramdef, providing dummy fallback when not found
|
||||||
|
-- Workaround for https://github.com/GrammaticalFramework/gf-core/issues/100
|
||||||
|
lookupParamDef :: C.ParamId -> Either String C.ParamDef
|
||||||
|
lookupParamDef pid = case Map.lookup pid paramValueMap of
|
||||||
|
Just d -> Right d
|
||||||
|
Nothing ->
|
||||||
|
-- Left $ printf "Cannot find param definition: %s" (show pid)
|
||||||
|
Right $ C.ParamDef (C.ParamId (C.Unqual "DUMMY")) [C.Param pid []]
|
||||||
|
|
||||||
|
-- | Lookup lintype for a function
|
||||||
|
lookupLinType :: C.FunId -> Either String C.LinType
|
||||||
|
lookupLinType funId = do
|
||||||
|
fun <- m2e (printf "Cannot find type for: %s" (show funId)) (Map.lookup funId funMap)
|
||||||
|
let (C.FunDef _ (C.Type _ (C.TypeApp catId _))) = fun
|
||||||
|
lincat <- m2e (printf "Cannot find lincat for: %s" (show catId)) (Map.lookup catId lincatMap)
|
||||||
|
let (C.LincatDef _ lt) = lincat
|
||||||
|
return lt
|
||||||
|
|
||||||
|
-- | Lookup lintype for a function's argument
|
||||||
|
lookupLinTypeArg :: C.FunId -> Int -> Either String C.LinType
|
||||||
|
lookupLinTypeArg funId argIx = do
|
||||||
|
fun <- m2e (printf "Cannot find type for: %s" (show funId)) (Map.lookup funId funMap)
|
||||||
|
let (C.FunDef _ (C.Type args _)) = fun
|
||||||
|
let (C.TypeBinding _ (C.Type _ (C.TypeApp catId _))) = args !! argIx
|
||||||
|
lincat <- m2e (printf "Cannot find lincat for: %s" (show catId)) (Map.lookup catId lincatMap)
|
||||||
|
let (C.LincatDef _ lt) = lincat
|
||||||
|
return lt
|
||||||
|
|
||||||
|
-- Filter out record fields from definitions which don't appear in lincat.
|
||||||
|
-- Workaround for https://github.com/GrammaticalFramework/gf-core/issues/101
|
||||||
|
cleanupRecordFields :: C.LinValue -> C.LinType -> C.LinValue
|
||||||
|
cleanupRecordFields (C.RecordValue rrvs) (C.RecordType rrs) =
|
||||||
|
let defnFields = Map.fromList [ (lid, lt) | (C.RecordRow lid lt) <- rrs ]
|
||||||
|
in C.RecordValue
|
||||||
|
[ C.RecordRow lid lv'
|
||||||
|
| C.RecordRow lid lv <- rrvs
|
||||||
|
, Map.member lid defnFields
|
||||||
|
, let Just lt = Map.lookup lid defnFields
|
||||||
|
, let lv' = cleanupRecordFields lv lt
|
||||||
|
]
|
||||||
|
cleanupRecordFields lv _ = lv
|
||||||
|
|
||||||
|
lindefs' =
|
||||||
|
[ C.LinDef funId varIds linValue'
|
||||||
|
| (C.LinDef funId varIds linValue) <- lindefs
|
||||||
|
, let Right linType = lookupLinType funId
|
||||||
|
, let linValue' = cleanupRecordFields linValue linType
|
||||||
|
]
|
||||||
|
es = map mkLin lindefs'
|
||||||
|
lins = Map.fromList $ rights es
|
||||||
|
|
||||||
|
-- | Main code generation function
|
||||||
|
mkLin :: C.LinDef -> Either String (CId, L.LinFun)
|
||||||
|
mkLin (C.LinDef funId varIds linValue) = do
|
||||||
|
-- when debug $ trace funId
|
||||||
|
(lf, _) <- val2lin linValue
|
||||||
|
return (fi2i funId, lf)
|
||||||
|
where
|
||||||
|
val2lin :: C.LinValue -> Either String (L.LinFun, Maybe C.LinType)
|
||||||
|
val2lin lv = case lv of
|
||||||
|
|
||||||
|
C.ConcatValue v1 v2 -> do
|
||||||
|
(v1',t1) <- val2lin v1
|
||||||
|
(v2',t2) <- val2lin v2
|
||||||
|
return (L.Concat v1' v2', t1 <|> t2) -- t1 else t2
|
||||||
|
|
||||||
|
C.LiteralValue ll -> case ll of
|
||||||
|
C.FloatConstant f -> return (L.Token $ show f, Just C.FloatType)
|
||||||
|
C.IntConstant i -> return (L.Token $ show i, Just C.IntType)
|
||||||
|
C.StrConstant s -> return (L.Token s, Just C.StrType)
|
||||||
|
|
||||||
|
C.ErrorValue err -> return (L.Error err, Nothing)
|
||||||
|
|
||||||
|
C.ParamConstant (C.Param pid lvs) -> do
|
||||||
|
let
|
||||||
|
collectProjections :: C.LinValue -> Either String [L.LinFun]
|
||||||
|
collectProjections (C.ParamConstant (C.Param pid lvs)) = do
|
||||||
|
def <- lookupParamDef pid
|
||||||
|
let (C.ParamDef tpid defpids) = def
|
||||||
|
pidIx <- eitherElemIndex pid [ p | C.Param p _ <- defpids ]
|
||||||
|
rest <- mapM collectProjections lvs
|
||||||
|
return $ L.Ix (pidIx+1) : concat rest
|
||||||
|
collectProjections lv = do
|
||||||
|
(lf,_) <- val2lin lv
|
||||||
|
return [lf]
|
||||||
|
lfs <- collectProjections lv
|
||||||
|
let term = L.Tuple lfs
|
||||||
|
def <- lookupParamDef pid
|
||||||
|
let (C.ParamDef tpid _) = def
|
||||||
|
return (term, Just $ C.ParamType (C.ParamTypeId tpid))
|
||||||
|
|
||||||
|
C.PredefValue (C.PredefId pid) -> case pid of
|
||||||
|
"BIND" -> return (L.Bind, Nothing)
|
||||||
|
"SOFT_BIND" -> return (L.Bind, Nothing)
|
||||||
|
"SOFT_SPACE" -> return (L.Space, Nothing)
|
||||||
|
"CAPIT" -> return (L.Capit, Nothing)
|
||||||
|
"ALL_CAPIT" -> return (L.AllCapit, Nothing)
|
||||||
|
_ -> Left $ printf "Unknown predef function: %s" pid
|
||||||
|
|
||||||
|
C.RecordValue rrvs -> do
|
||||||
|
let rrvs' = sortRecordRows rrvs
|
||||||
|
ts <- sequence [ val2lin lv | C.RecordRow lid lv <- rrvs' ]
|
||||||
|
return (L.Tuple (map fst ts), Just $ C.RecordType [ C.RecordRow lid lt | (C.RecordRow lid _, (_, Just lt)) <- zip rrvs' ts])
|
||||||
|
|
||||||
|
C.TableValue lt trvs -> do
|
||||||
|
-- group the rows by "left-most" value
|
||||||
|
let
|
||||||
|
groupRow :: C.TableRowValue -> C.TableRowValue -> Bool
|
||||||
|
groupRow (C.TableRow p1 _) (C.TableRow p2 _) = groupPattern p1 p2
|
||||||
|
|
||||||
|
groupPattern :: C.LinPattern -> C.LinPattern -> Bool
|
||||||
|
groupPattern p1 p2 = case (p1,p2) of
|
||||||
|
(C.ParamPattern (C.Param pid1 _), C.ParamPattern (C.Param pid2 _)) -> pid1 == pid2 -- compare only constructors
|
||||||
|
(C.RecordPattern (C.RecordRow lid1 patt1:_), C.RecordPattern (C.RecordRow lid2 patt2:_)) -> groupPattern patt1 patt2 -- lid1 == lid2 necessarily
|
||||||
|
_ -> error $ printf "Mismatched patterns in grouping:\n%s\n%s" (show p1) (show p2)
|
||||||
|
|
||||||
|
grps :: [[C.TableRowValue]]
|
||||||
|
grps = L.groupBy groupRow trvs
|
||||||
|
|
||||||
|
-- remove one level of depth and recurse
|
||||||
|
let
|
||||||
|
handleGroup :: [C.TableRowValue] -> Either String (L.LinFun, Maybe C.LinType)
|
||||||
|
handleGroup [C.TableRow patt lv] =
|
||||||
|
case reducePattern patt of
|
||||||
|
Just patt' -> do
|
||||||
|
(lf,lt) <- handleGroup [C.TableRow patt' lv]
|
||||||
|
return (L.Tuple [lf],lt)
|
||||||
|
Nothing -> val2lin lv
|
||||||
|
handleGroup rows = do
|
||||||
|
let rows' = map reduceRow rows
|
||||||
|
val2lin (C.TableValue lt rows') -- lt is wrong here, but is unused
|
||||||
|
|
||||||
|
reducePattern :: C.LinPattern -> Maybe C.LinPattern
|
||||||
|
reducePattern patt =
|
||||||
|
case patt of
|
||||||
|
C.ParamPattern (C.Param _ []) -> Nothing
|
||||||
|
C.ParamPattern (C.Param _ patts) -> Just $ C.ParamPattern (C.Param pid' patts')
|
||||||
|
where
|
||||||
|
C.ParamPattern (C.Param pid1 patts1) = head patts
|
||||||
|
pid' = pid1
|
||||||
|
patts' = patts1 ++ tail patts
|
||||||
|
|
||||||
|
C.RecordPattern [] -> Nothing
|
||||||
|
C.RecordPattern (C.RecordRow lid patt:rrs) ->
|
||||||
|
case reducePattern patt of
|
||||||
|
Just patt' -> Just $ C.RecordPattern (C.RecordRow lid patt':rrs)
|
||||||
|
Nothing -> if null rrs then Nothing else Just $ C.RecordPattern rrs
|
||||||
|
|
||||||
|
_ -> error $ printf "Unhandled pattern in reducing: %s" (show patt)
|
||||||
|
|
||||||
|
reduceRow :: C.TableRowValue -> C.TableRowValue
|
||||||
|
reduceRow (C.TableRow patt lv) =
|
||||||
|
let Just patt' = reducePattern patt
|
||||||
|
in C.TableRow patt' lv
|
||||||
|
|
||||||
|
-- ts :: [(L.LinFun, Maybe C.LinType)]
|
||||||
|
ts <- mapM handleGroup grps
|
||||||
|
|
||||||
|
-- return
|
||||||
|
let typ = case ts of
|
||||||
|
(_, Just tst):_ -> Just $ C.TableType lt tst
|
||||||
|
_ -> Nothing
|
||||||
|
return (L.Tuple (map fst ts), typ)
|
||||||
|
|
||||||
|
-- TODO TuplePattern, WildPattern?
|
||||||
|
|
||||||
|
C.TupleValue lvs -> do
|
||||||
|
ts <- mapM val2lin lvs
|
||||||
|
return (L.Tuple (map fst ts), Just $ C.TupleType (map (fromJust.snd) ts))
|
||||||
|
|
||||||
|
C.VariantValue [] -> return (L.Empty, Nothing) -- TODO Just C.StrType ?
|
||||||
|
C.VariantValue (vr:_) -> val2lin vr -- NOTE variants not supported, just pick first
|
||||||
|
|
||||||
|
C.VarValue (C.VarValueId (C.Unqual v)) -> do
|
||||||
|
ix <- eitherElemIndex (C.VarId v) varIds
|
||||||
|
lt <- lookupLinTypeArg funId ix
|
||||||
|
return (L.Argument (ix+1), Just lt)
|
||||||
|
|
||||||
|
C.PreValue pts df -> do
|
||||||
|
pts' <- forM pts $ \(pfxs, lv) -> do
|
||||||
|
(lv', _) <- val2lin lv
|
||||||
|
return (pfxs, lv')
|
||||||
|
(df', lt) <- val2lin df
|
||||||
|
return (L.Pre pts' df', lt)
|
||||||
|
|
||||||
|
C.Projection v1 lblId -> do
|
||||||
|
(v1', mtyp) <- val2lin v1
|
||||||
|
-- find label index in argument type
|
||||||
|
let Just (C.RecordType rrs) = mtyp
|
||||||
|
let rrs' = [ lid | C.RecordRow lid _ <- rrs ]
|
||||||
|
-- lblIx <- eitherElemIndex lblId rrs'
|
||||||
|
let
|
||||||
|
lblIx = case eitherElemIndex lblId rrs' of
|
||||||
|
Right x -> x
|
||||||
|
Left _ -> 0 -- corresponds to Prelude.False
|
||||||
|
-- lookup lintype for record row
|
||||||
|
let C.RecordRow _ lt = rrs !! lblIx
|
||||||
|
return (L.Projection v1' (L.Ix (lblIx+1)), Just lt)
|
||||||
|
|
||||||
|
C.Selection v1 v2 -> do
|
||||||
|
(v1', t1) <- val2lin v1
|
||||||
|
(v2', t2) <- val2lin v2
|
||||||
|
let Just (C.TableType t11 t12) = t1 -- t11 == t2
|
||||||
|
return (L.Projection v1' v2', Just t12)
|
||||||
|
|
||||||
|
-- C.CommentedValue cmnt lv -> val2lin lv
|
||||||
|
C.CommentedValue cmnt lv -> case cmnt of
|
||||||
|
"impossible" -> val2lin lv >>= \(_, typ) -> return (L.Empty, typ)
|
||||||
|
_ -> val2lin lv
|
||||||
|
|
||||||
|
v -> Left $ printf "val2lin not implemented for: %s" (show v)
|
||||||
|
|
||||||
|
unless (null $ lefts es) (raise $ unlines (lefts es))
|
||||||
|
|
||||||
|
let maybeOptimise = if debug then id else extractStrings
|
||||||
|
let concr = maybeOptimise $ L.Concrete {
|
||||||
|
L.toks = IntMap.empty,
|
||||||
|
L.lins = lins
|
||||||
|
}
|
||||||
|
return (mdi2i modId, concr)
|
||||||
|
|
||||||
|
-- | Remove ParamAliasDefs by inlining their definitions
|
||||||
|
inlineParamAliases :: [C.ParamDef] -> [C.ParamDef]
|
||||||
|
inlineParamAliases defs = if null aliases then defs else map rp' pdefs
|
||||||
|
where
|
||||||
|
(aliases,pdefs) = L.partition isParamAliasDef defs
|
||||||
|
|
||||||
|
rp' :: C.ParamDef -> C.ParamDef
|
||||||
|
rp' (C.ParamDef pid pids) = C.ParamDef pid (map rp'' pids)
|
||||||
|
rp' (C.ParamAliasDef _ _) = error "inlineParamAliases called on ParamAliasDef" -- impossible
|
||||||
|
|
||||||
|
rp'' :: C.ParamValueDef -> C.ParamValueDef
|
||||||
|
rp'' (C.Param pid pids) = C.Param pid (map rp''' pids)
|
||||||
|
|
||||||
|
rp''' :: C.ParamId -> C.ParamId
|
||||||
|
rp''' pid = case L.find (\(C.ParamAliasDef p _) -> p == pid) aliases of
|
||||||
|
Just (C.ParamAliasDef _ (C.ParamType (C.ParamTypeId p))) -> p
|
||||||
|
_ -> pid
|
||||||
|
|
||||||
|
-- | Always put 's' reocord field first, then sort alphabetically.
|
||||||
|
-- Workaround for https://github.com/GrammaticalFramework/gf-core/issues/102
|
||||||
|
-- Based on GF.Granmar.Macros.sortRec
|
||||||
|
sortRecordRows :: [C.RecordRowValue] -> [C.RecordRowValue]
|
||||||
|
sortRecordRows = L.sortBy ordLabel
|
||||||
|
where
|
||||||
|
ordLabel (C.RecordRow (C.LabelId l1) _) (C.RecordRow (C.LabelId l2) _) =
|
||||||
|
case (l1,l2) of
|
||||||
|
("s",_) -> LT
|
||||||
|
(_,"s") -> GT
|
||||||
|
(s1,s2) -> compare s1 s2
|
||||||
|
|
||||||
|
-- sortRecord :: C.LinValue -> C.LinValue
|
||||||
|
-- sortRecord (C.RecordValue rrvs) = C.RecordValue (sortRecordRows rrvs)
|
||||||
|
-- sortRecord lv = lv
|
||||||
|
|
||||||
|
isParamAliasDef :: C.ParamDef -> Bool
|
||||||
|
isParamAliasDef (C.ParamAliasDef _ _) = True
|
||||||
|
isParamAliasDef _ = False
|
||||||
|
|
||||||
|
isParamType :: C.LinType -> Bool
|
||||||
|
isParamType (C.ParamType _) = True
|
||||||
|
isParamType _ = False
|
||||||
|
|
||||||
|
isRecordType :: C.LinType -> Bool
|
||||||
|
isRecordType (C.RecordType _) = True
|
||||||
|
isRecordType _ = False
|
||||||
|
|
||||||
|
-- | Find all token strings, put them in a map and replace with token indexes
|
||||||
|
extractStrings :: L.Concrete -> L.Concrete
|
||||||
|
extractStrings concr = L.Concrete { L.toks = toks', L.lins = lins' }
|
||||||
|
where
|
||||||
|
imb = IntMapBuilder.fromIntMap (L.toks concr)
|
||||||
|
(lins',imb') = CMS.runState (go0 (L.lins concr)) imb
|
||||||
|
toks' = IntMapBuilder.toIntMap imb'
|
||||||
|
|
||||||
|
go0 :: Map.Map CId L.LinFun -> CMS.State (IntMapBuilder.IMB String) (Map.Map CId L.LinFun)
|
||||||
|
go0 mp = do
|
||||||
|
xs <- mapM (\(cid,lin) -> go lin >>= \lin' -> return (cid,lin')) (Map.toList mp)
|
||||||
|
return $ Map.fromList xs
|
||||||
|
|
||||||
|
go :: L.LinFun -> CMS.State (IntMapBuilder.IMB String) L.LinFun
|
||||||
|
go lf = case lf of
|
||||||
|
L.Token str -> do
|
||||||
|
imb <- CMS.get
|
||||||
|
let (ix,imb') = IntMapBuilder.insert' str imb
|
||||||
|
CMS.put imb'
|
||||||
|
return $ L.TokenIx ix
|
||||||
|
|
||||||
|
L.Pre pts df -> do
|
||||||
|
-- pts' <- mapM (\(pfxs,lv) -> go lv >>= \lv' -> return (pfxs,lv')) pts
|
||||||
|
pts' <- forM pts $ \(pfxs,lv) -> do
|
||||||
|
imb <- CMS.get
|
||||||
|
let str = show pfxs
|
||||||
|
let (ix,imb') = IntMapBuilder.insert' str imb
|
||||||
|
CMS.put imb'
|
||||||
|
lv' <- go lv
|
||||||
|
return (ix,lv')
|
||||||
|
df' <- go df
|
||||||
|
return $ L.PreIx pts' df'
|
||||||
|
L.Concat s t -> do
|
||||||
|
s' <- go s
|
||||||
|
t' <- go t
|
||||||
|
return $ L.Concat s' t'
|
||||||
|
L.Tuple ts -> do
|
||||||
|
ts' <- mapM go ts
|
||||||
|
return $ L.Tuple ts'
|
||||||
|
L.Projection t u -> do
|
||||||
|
t' <- go t
|
||||||
|
u' <- go u
|
||||||
|
return $ L.Projection t' u'
|
||||||
|
t -> return t
|
||||||
|
|
||||||
|
-- | Convert Maybe to Either value with error
|
||||||
|
m2e :: String -> Maybe a -> Either String a
|
||||||
|
m2e err = maybe (Left err) Right
|
||||||
|
|
||||||
|
-- | Wrap elemIndex into Either value
|
||||||
|
eitherElemIndex :: (Eq a, Show a) => a -> [a] -> Either String Int
|
||||||
|
eitherElemIndex x xs = m2e (printf "Cannot find: %s in %s" (show x) (show xs)) (elemIndex x xs)
|
||||||
|
|
||||||
|
mdi2s :: C.ModId -> String
|
||||||
|
mdi2s (C.ModId i) = i
|
||||||
|
|
||||||
|
mdi2i :: C.ModId -> CId
|
||||||
|
mdi2i (C.ModId i) = mkCId i
|
||||||
|
|
||||||
|
fi2i :: C.FunId -> CId
|
||||||
|
fi2i (C.FunId i) = mkCId i
|
||||||
|
|
||||||
|
-- Debugging
|
||||||
|
|
||||||
|
debugDir :: FilePath
|
||||||
|
debugDir = "DEBUG"
|
||||||
|
|
||||||
|
-- | Pretty-print canonical grammars to file
|
||||||
|
ppCanonical :: FilePath -> C.Grammar -> IO ()
|
||||||
|
ppCanonical path (C.Grammar ab cncs) = do
|
||||||
|
let (C.Abstract modId flags cats funs) = ab
|
||||||
|
writeFile (path </> mdi2s modId <.> "canonical.gf") (render $ pp ab)
|
||||||
|
forM_ cncs $ \cnc@(C.Concrete modId absModId flags params lincats lindefs) ->
|
||||||
|
writeFile' (path </> mdi2s modId <.> "canonical.gf") (render $ pp cnc)
|
||||||
|
|
||||||
|
-- | Dump canonical grammars to file
|
||||||
|
dumpCanonical :: FilePath -> C.Grammar -> IO ()
|
||||||
|
dumpCanonical path (C.Grammar ab cncs) = do
|
||||||
|
let (C.Abstract modId flags cats funs) = ab
|
||||||
|
let body = unlines $ map show cats ++ [""] ++ map show funs
|
||||||
|
writeFile' (path </> mdi2s modId <.> "canonical.dump") body
|
||||||
|
|
||||||
|
forM_ cncs $ \(C.Concrete modId absModId flags params lincats lindefs) -> do
|
||||||
|
let body = unlines $ concat [
|
||||||
|
map show params,
|
||||||
|
[""],
|
||||||
|
map show lincats,
|
||||||
|
[""],
|
||||||
|
map show lindefs
|
||||||
|
]
|
||||||
|
writeFile' (path </> mdi2s modId <.> "canonical.dump") body
|
||||||
|
|
||||||
|
-- | Pretty-print LPGF to file
|
||||||
|
ppLPGF :: FilePath -> LPGF -> IO ()
|
||||||
|
ppLPGF path lpgf =
|
||||||
|
forM_ (Map.toList $ L.concretes lpgf) $ \(cid,concr) ->
|
||||||
|
writeFile' (path </> showCId cid <.> "lpgf.txt") (L.render $ L.pp concr)
|
||||||
|
|
||||||
|
-- | Dump LPGF to file
|
||||||
|
dumpLPGF :: FilePath -> LPGF -> IO ()
|
||||||
|
dumpLPGF path lpgf =
|
||||||
|
forM_ (Map.toList $ L.concretes lpgf) $ \(cid,concr) -> do
|
||||||
|
let body = unlines $ map show (Map.toList $ L.lins concr)
|
||||||
|
writeFile' (path </> showCId cid <.> "lpgf.dump") body
|
||||||
|
|
||||||
|
-- | Write a file and report it to console
|
||||||
|
writeFile' :: FilePath -> String -> IO ()
|
||||||
|
writeFile' p b = do
|
||||||
|
writeFile p b
|
||||||
|
putStrLn $ "Wrote " ++ p
|
||||||
@@ -1,14 +1,17 @@
|
|||||||
{-# LANGUAGE ImplicitParams, BangPatterns, FlexibleContexts, MagicHash #-}
|
{-# LANGUAGE BangPatterns, FlexibleContexts #-}
|
||||||
module GF.Compile.GrammarToPGF (grammar2PGF) where
|
module GF.Compile.GrammarToPGF (mkCanon2pgf) where
|
||||||
|
|
||||||
|
--import GF.Compile.Export
|
||||||
import GF.Compile.GeneratePMCFG
|
import GF.Compile.GeneratePMCFG
|
||||||
import GF.Compile.GenerateBC
|
import GF.Compile.GenerateBC
|
||||||
import GF.Compile.OptimizePGF
|
|
||||||
|
|
||||||
import PGF2 hiding (mkType)
|
import PGF(CId,mkCId,utf8CId)
|
||||||
import PGF2.Internal
|
import PGF.Internal(fidInt,fidFloat,fidString,fidVar)
|
||||||
|
import PGF.Internal(updateProductionIndices)
|
||||||
|
import qualified PGF.Internal as C
|
||||||
|
import qualified PGF.Internal as D
|
||||||
import GF.Grammar.Predef
|
import GF.Grammar.Predef
|
||||||
import GF.Grammar.Grammar hiding (Production)
|
import GF.Grammar.Grammar
|
||||||
import qualified GF.Grammar.Lookup as Look
|
import qualified GF.Grammar.Lookup as Look
|
||||||
import qualified GF.Grammar as A
|
import qualified GF.Grammar as A
|
||||||
import qualified GF.Grammar.Macros as GM
|
import qualified GF.Grammar.Macros as GM
|
||||||
@@ -19,141 +22,111 @@ import GF.Infra.UseIO (IOE)
|
|||||||
import GF.Data.Operations
|
import GF.Data.Operations
|
||||||
|
|
||||||
import Data.List
|
import Data.List
|
||||||
import Data.Char
|
|
||||||
import qualified Data.Set as Set
|
import qualified Data.Set as Set
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
import qualified Data.IntMap as IntMap
|
import qualified Data.IntMap as IntMap
|
||||||
import Data.Array.IArray
|
import Data.Array.IArray
|
||||||
import Data.Maybe(fromMaybe)
|
|
||||||
|
|
||||||
import GHC.Prim
|
|
||||||
import GHC.Base(getTag)
|
|
||||||
|
|
||||||
grammar2PGF :: Options -> SourceGrammar -> ModuleName -> Map.Map PGF2.Fun Double -> IO PGF
|
mkCanon2pgf :: Options -> SourceGrammar -> ModuleName -> IOE D.PGF
|
||||||
grammar2PGF opts gr am probs = do
|
mkCanon2pgf opts gr am = do
|
||||||
cnc_infos <- getConcreteInfos gr am
|
(an,abs) <- mkAbstr am
|
||||||
return $
|
cncs <- mapM mkConcr (allConcretes gr am)
|
||||||
build (let gflags = if flag optSplitPGF opts
|
return $ updateProductionIndices (D.PGF Map.empty an abs (Map.fromList cncs))
|
||||||
then [("split", LStr "true")]
|
|
||||||
else []
|
|
||||||
(an,abs) = mkAbstr am probs
|
|
||||||
cncs = map (mkConcr opts abs) cnc_infos
|
|
||||||
in newPGF gflags an abs cncs)
|
|
||||||
where
|
where
|
||||||
cenv = resourceValues opts gr
|
cenv = resourceValues opts gr
|
||||||
aflags = err (const noOptions) mflags (lookupModule gr am)
|
|
||||||
|
|
||||||
mkAbstr :: (?builder :: Builder s) => ModuleName -> Map.Map PGF2.Fun Double -> (AbsName, B s AbstrInfo)
|
mkAbstr am = return (mi2i am, D.Abstr flags funs cats)
|
||||||
mkAbstr am probs = (mi2i am, newAbstr flags cats funs)
|
|
||||||
where
|
where
|
||||||
|
aflags = err (const noOptions) mflags (lookupModule gr am)
|
||||||
|
|
||||||
adefs =
|
adefs =
|
||||||
[((cPredefAbs,c), AbsCat (Just (L NoLoc []))) | c <- [cFloat,cInt,cString]] ++
|
[((cPredefAbs,c), AbsCat (Just (L NoLoc []))) | c <- [cFloat,cInt,cString]] ++
|
||||||
Look.allOrigInfos gr am
|
Look.allOrigInfos gr am
|
||||||
|
|
||||||
flags = optionsPGF aflags
|
flags = Map.fromList [(mkCId f,x) | (f,x) <- optionsPGF aflags]
|
||||||
|
|
||||||
toLogProb = realToFrac . negate . log
|
funs = Map.fromList [(i2i f, (mkType [] ty, arity, mkDef gr arity mdef, 0)) |
|
||||||
|
|
||||||
cats = [(c', snd (mkContext [] cont), toLogProb (fromMaybe 0 (Map.lookup c' probs))) |
|
|
||||||
((m,c),AbsCat (Just (L _ cont))) <- adefs, let c' = i2i c]
|
|
||||||
|
|
||||||
funs = [(f', mkType [] ty, arity, bcode, toLogProb (fromMaybe 0 (Map.lookup f' funs_probs))) |
|
|
||||||
((m,f),AbsFun (Just (L _ ty)) ma mdef _) <- adefs,
|
((m,f),AbsFun (Just (L _ ty)) ma mdef _) <- adefs,
|
||||||
let arity = mkArity ma mdef ty,
|
let arity = mkArity ma mdef ty]
|
||||||
let bcode = mkDef gr arity mdef,
|
|
||||||
let f' = i2i f]
|
|
||||||
|
|
||||||
funs_probs = (Map.fromList . concat . Map.elems . fmap pad . Map.fromListWith (++))
|
|
||||||
[(i2i cat,[(i2i f,Map.lookup f' probs)]) | ((m,f),AbsFun (Just (L _ ty)) _ _ _) <- adefs,
|
|
||||||
let (_,(_,cat),_) = GM.typeForm ty,
|
|
||||||
let f' = i2i f]
|
|
||||||
where
|
|
||||||
pad :: [(a,Maybe Double)] -> [(a,Double)]
|
|
||||||
pad pfs = [(f,fromMaybe deflt mb_p) | (f,mb_p) <- pfs]
|
|
||||||
where
|
|
||||||
deflt = case length [f | (f,Nothing) <- pfs] of
|
|
||||||
0 -> 0
|
|
||||||
n -> max 0 ((1 - sum [d | (f,Just d) <- pfs]) / fromIntegral n)
|
|
||||||
|
|
||||||
mkConcr opts abs (cm,ex_seqs,cdefs) =
|
cats = Map.fromList [(i2i c, (snd (mkContext [] cont),catfuns c, 0)) |
|
||||||
|
((m,c),AbsCat (Just (L _ cont))) <- adefs]
|
||||||
|
|
||||||
|
catfuns cat =
|
||||||
|
[(0,i2i f) | ((m,f),AbsFun (Just (L _ ty)) _ _ (Just True)) <- adefs, snd (GM.valCat ty) == cat]
|
||||||
|
|
||||||
|
mkConcr cm = do
|
||||||
let cflags = err (const noOptions) mflags (lookupModule gr cm)
|
let cflags = err (const noOptions) mflags (lookupModule gr cm)
|
||||||
ciCmp | flag optCaseSensitive cflags = compare
|
ciCmp | flag optCaseSensitive cflags = compare
|
||||||
| otherwise = compareCaseInsensitive
|
| otherwise = C.compareCaseInsensitve
|
||||||
|
|
||||||
flags = optionsPGF aflags
|
(ex_seqs,cdefs) <- addMissingPMCFGs
|
||||||
|
Map.empty
|
||||||
|
([((cPredefAbs,c), CncCat (Just (L NoLoc GM.defLinType)) Nothing Nothing Nothing Nothing) | c <- [cInt,cFloat,cString]] ++
|
||||||
|
Look.allOrigInfos gr cm)
|
||||||
|
|
||||||
seqs = (mkSetArray . Set.fromList . concat) $
|
let flags = Map.fromList [(mkCId f,x) | (f,x) <- optionsPGF cflags]
|
||||||
(elems (ex_seqs :: Array SeqId [Symbol]) : [maybe [] elems (mseqs mi) | (m,mi) <- allExtends gr cm])
|
|
||||||
|
seqs = (mkArray . C.sortNubBy ciCmp . concat) $
|
||||||
|
(Map.keys ex_seqs : [maybe [] elems (mseqs mi) | (m,mi) <- allExtends gr cm])
|
||||||
|
|
||||||
|
ex_seqs_arr = mkMapArray ex_seqs :: Array SeqId Sequence
|
||||||
|
|
||||||
!(!fid_cnt1,!cnccats) = genCncCats gr am cm cdefs
|
!(!fid_cnt1,!cnccats) = genCncCats gr am cm cdefs
|
||||||
cnccat_ranges = Map.fromList (map (\(cid,s,e,_) -> (cid,(s,e))) cnccats)
|
|
||||||
!(!fid_cnt2,!productions,!lindefs,!linrefs,!cncfuns)
|
!(!fid_cnt2,!productions,!lindefs,!linrefs,!cncfuns)
|
||||||
= genCncFuns gr am cm ex_seqs ciCmp seqs cdefs fid_cnt1 cnccat_ranges
|
= genCncFuns gr am cm ex_seqs_arr ciCmp seqs cdefs fid_cnt1 cnccats
|
||||||
|
|
||||||
printnames = genPrintNames cdefs
|
printnames = genPrintNames cdefs
|
||||||
|
return (mi2i cm, D.Concr flags
|
||||||
startCat = (fromMaybe "S" (flag optStartCat aflags))
|
printnames
|
||||||
|
cncfuns
|
||||||
(lindefs',linrefs',productions',cncfuns',sequences',cnccats') =
|
lindefs
|
||||||
(if flag optOptimizePGF opts then optimizePGF startCat else id)
|
linrefs
|
||||||
(lindefs,linrefs,productions,cncfuns,elems seqs,cnccats)
|
seqs
|
||||||
|
productions
|
||||||
in (mi2i cm, newConcr abs
|
IntMap.empty
|
||||||
flags
|
Map.empty
|
||||||
printnames
|
cnccats
|
||||||
lindefs'
|
IntMap.empty
|
||||||
linrefs'
|
fid_cnt2)
|
||||||
productions'
|
|
||||||
cncfuns'
|
|
||||||
sequences'
|
|
||||||
cnccats'
|
|
||||||
fid_cnt2)
|
|
||||||
|
|
||||||
getConcreteInfos gr am = mapM flatten (allConcretes gr am)
|
|
||||||
where
|
where
|
||||||
flatten cm = do
|
|
||||||
(seqs,infos) <- addMissingPMCFGs cm Map.empty
|
|
||||||
(lit_infos ++ Look.allOrigInfos gr cm)
|
|
||||||
return (cm,mkMapArray seqs :: Array SeqId [Symbol],infos)
|
|
||||||
|
|
||||||
lit_infos = [((cPredefAbs,c), CncCat (Just (L NoLoc GM.defLinType)) Nothing Nothing Nothing Nothing) | c <- [cInt,cFloat,cString]]
|
|
||||||
|
|
||||||
-- if some module was compiled with -no-pmcfg, then
|
-- if some module was compiled with -no-pmcfg, then
|
||||||
-- we have to create the PMCFG code just before linking
|
-- we have to create the PMCFG code just before linking
|
||||||
addMissingPMCFGs cm seqs [] = return (seqs,[])
|
addMissingPMCFGs seqs [] = return (seqs,[])
|
||||||
addMissingPMCFGs cm seqs (((m,id), info):is) = do
|
addMissingPMCFGs seqs (((m,id), info):is) = do
|
||||||
(seqs,info) <- addPMCFG opts gr cenv Nothing am cm seqs id info
|
(seqs,info) <- addPMCFG opts gr cenv Nothing am cm seqs id info
|
||||||
(seqs,infos) <- addMissingPMCFGs cm seqs is
|
(seqs,is ) <- addMissingPMCFGs seqs is
|
||||||
return (seqs, ((m,id), info) : infos)
|
return (seqs, ((m,id), info) : is)
|
||||||
|
|
||||||
i2i :: Ident -> String
|
i2i :: Ident -> CId
|
||||||
i2i = showIdent
|
i2i = utf8CId . ident2utf8
|
||||||
|
|
||||||
mi2i :: ModuleName -> String
|
mi2i :: ModuleName -> CId
|
||||||
mi2i (MN i) = i2i i
|
mi2i (MN i) = i2i i
|
||||||
|
|
||||||
mkType :: (?builder :: Builder s) => [Ident] -> A.Type -> B s PGF2.Type
|
mkType :: [Ident] -> A.Type -> C.Type
|
||||||
mkType scope t =
|
mkType scope t =
|
||||||
case GM.typeForm t of
|
case GM.typeForm t of
|
||||||
(hyps,(_,cat),args) -> let (scope',hyps') = mkContext scope hyps
|
(hyps,(_,cat),args) -> let (scope',hyps') = mkContext scope hyps
|
||||||
in dTyp hyps' (i2i cat) (map (mkExp scope') args)
|
in C.DTyp hyps' (i2i cat) (map (mkExp scope') args)
|
||||||
|
|
||||||
mkExp :: (?builder :: Builder s) => [Ident] -> A.Term -> B s Expr
|
mkExp :: [Ident] -> A.Term -> C.Expr
|
||||||
mkExp scope t =
|
mkExp scope t =
|
||||||
case t of
|
case t of
|
||||||
Q (_,c) -> eFun (i2i c)
|
Q (_,c) -> C.EFun (i2i c)
|
||||||
QC (_,c) -> eFun (i2i c)
|
QC (_,c) -> C.EFun (i2i c)
|
||||||
Vr x -> case lookup x (zip scope [0..]) of
|
Vr x -> case lookup x (zip scope [0..]) of
|
||||||
Just i -> eVar i
|
Just i -> C.EVar i
|
||||||
Nothing -> eMeta 0
|
Nothing -> C.EMeta 0
|
||||||
Abs b x t-> eAbs b (i2i x) (mkExp (x:scope) t)
|
Abs b x t-> C.EAbs b (i2i x) (mkExp (x:scope) t)
|
||||||
App t1 t2-> eApp (mkExp scope t1) (mkExp scope t2)
|
App t1 t2-> C.EApp (mkExp scope t1) (mkExp scope t2)
|
||||||
EInt i -> eLit (LInt (fromIntegral i))
|
EInt i -> C.ELit (C.LInt (fromIntegral i))
|
||||||
EFloat f -> eLit (LFlt f)
|
EFloat f -> C.ELit (C.LFlt f)
|
||||||
K s -> eLit (LStr s)
|
K s -> C.ELit (C.LStr s)
|
||||||
Meta i -> eMeta i
|
Meta i -> C.EMeta i
|
||||||
_ -> eMeta 0
|
_ -> C.EMeta 0
|
||||||
{-
|
|
||||||
mkPatt scope p =
|
mkPatt scope p =
|
||||||
case p of
|
case p of
|
||||||
A.PP (_,c) ps->let (scope',ps') = mapAccumL mkPatt scope ps
|
A.PP (_,c) ps->let (scope',ps') = mapAccumL mkPatt scope ps
|
||||||
@@ -168,64 +141,67 @@ mkPatt scope p =
|
|||||||
A.PImplArg p-> let (scope',p') = mkPatt scope p
|
A.PImplArg p-> let (scope',p') = mkPatt scope p
|
||||||
in (scope',C.PImplArg p')
|
in (scope',C.PImplArg p')
|
||||||
A.PTilde t -> ( scope,C.PTilde (mkExp scope t))
|
A.PTilde t -> ( scope,C.PTilde (mkExp scope t))
|
||||||
-}
|
|
||||||
mkContext :: (?builder :: Builder s) => [Ident] -> A.Context -> ([Ident],[B s PGF2.Hypo])
|
mkContext :: [Ident] -> A.Context -> ([Ident],[C.Hypo])
|
||||||
mkContext scope hyps = mapAccumL (\scope (bt,x,ty) -> let ty' = mkType scope ty
|
mkContext scope hyps = mapAccumL (\scope (bt,x,ty) -> let ty' = mkType scope ty
|
||||||
in if x == identW
|
in if x == identW
|
||||||
then ( scope,hypo bt (i2i x) ty')
|
then ( scope,(bt,i2i x,ty'))
|
||||||
else (x:scope,hypo bt (i2i x) ty')) scope hyps
|
else (x:scope,(bt,i2i x,ty'))) scope hyps
|
||||||
|
|
||||||
mkDef gr arity (Just eqs) = generateByteCode gr arity eqs
|
mkDef gr arity (Just eqs) = Just ([C.Equ ps' (mkExp scope' e) | L _ (ps,e) <- eqs, let (scope',ps') = mapAccumL mkPatt [] ps]
|
||||||
mkDef gr arity Nothing = []
|
,generateByteCode gr arity eqs
|
||||||
|
)
|
||||||
|
mkDef gr arity Nothing = Nothing
|
||||||
|
|
||||||
mkArity (Just a) _ ty = a -- known arity, i.e. defined function
|
mkArity (Just a) _ ty = a -- known arity, i.e. defined function
|
||||||
mkArity Nothing (Just _) ty = 0 -- defined function with no arity - must be an axiom
|
mkArity Nothing (Just _) ty = 0 -- defined function with no arity - must be an axiom
|
||||||
mkArity Nothing _ ty = let (ctxt, _, _) = GM.typeForm ty -- constructor
|
mkArity Nothing _ ty = let (ctxt, _, _) = GM.typeForm ty -- constructor
|
||||||
in length ctxt
|
in length ctxt
|
||||||
|
|
||||||
genCncCats gr am cm cdefs = mkCncCats 0 cdefs
|
genCncCats gr am cm cdefs =
|
||||||
|
let (index,cats) = mkCncCats 0 cdefs
|
||||||
|
in (index, Map.fromList cats)
|
||||||
where
|
where
|
||||||
mkCncCats index [] = (index,[])
|
mkCncCats index [] = (index,[])
|
||||||
mkCncCats index (((m,id),CncCat (Just (L _ lincat)) _ _ _ _):cdefs)
|
mkCncCats index (((m,id),CncCat (Just (L _ lincat)) _ _ _ _):cdefs)
|
||||||
| id == cInt =
|
| id == cInt =
|
||||||
let cc = pgfCncCat gr (i2i id) lincat fidInt
|
let cc = pgfCncCat gr lincat fidInt
|
||||||
(index',cats) = mkCncCats index cdefs
|
(index',cats) = mkCncCats index cdefs
|
||||||
in (index', cc : cats)
|
in (index', (i2i id,cc) : cats)
|
||||||
| id == cFloat =
|
| id == cFloat =
|
||||||
let cc = pgfCncCat gr (i2i id) lincat fidFloat
|
let cc = pgfCncCat gr lincat fidFloat
|
||||||
(index',cats) = mkCncCats index cdefs
|
(index',cats) = mkCncCats index cdefs
|
||||||
in (index', cc : cats)
|
in (index', (i2i id,cc) : cats)
|
||||||
| id == cString =
|
| id == cString =
|
||||||
let cc = pgfCncCat gr (i2i id) lincat fidString
|
let cc = pgfCncCat gr lincat fidString
|
||||||
(index',cats) = mkCncCats index cdefs
|
(index',cats) = mkCncCats index cdefs
|
||||||
in (index', cc : cats)
|
in (index', (i2i id,cc) : cats)
|
||||||
| otherwise =
|
| otherwise =
|
||||||
let cc@(_, _s, e, _) = pgfCncCat gr (i2i id) lincat index
|
let cc@(C.CncCat _s e _) = pgfCncCat gr lincat index
|
||||||
(index',cats) = mkCncCats (e+1) cdefs
|
(index',cats) = mkCncCats (e+1) cdefs
|
||||||
in (index', cc : cats)
|
in (index', (i2i id,cc) : cats)
|
||||||
mkCncCats index (_ :cdefs) = mkCncCats index cdefs
|
mkCncCats index (_ :cdefs) = mkCncCats index cdefs
|
||||||
|
|
||||||
genCncFuns :: Grammar
|
genCncFuns :: Grammar
|
||||||
-> ModuleName
|
-> ModuleName
|
||||||
-> ModuleName
|
-> ModuleName
|
||||||
-> Array SeqId [Symbol]
|
-> Array SeqId Sequence
|
||||||
-> ([Symbol] -> [Symbol] -> Ordering)
|
-> (Sequence -> Sequence -> Ordering)
|
||||||
-> Array SeqId [Symbol]
|
-> Array SeqId Sequence
|
||||||
-> [(QIdent, Info)]
|
-> [(QIdent, Info)]
|
||||||
-> FId
|
-> FId
|
||||||
-> Map.Map PGF2.Cat (Int,Int)
|
-> Map.Map CId D.CncCat
|
||||||
-> (FId,
|
-> (FId,
|
||||||
[(FId, [Production])],
|
IntMap.IntMap (Set.Set D.Production),
|
||||||
[(FId, [FunId])],
|
IntMap.IntMap [FunId],
|
||||||
[(FId, [FunId])],
|
IntMap.IntMap [FunId],
|
||||||
[(PGF2.Fun,[SeqId])])
|
Array FunId D.CncFun)
|
||||||
genCncFuns gr am cm ex_seqs ciCmp seqs cdefs fid_cnt cnccat_ranges =
|
genCncFuns gr am cm ex_seqs ciCmp seqs cdefs fid_cnt cnccats =
|
||||||
let (fid_cnt1,funs_cnt1,funs1,lindefs,linrefs) = mkCncCats cdefs fid_cnt 0 [] IntMap.empty IntMap.empty
|
let (fid_cnt1,funs_cnt1,funs1,lindefs,linrefs) = mkCncCats cdefs fid_cnt 0 [] IntMap.empty IntMap.empty
|
||||||
(fid_cnt2,funs_cnt2,funs2,prods0) = mkCncFuns cdefs fid_cnt1 funs_cnt1 funs1 lindefs Map.empty IntMap.empty
|
(fid_cnt2,funs_cnt2,funs2,prods) = mkCncFuns cdefs fid_cnt1 funs_cnt1 funs1 lindefs Map.empty IntMap.empty
|
||||||
prods = [(fid,Set.toList prodSet) | (fid,prodSet) <- IntMap.toList prods0]
|
in (fid_cnt2,prods,lindefs,linrefs,array (0,funs_cnt2-1) funs2)
|
||||||
in (fid_cnt2,prods,IntMap.toList lindefs,IntMap.toList linrefs,reverse funs2)
|
|
||||||
where
|
where
|
||||||
mkCncCats [] fid_cnt funs_cnt funs lindefs linrefs =
|
mkCncCats [] fid_cnt funs_cnt funs lindefs linrefs =
|
||||||
(fid_cnt,funs_cnt,funs,lindefs,linrefs)
|
(fid_cnt,funs_cnt,funs,lindefs,linrefs)
|
||||||
mkCncCats (((m,id),CncCat _ _ _ _ (Just (PMCFG prods0 funs0))):cdefs) fid_cnt funs_cnt funs lindefs linrefs =
|
mkCncCats (((m,id),CncCat _ _ _ _ (Just (PMCFG prods0 funs0))):cdefs) fid_cnt funs_cnt funs lindefs linrefs =
|
||||||
let !funs_cnt' = let (s_funid, e_funid) = bounds funs0
|
let !funs_cnt' = let (s_funid, e_funid) = bounds funs0
|
||||||
@@ -234,16 +210,17 @@ genCncFuns gr am cm ex_seqs ciCmp seqs cdefs fid_cnt cnccat_ranges =
|
|||||||
linrefs' = foldl' (toLinRef (am,id) funs_cnt) linrefs prods0
|
linrefs' = foldl' (toLinRef (am,id) funs_cnt) linrefs prods0
|
||||||
funs' = foldl' (toCncFun funs_cnt (m,mkLinDefId id)) funs (assocs funs0)
|
funs' = foldl' (toCncFun funs_cnt (m,mkLinDefId id)) funs (assocs funs0)
|
||||||
in mkCncCats cdefs fid_cnt funs_cnt' funs' lindefs' linrefs'
|
in mkCncCats cdefs fid_cnt funs_cnt' funs' lindefs' linrefs'
|
||||||
mkCncCats (_ :cdefs) fid_cnt funs_cnt funs lindefs linrefs =
|
mkCncCats (_ :cdefs) fid_cnt funs_cnt funs lindefs linrefs =
|
||||||
mkCncCats cdefs fid_cnt funs_cnt funs lindefs linrefs
|
mkCncCats cdefs fid_cnt funs_cnt funs lindefs linrefs
|
||||||
|
|
||||||
mkCncFuns [] fid_cnt funs_cnt funs lindefs crc prods =
|
mkCncFuns [] fid_cnt funs_cnt funs lindefs crc prods =
|
||||||
(fid_cnt,funs_cnt,funs,prods)
|
(fid_cnt,funs_cnt,funs,prods)
|
||||||
mkCncFuns (((m,id),CncFun _ _ _ (Just (PMCFG prods0 funs0))):cdefs) fid_cnt funs_cnt funs lindefs crc prods =
|
mkCncFuns (((m,id),CncFun _ _ _ (Just (PMCFG prods0 funs0))):cdefs) fid_cnt funs_cnt funs lindefs crc prods =
|
||||||
let ty_C = err error (\x -> x) $ fmap GM.typeForm (Look.lookupFunType gr am id)
|
let ---Ok ty_C = fmap GM.typeForm (Look.lookupFunType gr am id)
|
||||||
|
ty_C = err error (\x -> x) $ fmap GM.typeForm (Look.lookupFunType gr am id)
|
||||||
!funs_cnt' = let (s_funid, e_funid) = bounds funs0
|
!funs_cnt' = let (s_funid, e_funid) = bounds funs0
|
||||||
in funs_cnt+(e_funid-s_funid+1)
|
in funs_cnt+(e_funid-s_funid+1)
|
||||||
!(fid_cnt',crc',prods')
|
!(fid_cnt',crc',prods')
|
||||||
= foldl' (toProd lindefs ty_C funs_cnt)
|
= foldl' (toProd lindefs ty_C funs_cnt)
|
||||||
(fid_cnt,crc,prods) prods0
|
(fid_cnt,crc,prods) prods0
|
||||||
funs' = foldl' (toCncFun funs_cnt (m,id)) funs (assocs funs0)
|
funs' = foldl' (toCncFun funs_cnt (m,id)) funs (assocs funs0)
|
||||||
@@ -251,23 +228,23 @@ genCncFuns gr am cm ex_seqs ciCmp seqs cdefs fid_cnt cnccat_ranges =
|
|||||||
mkCncFuns (_ :cdefs) fid_cnt funs_cnt funs lindefs crc prods =
|
mkCncFuns (_ :cdefs) fid_cnt funs_cnt funs lindefs crc prods =
|
||||||
mkCncFuns cdefs fid_cnt funs_cnt funs lindefs crc prods
|
mkCncFuns cdefs fid_cnt funs_cnt funs lindefs crc prods
|
||||||
|
|
||||||
toProd lindefs (ctxt_C,res_C,_) offs st (A.Production fid0 funid0 args0) =
|
toProd lindefs (ctxt_C,res_C,_) offs st (Production fid0 funid0 args0) =
|
||||||
let !((fid_cnt,crc,prods),args) = mapAccumL mkArg st (zip ctxt_C args0)
|
let !((fid_cnt,crc,prods),args) = mapAccumL mkArg st (zip ctxt_C args0)
|
||||||
set0 = Set.fromList (map (PApply (offs+funid0)) (sequence args))
|
set0 = Set.fromList (map (C.PApply (offs+funid0)) (sequence args))
|
||||||
fid = mkFId res_C fid0
|
fid = mkFId res_C fid0
|
||||||
!prods' = case IntMap.lookup fid prods of
|
!prods' = case IntMap.lookup fid prods of
|
||||||
Just set -> IntMap.insert fid (Set.union set0 set) prods
|
Just set -> IntMap.insert fid (Set.union set0 set) prods
|
||||||
Nothing -> IntMap.insert fid set0 prods
|
Nothing -> IntMap.insert fid set0 prods
|
||||||
in (fid_cnt,crc,prods')
|
in (fid_cnt,crc,prods')
|
||||||
where
|
where
|
||||||
mkArg st@(fid_cnt,crc,prods) ((_,_,ty),fid0s) =
|
mkArg st@(fid_cnt,crc,prods) ((_,_,ty),fid0s ) =
|
||||||
case fid0s of
|
case fid0s of
|
||||||
[fid0] -> (st,map (flip PArg (mkFId arg_C fid0)) ctxt)
|
[fid0] -> (st,map (flip C.PArg (mkFId arg_C fid0)) ctxt)
|
||||||
fid0s -> case Map.lookup fids crc of
|
fid0s -> case Map.lookup fids crc of
|
||||||
Just fid -> (st,map (flip PArg fid) ctxt)
|
Just fid -> (st,map (flip C.PArg fid) ctxt)
|
||||||
Nothing -> let !crc' = Map.insert fids fid_cnt crc
|
Nothing -> let !crc' = Map.insert fids fid_cnt crc
|
||||||
!prods' = IntMap.insert fid_cnt (Set.fromList (map PCoerce fids)) prods
|
!prods' = IntMap.insert fid_cnt (Set.fromList (map C.PCoerce fids)) prods
|
||||||
in ((fid_cnt+1,crc',prods'),map (flip PArg fid_cnt) ctxt)
|
in ((fid_cnt+1,crc',prods'),map (flip C.PArg fid_cnt) ctxt)
|
||||||
where
|
where
|
||||||
(hargs_C,arg_C) = GM.catSkeleton ty
|
(hargs_C,arg_C) = GM.catSkeleton ty
|
||||||
ctxt = mapM (mkCtxt lindefs) hargs_C
|
ctxt = mapM (mkCtxt lindefs) hargs_C
|
||||||
@@ -275,14 +252,14 @@ genCncFuns gr am cm ex_seqs ciCmp seqs cdefs fid_cnt cnccat_ranges =
|
|||||||
|
|
||||||
mkLinDefId id = prefixIdent "lindef " id
|
mkLinDefId id = prefixIdent "lindef " id
|
||||||
|
|
||||||
toLinDef res offs lindefs (A.Production fid0 funid0 args) =
|
toLinDef res offs lindefs (Production fid0 funid0 args) =
|
||||||
if args == [[fidVar]]
|
if args == [[fidVar]]
|
||||||
then IntMap.insertWith (++) fid [offs+funid0] lindefs
|
then IntMap.insertWith (++) fid [offs+funid0] lindefs
|
||||||
else lindefs
|
else lindefs
|
||||||
where
|
where
|
||||||
fid = mkFId res fid0
|
fid = mkFId res fid0
|
||||||
|
|
||||||
toLinRef res offs linrefs (A.Production fid0 funid0 [fargs]) =
|
toLinRef res offs linrefs (Production fid0 funid0 [fargs]) =
|
||||||
if fid0 == fidVar
|
if fid0 == fidVar
|
||||||
then foldr (\fid -> IntMap.insertWith (++) fid [offs+funid0]) linrefs fids
|
then foldr (\fid -> IntMap.insertWith (++) fid [offs+funid0]) linrefs fids
|
||||||
else linrefs
|
else linrefs
|
||||||
@@ -290,20 +267,20 @@ genCncFuns gr am cm ex_seqs ciCmp seqs cdefs fid_cnt cnccat_ranges =
|
|||||||
fids = map (mkFId res) fargs
|
fids = map (mkFId res) fargs
|
||||||
|
|
||||||
mkFId (_,cat) fid0 =
|
mkFId (_,cat) fid0 =
|
||||||
case Map.lookup (i2i cat) cnccat_ranges of
|
case Map.lookup (i2i cat) cnccats of
|
||||||
Just (s,e) -> s+fid0
|
Just (C.CncCat s e _) -> s+fid0
|
||||||
Nothing -> error ("GrammarToPGF.mkFId: missing category "++showIdent cat)
|
Nothing -> error ("GrammarToPGF.mkFId: missing category "++showIdent cat)
|
||||||
|
|
||||||
mkCtxt lindefs (_,cat) =
|
mkCtxt lindefs (_,cat) =
|
||||||
case Map.lookup (i2i cat) cnccat_ranges of
|
case Map.lookup (i2i cat) cnccats of
|
||||||
Just (s,e) -> [(fid,fid) | fid <- [s..e], Just _ <- [IntMap.lookup fid lindefs]]
|
Just (C.CncCat s e _) -> [(C.fidVar,fid) | fid <- [s..e], Just _ <- [IntMap.lookup fid lindefs]]
|
||||||
Nothing -> error "GrammarToPGF.mkCtxt failed"
|
Nothing -> error "GrammarToPGF.mkCtxt failed"
|
||||||
|
|
||||||
toCncFun offs (m,id) funs (funid0,lins0) =
|
toCncFun offs (m,id) funs (funid0,lins0) =
|
||||||
let mseqs = case lookupModule gr m of
|
let mseqs = case lookupModule gr m of
|
||||||
Ok (ModInfo{mseqs=Just mseqs}) -> mseqs
|
Ok (ModInfo{mseqs=Just mseqs}) -> mseqs
|
||||||
_ -> ex_seqs
|
_ -> ex_seqs
|
||||||
in (i2i id, map (newIndex mseqs) (elems lins0)):funs
|
in (offs+funid0,C.CncFun (i2i id) (amap (newIndex mseqs) lins0)):funs
|
||||||
where
|
where
|
||||||
newIndex mseqs i = binSearch (mseqs ! i) seqs (bounds seqs)
|
newIndex mseqs i = binSearch (mseqs ! i) seqs (bounds seqs)
|
||||||
|
|
||||||
@@ -316,9 +293,8 @@ genCncFuns gr am cm ex_seqs ciCmp seqs cdefs fid_cnt cnccat_ranges =
|
|||||||
where
|
where
|
||||||
k = (i+j) `div` 2
|
k = (i+j) `div` 2
|
||||||
|
|
||||||
|
|
||||||
genPrintNames cdefs =
|
genPrintNames cdefs =
|
||||||
[(i2i id, name) | ((m,id),info) <- cdefs, name <- prn info]
|
Map.fromAscList [(i2i id, name) | ((m,id),info) <- cdefs, name <- prn info]
|
||||||
where
|
where
|
||||||
prn (CncFun _ _ (Just (L _ tr)) _) = [flatten tr]
|
prn (CncFun _ _ (Just (L _ tr)) _) = [flatten tr]
|
||||||
prn (CncCat _ _ _ (Just (L _ tr)) _) = [flatten tr]
|
prn (CncCat _ _ _ (Just (L _ tr)) _) = [flatten tr]
|
||||||
@@ -330,118 +306,3 @@ genPrintNames cdefs =
|
|||||||
|
|
||||||
mkArray lst = listArray (0,length lst-1) lst
|
mkArray lst = listArray (0,length lst-1) lst
|
||||||
mkMapArray map = array (0,Map.size map-1) [(v,k) | (k,v) <- Map.toList map]
|
mkMapArray map = array (0,Map.size map-1) [(v,k) | (k,v) <- Map.toList map]
|
||||||
mkSetArray set = listArray (0,Set.size set-1) (Set.toList set)
|
|
||||||
|
|
||||||
-- The following is a version of Data.List.sortBy which together
|
|
||||||
-- with the sorting also eliminates duplicate values
|
|
||||||
sortNubBy cmp = mergeAll . sequences
|
|
||||||
where
|
|
||||||
sequences (a:b:xs) =
|
|
||||||
case cmp a b of
|
|
||||||
GT -> descending b [a] xs
|
|
||||||
EQ -> sequences (b:xs)
|
|
||||||
LT -> ascending b (a:) xs
|
|
||||||
sequences xs = [xs]
|
|
||||||
|
|
||||||
descending a as [] = [a:as]
|
|
||||||
descending a as (b:bs) =
|
|
||||||
case cmp a b of
|
|
||||||
GT -> descending b (a:as) bs
|
|
||||||
EQ -> descending a as bs
|
|
||||||
LT -> (a:as) : sequences (b:bs)
|
|
||||||
|
|
||||||
ascending a as [] = let !x = as [a]
|
|
||||||
in [x]
|
|
||||||
ascending a as (b:bs) =
|
|
||||||
case cmp a b of
|
|
||||||
GT -> let !x = as [a]
|
|
||||||
in x : sequences (b:bs)
|
|
||||||
EQ -> ascending a as bs
|
|
||||||
LT -> ascending b (\ys -> as (a:ys)) bs
|
|
||||||
|
|
||||||
mergeAll [x] = x
|
|
||||||
mergeAll xs = mergeAll (mergePairs xs)
|
|
||||||
|
|
||||||
mergePairs (a:b:xs) = let !x = merge a b
|
|
||||||
in x : mergePairs xs
|
|
||||||
mergePairs xs = xs
|
|
||||||
|
|
||||||
merge as@(a:as') bs@(b:bs') =
|
|
||||||
case cmp a b of
|
|
||||||
GT -> b:merge as bs'
|
|
||||||
EQ -> a:merge as' bs'
|
|
||||||
LT -> a:merge as' bs
|
|
||||||
merge [] bs = bs
|
|
||||||
merge as [] = as
|
|
||||||
|
|
||||||
-- The following function does case-insensitive comparison of sequences.
|
|
||||||
-- This is used to allow case-insensitive parsing, while
|
|
||||||
-- the linearizer still has access to the original cases.
|
|
||||||
|
|
||||||
compareCaseInsensitive [] [] = EQ
|
|
||||||
compareCaseInsensitive [] _ = LT
|
|
||||||
compareCaseInsensitive _ [] = GT
|
|
||||||
compareCaseInsensitive (x:xs) (y:ys) =
|
|
||||||
case compareSym x y of
|
|
||||||
EQ -> compareCaseInsensitive xs ys
|
|
||||||
x -> x
|
|
||||||
where
|
|
||||||
compareSym s1 s2 =
|
|
||||||
case s1 of
|
|
||||||
SymCat d1 r1
|
|
||||||
-> case s2 of
|
|
||||||
SymCat d2 r2
|
|
||||||
-> case compare d1 d2 of
|
|
||||||
EQ -> r1 `compare` r2
|
|
||||||
x -> x
|
|
||||||
_ -> LT
|
|
||||||
SymLit d1 r1
|
|
||||||
-> case s2 of
|
|
||||||
SymCat {} -> GT
|
|
||||||
SymLit d2 r2
|
|
||||||
-> case compare d1 d2 of
|
|
||||||
EQ -> r1 `compare` r2
|
|
||||||
x -> x
|
|
||||||
_ -> LT
|
|
||||||
SymVar d1 r1
|
|
||||||
-> if tagToEnum# (getTag s2 ># 2#)
|
|
||||||
then LT
|
|
||||||
else case s2 of
|
|
||||||
SymVar d2 r2
|
|
||||||
-> case compare d1 d2 of
|
|
||||||
EQ -> r1 `compare` r2
|
|
||||||
x -> x
|
|
||||||
_ -> GT
|
|
||||||
SymKS t1
|
|
||||||
-> if tagToEnum# (getTag s2 ># 3#)
|
|
||||||
then LT
|
|
||||||
else case s2 of
|
|
||||||
SymKS t2 -> t1 `compareToken` t2
|
|
||||||
_ -> GT
|
|
||||||
SymKP a1 b1
|
|
||||||
-> if tagToEnum# (getTag s2 ># 4#)
|
|
||||||
then LT
|
|
||||||
else case s2 of
|
|
||||||
SymKP a2 b2
|
|
||||||
-> case compare a1 a2 of
|
|
||||||
EQ -> b1 `compare` b2
|
|
||||||
x -> x
|
|
||||||
_ -> GT
|
|
||||||
_ -> let t1 = getTag s1
|
|
||||||
t2 = getTag s2
|
|
||||||
in if tagToEnum# (t1 <# t2)
|
|
||||||
then LT
|
|
||||||
else if tagToEnum# (t1 ==# t2)
|
|
||||||
then EQ
|
|
||||||
else GT
|
|
||||||
|
|
||||||
compareToken [] [] = EQ
|
|
||||||
compareToken [] _ = LT
|
|
||||||
compareToken _ [] = GT
|
|
||||||
compareToken (x:xs) (y:ys)
|
|
||||||
| x == y = compareToken xs ys
|
|
||||||
| otherwise = case compare (toLower x) (toLower y) of
|
|
||||||
EQ -> case compareToken xs ys of
|
|
||||||
EQ -> compare x y
|
|
||||||
x -> x
|
|
||||||
x -> x
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
-- Stability : (stable)
|
-- Stability : (stable)
|
||||||
-- Portability : (portable)
|
-- Portability : (portable)
|
||||||
--
|
--
|
||||||
-- > CVS $Date: 2005/09/16 13:56:13 $
|
-- > CVS $Date: 2005/09/16 13:56:13 $
|
||||||
-- > CVS $Author: aarne $
|
-- > CVS $Author: aarne $
|
||||||
-- > CVS $Revision: 1.18 $
|
-- > CVS $Revision: 1.18 $
|
||||||
--
|
--
|
||||||
@@ -21,7 +21,7 @@ import GF.Grammar.Printer
|
|||||||
import GF.Grammar.Macros
|
import GF.Grammar.Macros
|
||||||
import GF.Grammar.Lookup
|
import GF.Grammar.Lookup
|
||||||
import GF.Grammar.Predef
|
import GF.Grammar.Predef
|
||||||
import GF.Compile.Compute.Concrete(GlobalEnv,normalForm,resourceValues)
|
import GF.Compile.Compute.ConcreteNew(GlobalEnv,normalForm,resourceValues)
|
||||||
import GF.Data.Operations
|
import GF.Data.Operations
|
||||||
import GF.Infra.Option
|
import GF.Infra.Option
|
||||||
|
|
||||||
@@ -90,7 +90,7 @@ evalInfo opts resenv sgr m c info = do
|
|||||||
let ppr' = fmap (evalPrintname resenv c) ppr
|
let ppr' = fmap (evalPrintname resenv c) ppr
|
||||||
return $ CncFun mt pde' ppr' mpmcfg -- only cat in type actually needed
|
return $ CncFun mt pde' ppr' mpmcfg -- only cat in type actually needed
|
||||||
{-
|
{-
|
||||||
ResOper pty pde
|
ResOper pty pde
|
||||||
| not new && OptExpand `Set.member` optim -> do
|
| not new && OptExpand `Set.member` optim -> do
|
||||||
pde' <- case pde of
|
pde' <- case pde of
|
||||||
Just (L loc de) -> do de <- computeConcrete gr de
|
Just (L loc de) -> do de <- computeConcrete gr de
|
||||||
@@ -171,13 +171,13 @@ mkLinDefault gr typ = liftM (Abs Explicit varStr) $ mkDefField typ
|
|||||||
_ -> Bad (render ("linearization type field cannot be" <+> typ))
|
_ -> Bad (render ("linearization type field cannot be" <+> typ))
|
||||||
|
|
||||||
mkLinReference :: SourceGrammar -> Type -> Err Term
|
mkLinReference :: SourceGrammar -> Type -> Err Term
|
||||||
mkLinReference gr typ =
|
mkLinReference gr typ =
|
||||||
liftM (Abs Explicit varStr) $
|
liftM (Abs Explicit varStr) $
|
||||||
case mkDefField typ (Vr varStr) of
|
case mkDefField typ (Vr varStr) of
|
||||||
Bad "no string" -> return Empty
|
Bad "no string" -> return Empty
|
||||||
x -> x
|
x -> x
|
||||||
where
|
where
|
||||||
mkDefField ty trm =
|
mkDefField ty trm =
|
||||||
case ty of
|
case ty of
|
||||||
Table pty ty -> do ps <- allParamValues gr pty
|
Table pty ty -> do ps <- allParamValues gr pty
|
||||||
case ps of
|
case ps of
|
||||||
@@ -203,7 +203,7 @@ factor param c i t =
|
|||||||
T (TComp ty) cs -> factors ty [(p, factor param c (i+1) v) | (p, v) <- cs]
|
T (TComp ty) cs -> factors ty [(p, factor param c (i+1) v) | (p, v) <- cs]
|
||||||
_ -> composSafeOp (factor param c i) t
|
_ -> composSafeOp (factor param c i) t
|
||||||
where
|
where
|
||||||
factors ty pvs0
|
factors ty pvs0
|
||||||
| not param = V ty (map snd pvs0)
|
| not param = V ty (map snd pvs0)
|
||||||
factors ty [] = V ty []
|
factors ty [] = V ty []
|
||||||
factors ty pvs0@[(p,v)] = V ty [v]
|
factors ty pvs0@[(p,v)] = V ty [v]
|
||||||
@@ -224,7 +224,7 @@ factor param c i t =
|
|||||||
replace :: Term -> Term -> Term -> Term
|
replace :: Term -> Term -> Term -> Term
|
||||||
replace old new trm =
|
replace old new trm =
|
||||||
case trm of
|
case trm of
|
||||||
-- these are the important cases, since they can correspond to patterns
|
-- these are the important cases, since they can correspond to patterns
|
||||||
QC _ | trm == old -> new
|
QC _ | trm == old -> new
|
||||||
App _ _ | trm == old -> new
|
App _ _ | trm == old -> new
|
||||||
R _ | trm == old -> new
|
R _ | trm == old -> new
|
||||||
|
|||||||
@@ -1,189 +0,0 @@
|
|||||||
{-# LANGUAGE BangPatterns #-}
|
|
||||||
module GF.Compile.OptimizePGF(optimizePGF) where
|
|
||||||
|
|
||||||
import PGF2(Cat,Fun)
|
|
||||||
import PGF2.Internal
|
|
||||||
import Data.Array.ST
|
|
||||||
import Data.Array.Unboxed
|
|
||||||
import qualified Data.Map as Map
|
|
||||||
import qualified Data.Set as Set
|
|
||||||
import qualified Data.IntSet as IntSet
|
|
||||||
import qualified Data.IntMap as IntMap
|
|
||||||
import qualified Data.List as List
|
|
||||||
import Control.Monad.ST
|
|
||||||
|
|
||||||
type ConcrData = ([(FId,[FunId])], -- ^ Lindefs
|
|
||||||
[(FId,[FunId])], -- ^ Linrefs
|
|
||||||
[(FId,[Production])], -- ^ Productions
|
|
||||||
[(Fun,[SeqId])], -- ^ Concrete functions (must be sorted by Fun)
|
|
||||||
[[Symbol]], -- ^ Sequences (must be sorted)
|
|
||||||
[(Cat,FId,FId,[String])]) -- ^ Concrete categories
|
|
||||||
|
|
||||||
optimizePGF :: Cat -> ConcrData -> ConcrData
|
|
||||||
optimizePGF startCat = topDownFilter startCat . bottomUpFilter
|
|
||||||
|
|
||||||
catString = "String"
|
|
||||||
catInt = "Int"
|
|
||||||
catFloat = "Float"
|
|
||||||
catVar = "__gfVar"
|
|
||||||
|
|
||||||
topDownFilter :: Cat -> ConcrData -> ConcrData
|
|
||||||
topDownFilter startCat (lindefs,linrefs,prods,cncfuns,sequences,cnccats) =
|
|
||||||
let env0 = (Map.empty,Map.empty)
|
|
||||||
(env1,lindefs') = List.mapAccumL (\env (fid,funids) -> let (env',funids') = List.mapAccumL (optimizeFun fid [PArg [] fidVar]) env funids in (env',(fid,funids')))
|
|
||||||
env0
|
|
||||||
lindefs
|
|
||||||
(env2,linrefs') = List.mapAccumL (\env (fid,funids) -> let (env',funids') = List.mapAccumL (optimizeFun fidVar [PArg [] fid]) env funids in (env',(fid,funids')))
|
|
||||||
env1
|
|
||||||
linrefs
|
|
||||||
(env3,prods') = List.mapAccumL (\env (fid,set) -> let (env',set') = List.mapAccumL (optimizeProd fid) env set in (env',(fid,set')))
|
|
||||||
env2
|
|
||||||
prods
|
|
||||||
cnccats' = map filterCatLabels cnccats
|
|
||||||
(sequences',cncfuns') = env3
|
|
||||||
in (lindefs',linrefs',prods',mkSetArray cncfuns',mkSetArray sequences',cnccats')
|
|
||||||
where
|
|
||||||
cncfuns_array = listArray (0,length cncfuns-1) cncfuns :: Array FunId (Fun, [SeqId])
|
|
||||||
sequences_array = listArray (0,length sequences-1) sequences :: Array SeqId [Symbol]
|
|
||||||
prods_map = IntMap.fromList prods
|
|
||||||
fid2catMap = IntMap.fromList ((fidVar,catVar) : [(fid,cat) | (cat,start,end,lbls) <- cnccats,
|
|
||||||
fid <- [start..end]])
|
|
||||||
|
|
||||||
fid2cat fid =
|
|
||||||
case IntMap.lookup fid fid2catMap of
|
|
||||||
Just cat -> cat
|
|
||||||
Nothing -> case [fid | Just set <- [IntMap.lookup fid prods_map], PCoerce fid <- set] of
|
|
||||||
(fid:_) -> fid2cat fid
|
|
||||||
_ -> error "unknown forest id"
|
|
||||||
|
|
||||||
starts =
|
|
||||||
[(startCat,lbl) | (cat,_,_,lbls) <- cnccats, cat==startCat, lbl <- [0..length lbls-1]]
|
|
||||||
|
|
||||||
allRelations =
|
|
||||||
Map.unionsWith Set.union
|
|
||||||
[rel fid prod | (fid,set) <- prods, prod <- set]
|
|
||||||
where
|
|
||||||
rel fid (PApply funid args) = Map.fromList [((fid2cat fid,lbl),deps args seqid) | (lbl,seqid) <- zip [0..] lin]
|
|
||||||
where
|
|
||||||
(_,lin) = cncfuns_array ! funid
|
|
||||||
rel fid _ = Map.empty
|
|
||||||
|
|
||||||
deps args seqid = Set.fromList [let PArg _ fid = args !! r in (fid2cat fid,d) | SymCat r d <- seq]
|
|
||||||
where
|
|
||||||
seq = sequences_array ! seqid
|
|
||||||
|
|
||||||
-- here we create a mapping from a category to an array of indices.
|
|
||||||
-- An element of the array is equal to -1 if the corresponding index
|
|
||||||
-- is not going to be used in the optimized grammar, or the new index
|
|
||||||
-- if it will be used
|
|
||||||
closure :: Map.Map Cat [Int]
|
|
||||||
closure = runST $ do
|
|
||||||
set <- initSet
|
|
||||||
addLitCat catString set
|
|
||||||
addLitCat catInt set
|
|
||||||
addLitCat catFloat set
|
|
||||||
addLitCat catVar set
|
|
||||||
closureSet set starts
|
|
||||||
doneSet set
|
|
||||||
where
|
|
||||||
initSet :: ST s (Map.Map Cat (STUArray s Int Int))
|
|
||||||
initSet =
|
|
||||||
fmap Map.fromList $ sequence
|
|
||||||
[fmap ((,) cat) (newArray (0,length lbls-1) (-1))
|
|
||||||
| (cat,_,_,lbls) <- cnccats]
|
|
||||||
|
|
||||||
addLitCat cat set =
|
|
||||||
case Map.lookup cat set of
|
|
||||||
Just indices -> writeArray indices 0 0
|
|
||||||
Nothing -> return ()
|
|
||||||
|
|
||||||
closureSet set [] = return ()
|
|
||||||
closureSet set (x@(cat,index):xs) =
|
|
||||||
case Map.lookup cat set of
|
|
||||||
Just indices -> do v <- readArray indices index
|
|
||||||
writeArray indices index 0
|
|
||||||
if v < 0
|
|
||||||
then case Map.lookup x allRelations of
|
|
||||||
Just ys -> closureSet set (Set.toList ys++xs)
|
|
||||||
Nothing -> closureSet set xs
|
|
||||||
else closureSet set xs
|
|
||||||
Nothing -> error "unknown cat"
|
|
||||||
|
|
||||||
doneSet :: Map.Map Cat (STUArray s Int Int) -> ST s (Map.Map Cat [Int])
|
|
||||||
doneSet set =
|
|
||||||
fmap Map.fromAscList $ mapM done (Map.toAscList set)
|
|
||||||
where
|
|
||||||
done (cat,indices) = do
|
|
||||||
indices <- fmap (reindex 0) (getElems indices)
|
|
||||||
return (cat,indices)
|
|
||||||
|
|
||||||
reindex k [] = []
|
|
||||||
reindex k (v:vs)
|
|
||||||
| v < 0 = v : reindex k vs
|
|
||||||
| otherwise = k : reindex (k+1) vs
|
|
||||||
|
|
||||||
optimizeProd res env (PApply funid args) =
|
|
||||||
let (env',funid') = optimizeFun res args env funid
|
|
||||||
in (env', PApply funid' args)
|
|
||||||
optimizeProd res env prod = (env,prod)
|
|
||||||
|
|
||||||
optimizeFun res args (seqs,funs) funid =
|
|
||||||
let (seqs',lin') = List.mapAccumL addUnique seqs [map updateSymbol (sequences_array ! seqid) |
|
|
||||||
(idx,seqid) <- zip (indicesOf res) lin, idx >= 0]
|
|
||||||
(funs',funid') = addUnique funs (fun, lin')
|
|
||||||
in ((seqs',funs'), funid')
|
|
||||||
where
|
|
||||||
(fun,lin) = cncfuns_array ! funid
|
|
||||||
|
|
||||||
indicesOf fid
|
|
||||||
| fid < 0 = [0]
|
|
||||||
| otherwise =
|
|
||||||
case Map.lookup (fid2cat fid) closure of
|
|
||||||
Just indices -> indices
|
|
||||||
Nothing -> error "unknown category"
|
|
||||||
|
|
||||||
addUnique seqs seq =
|
|
||||||
case Map.lookup seq seqs of
|
|
||||||
Just seqid -> (seqs,seqid)
|
|
||||||
Nothing -> let seqid = Map.size seqs
|
|
||||||
in (Map.insert seq seqid seqs, seqid)
|
|
||||||
|
|
||||||
updateSymbol (SymCat r d) = let PArg _ fid = args !! r in SymCat r (indicesOf fid !! d)
|
|
||||||
updateSymbol s = s
|
|
||||||
|
|
||||||
filterCatLabels (cat,start,end,lbls) =
|
|
||||||
case Map.lookup cat closure of
|
|
||||||
Just indices -> let lbls' = [lbl | (idx,lbl) <- zip indices lbls, idx >= 0]
|
|
||||||
in (cat,start,end,lbls')
|
|
||||||
Nothing -> error ("unknown category")
|
|
||||||
|
|
||||||
mkSetArray map = sortSnd (Map.toList map)
|
|
||||||
where
|
|
||||||
sortSnd = List.map fst . List.sortBy (\(_,i) (_,j) -> compare i j)
|
|
||||||
|
|
||||||
|
|
||||||
bottomUpFilter :: ConcrData -> ConcrData
|
|
||||||
bottomUpFilter (lindefs,linrefs,prods,cncfuns,sequences,cnccats) =
|
|
||||||
(lindefs,linrefs,filterProductions IntMap.empty IntSet.empty prods,cncfuns,sequences,cnccats)
|
|
||||||
|
|
||||||
filterProductions prods0 hoc0 prods
|
|
||||||
| prods0 == prods1 = IntMap.toList prods0
|
|
||||||
| otherwise = filterProductions prods1 hoc1 prods
|
|
||||||
where
|
|
||||||
(prods1,hoc1) = foldl foldProdSet (IntMap.empty,IntSet.empty) prods
|
|
||||||
|
|
||||||
foldProdSet (!prods,!hoc) (fid,set)
|
|
||||||
| null set1 = (prods,hoc)
|
|
||||||
| otherwise = (IntMap.insert fid set1 prods,hoc1)
|
|
||||||
where
|
|
||||||
set1 = filter filterRule set
|
|
||||||
hoc1 = foldl accumHOC hoc set1
|
|
||||||
|
|
||||||
filterRule (PApply funid args) = all (\(PArg _ fid) -> isLive fid) args
|
|
||||||
filterRule (PCoerce fid) = isLive fid
|
|
||||||
filterRule _ = True
|
|
||||||
|
|
||||||
isLive fid = isPredefFId fid || IntMap.member fid prods0 || IntSet.member fid hoc0
|
|
||||||
|
|
||||||
accumHOC hoc (PApply funid args) = List.foldl' (\hoc (PArg hypos _) -> List.foldl' (\hoc fid -> IntSet.insert fid hoc) hoc (map snd hypos)) hoc args
|
|
||||||
accumHOC hoc _ = hoc
|
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
-- Stability : (stable)
|
-- Stability : (stable)
|
||||||
-- Portability : (portable)
|
-- Portability : (portable)
|
||||||
--
|
--
|
||||||
-- > CVS $Date: 2005/06/17 12:39:07 $
|
-- > CVS $Date: 2005/06/17 12:39:07 $
|
||||||
-- > CVS $Author: bringert $
|
-- > CVS $Author: bringert $
|
||||||
-- > CVS $Revision: 1.8 $
|
-- > CVS $Revision: 1.8 $
|
||||||
--
|
--
|
||||||
@@ -16,14 +16,13 @@
|
|||||||
|
|
||||||
module GF.Compile.PGFtoHaskell (grammar2haskell) where
|
module GF.Compile.PGFtoHaskell (grammar2haskell) where
|
||||||
|
|
||||||
import PGF2
|
import PGF(showCId)
|
||||||
import PGF2.Internal
|
import PGF.Internal
|
||||||
|
|
||||||
import GF.Data.Operations
|
import GF.Data.Operations
|
||||||
import GF.Infra.Option
|
import GF.Infra.Option
|
||||||
|
|
||||||
import Data.List(isPrefixOf,find,intercalate,intersperse,groupBy,sortBy)
|
import Data.List --(isPrefixOf, find, intersperse)
|
||||||
import Data.Maybe(mapMaybe)
|
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
|
|
||||||
type Prefix = String -> String
|
type Prefix = String -> String
|
||||||
@@ -35,12 +34,11 @@ grammar2haskell :: Options
|
|||||||
-> PGF
|
-> PGF
|
||||||
-> String
|
-> String
|
||||||
grammar2haskell opts name gr = foldr (++++) [] $
|
grammar2haskell opts name gr = foldr (++++) [] $
|
||||||
pragmas ++ haskPreamble gadt name derivingClause (extraImports ++ pgfImports) ++
|
pragmas ++ haskPreamble gadt name derivingClause extraImports ++
|
||||||
[types, gfinstances gId lexical gr'] ++ compos
|
[types, gfinstances gId lexical gr'] ++ compos
|
||||||
where gr' = hSkeleton gr
|
where gr' = hSkeleton gr
|
||||||
gadt = haskellOption opts HaskellGADT
|
gadt = haskellOption opts HaskellGADT
|
||||||
dataExt = haskellOption opts HaskellData
|
dataExt = haskellOption opts HaskellData
|
||||||
pgf2 = haskellOption opts HaskellPGF2
|
|
||||||
lexical cat = haskellOption opts HaskellLexical && isLexicalCat opts cat
|
lexical cat = haskellOption opts HaskellLexical && isLexicalCat opts cat
|
||||||
gId | haskellOption opts HaskellNoPrefix = rmForbiddenChars
|
gId | haskellOption opts HaskellNoPrefix = rmForbiddenChars
|
||||||
| otherwise = ("G"++) . rmForbiddenChars
|
| otherwise = ("G"++) . rmForbiddenChars
|
||||||
@@ -52,23 +50,21 @@ grammar2haskell opts name gr = foldr (++++) [] $
|
|||||||
derivingClause
|
derivingClause
|
||||||
| dataExt = "deriving (Show,Data)"
|
| dataExt = "deriving (Show,Data)"
|
||||||
| otherwise = "deriving Show"
|
| otherwise = "deriving Show"
|
||||||
extraImports | gadt = ["import Control.Monad.Identity", "import Data.Monoid"]
|
extraImports | gadt = ["import Control.Monad.Identity",
|
||||||
|
"import Data.Monoid"]
|
||||||
| dataExt = ["import Data.Data"]
|
| dataExt = ["import Data.Data"]
|
||||||
| otherwise = []
|
| otherwise = []
|
||||||
pgfImports | pgf2 = ["import PGF2 hiding (Tree)", "", "showCId :: CId -> String", "showCId = id"]
|
|
||||||
| otherwise = ["import PGF hiding (Tree)"]
|
|
||||||
types | gadt = datatypesGADT gId lexical gr'
|
types | gadt = datatypesGADT gId lexical gr'
|
||||||
| otherwise = datatypes gId derivingClause lexical gr'
|
| otherwise = datatypes gId derivingClause lexical gr'
|
||||||
compos | gadt = prCompos gId lexical gr' ++ composClass
|
compos | gadt = prCompos gId lexical gr' ++ composClass
|
||||||
| otherwise = []
|
| otherwise = []
|
||||||
|
|
||||||
haskPreamble :: Bool -> String -> String -> [String] -> [String]
|
haskPreamble gadt name derivingClause extraImports =
|
||||||
haskPreamble gadt name derivingClause imports =
|
|
||||||
[
|
[
|
||||||
"module " ++ name ++ " where",
|
"module " ++ name ++ " where",
|
||||||
""
|
""
|
||||||
] ++ imports ++ [
|
] ++ extraImports ++ [
|
||||||
"",
|
"import PGF hiding (Tree)",
|
||||||
"----------------------------------------------------",
|
"----------------------------------------------------",
|
||||||
"-- automatic translation from GF to Haskell",
|
"-- automatic translation from GF to Haskell",
|
||||||
"----------------------------------------------------",
|
"----------------------------------------------------",
|
||||||
@@ -89,11 +85,10 @@ haskPreamble gadt name derivingClause imports =
|
|||||||
""
|
""
|
||||||
]
|
]
|
||||||
|
|
||||||
predefInst :: Bool -> String -> String -> String -> String -> String -> String
|
|
||||||
predefInst gadt derivingClause gtyp typ destr consr =
|
predefInst gadt derivingClause gtyp typ destr consr =
|
||||||
(if gadt
|
(if gadt
|
||||||
then []
|
then []
|
||||||
else "newtype" +++ gtyp +++ "=" +++ gtyp +++ typ +++ derivingClause ++ "\n\n"
|
else ("newtype" +++ gtyp +++ "=" +++ gtyp +++ typ +++ derivingClause ++ "\n\n")
|
||||||
)
|
)
|
||||||
++
|
++
|
||||||
"instance Gf" +++ gtyp +++ "where" ++++
|
"instance Gf" +++ gtyp +++ "where" ++++
|
||||||
@@ -108,10 +103,10 @@ type OIdent = String
|
|||||||
type HSkeleton = [(OIdent, [(OIdent, [OIdent])])]
|
type HSkeleton = [(OIdent, [(OIdent, [OIdent])])]
|
||||||
|
|
||||||
datatypes :: Prefix -> DerivingClause -> (OIdent -> Bool) -> (String,HSkeleton) -> String
|
datatypes :: Prefix -> DerivingClause -> (OIdent -> Bool) -> (String,HSkeleton) -> String
|
||||||
datatypes gId derivingClause lexical = foldr (+++++) "" . filter (/="") . map (hDatatype gId derivingClause lexical) . snd
|
datatypes gId derivingClause lexical = (foldr (+++++) "") . (filter (/="")) . (map (hDatatype gId derivingClause lexical)) . snd
|
||||||
|
|
||||||
gfinstances :: Prefix -> (OIdent -> Bool) -> (String,HSkeleton) -> String
|
gfinstances :: Prefix -> (OIdent -> Bool) -> (String,HSkeleton) -> String
|
||||||
gfinstances gId lexical (m,g) = foldr (+++++) "" $ filter (/="") $ map (gfInstance gId lexical m) g
|
gfinstances gId lexical (m,g) = (foldr (+++++) "") $ (filter (/="")) $ (map (gfInstance gId lexical m)) g
|
||||||
|
|
||||||
|
|
||||||
hDatatype :: Prefix -> DerivingClause -> (OIdent -> Bool) -> (OIdent, [(OIdent, [OIdent])]) -> String
|
hDatatype :: Prefix -> DerivingClause -> (OIdent -> Bool) -> (OIdent, [(OIdent, [OIdent])]) -> String
|
||||||
@@ -136,17 +131,16 @@ nonLexicalRules True rules = [r | r@(f,t) <- rules, not (null t)]
|
|||||||
lexicalConstructor :: OIdent -> String
|
lexicalConstructor :: OIdent -> String
|
||||||
lexicalConstructor cat = "Lex" ++ cat
|
lexicalConstructor cat = "Lex" ++ cat
|
||||||
|
|
||||||
predefTypeSkel :: HSkeleton
|
|
||||||
predefTypeSkel = [(c,[]) | c <- ["String", "Int", "Float"]]
|
predefTypeSkel = [(c,[]) | c <- ["String", "Int", "Float"]]
|
||||||
|
|
||||||
-- GADT version of data types
|
-- GADT version of data types
|
||||||
datatypesGADT :: Prefix -> (OIdent -> Bool) -> (String,HSkeleton) -> String
|
datatypesGADT :: Prefix -> (OIdent -> Bool) -> (String,HSkeleton) -> String
|
||||||
datatypesGADT gId lexical (_,skel) = unlines $
|
datatypesGADT gId lexical (_,skel) = unlines $
|
||||||
concatMap (hCatTypeGADT gId) (skel ++ predefTypeSkel) ++
|
concatMap (hCatTypeGADT gId) (skel ++ predefTypeSkel) ++
|
||||||
[
|
[
|
||||||
"",
|
"",
|
||||||
"data Tree :: * -> * where"
|
"data Tree :: * -> * where"
|
||||||
] ++
|
] ++
|
||||||
concatMap (map (" "++) . hDatatypeGADT gId lexical) skel ++
|
concatMap (map (" "++) . hDatatypeGADT gId lexical) skel ++
|
||||||
[
|
[
|
||||||
" GString :: String -> Tree GString_",
|
" GString :: String -> Tree GString_",
|
||||||
@@ -170,23 +164,23 @@ hCatTypeGADT gId (cat,rules)
|
|||||||
"data"+++gId cat++"_"]
|
"data"+++gId cat++"_"]
|
||||||
|
|
||||||
hDatatypeGADT :: Prefix -> (OIdent -> Bool) -> (OIdent, [(OIdent, [OIdent])]) -> [String]
|
hDatatypeGADT :: Prefix -> (OIdent -> Bool) -> (OIdent, [(OIdent, [OIdent])]) -> [String]
|
||||||
hDatatypeGADT gId lexical (cat, rules)
|
hDatatypeGADT gId lexical (cat, rules)
|
||||||
| isListCat (cat,rules) = [gId cat+++"::"+++"["++gId (elemCat cat)++"]" +++ "->" +++ t]
|
| isListCat (cat,rules) = [gId cat+++"::"+++"["++gId (elemCat cat)++"]" +++ "->" +++ t]
|
||||||
| otherwise =
|
| otherwise =
|
||||||
[ gId f +++ "::" +++ concatMap (\a -> gId a +++ "-> ") args ++ t
|
[ gId f +++ "::" +++ concatMap (\a -> gId a +++ "-> ") args ++ t
|
||||||
| (f,args) <- nonLexicalRules (lexical cat) rules ]
|
| (f,args) <- nonLexicalRules (lexical cat) rules ]
|
||||||
++ if lexical cat then [lexicalConstructor cat +++ ":: String ->"+++ t] else []
|
++ if lexical cat then [lexicalConstructor cat +++ ":: String ->"+++ t] else []
|
||||||
where t = "Tree" +++ gId cat ++ "_"
|
where t = "Tree" +++ gId cat ++ "_"
|
||||||
|
|
||||||
hEqGADT :: Prefix -> (OIdent -> Bool) -> (OIdent, [(OIdent, [OIdent])]) -> [String]
|
hEqGADT :: Prefix -> (OIdent -> Bool) -> (OIdent, [(OIdent, [OIdent])]) -> [String]
|
||||||
hEqGADT gId lexical (cat, rules)
|
hEqGADT gId lexical (cat, rules)
|
||||||
| isListCat (cat,rules) = let r = listr cat in ["(" ++ patt "x" r ++ "," ++ patt "y" r ++ ") -> " ++ listeqs]
|
| isListCat (cat,rules) = let r = listr cat in ["(" ++ patt "x" r ++ "," ++ patt "y" r ++ ") -> " ++ listeqs]
|
||||||
| otherwise = ["(" ++ patt "x" r ++ "," ++ patt "y" r ++ ") -> " ++ eqs r | r <- nonLexicalRules (lexical cat) rules]
|
| otherwise = ["(" ++ patt "x" r ++ "," ++ patt "y" r ++ ") -> " ++ eqs r | r <- nonLexicalRules (lexical cat) rules]
|
||||||
++ if lexical cat then ["(" ++ lexicalConstructor cat +++ "x" ++ "," ++ lexicalConstructor cat +++ "y" ++ ") -> x == y"] else []
|
++ if lexical cat then ["(" ++ lexicalConstructor cat +++ "x" ++ "," ++ lexicalConstructor cat +++ "y" ++ ") -> x == y"] else []
|
||||||
|
|
||||||
where
|
where
|
||||||
patt s (f,xs) = unwords (gId f : mkSVars s (length xs))
|
patt s (f,xs) = unwords (gId f : mkSVars s (length xs))
|
||||||
eqs (_,xs) = unwords ("and" : "[" : intersperse "," [x ++ " == " ++ y |
|
eqs (_,xs) = unwords ("and" : "[" : intersperse "," [x ++ " == " ++ y |
|
||||||
(x,y) <- zip (mkSVars "x" (length xs)) (mkSVars "y" (length xs)) ] ++ ["]"])
|
(x,y) <- zip (mkSVars "x" (length xs)) (mkSVars "y" (length xs)) ] ++ ["]"])
|
||||||
listr c = (c,["foo"]) -- foo just for length = 1
|
listr c = (c,["foo"]) -- foo just for length = 1
|
||||||
listeqs = "and [x == y | (x,y) <- zip x1 y1]"
|
listeqs = "and [x == y | (x,y) <- zip x1 y1]"
|
||||||
@@ -195,26 +189,25 @@ prCompos :: Prefix -> (OIdent -> Bool) -> (String,HSkeleton) -> [String]
|
|||||||
prCompos gId lexical (_,catrules) =
|
prCompos gId lexical (_,catrules) =
|
||||||
["instance Compos Tree where",
|
["instance Compos Tree where",
|
||||||
" compos r a f t = case t of"]
|
" compos r a f t = case t of"]
|
||||||
++
|
++
|
||||||
[" " ++ prComposCons (gId f) xs | (c,rs) <- catrules, not (isListCat (c,rs)),
|
[" " ++ prComposCons (gId f) xs | (c,rs) <- catrules, not (isListCat (c,rs)),
|
||||||
(f,xs) <- rs, not (null xs)]
|
(f,xs) <- rs, not (null xs)]
|
||||||
++
|
++
|
||||||
[" " ++ prComposCons (gId c) ["x1"] | (c,rs) <- catrules, isListCat (c,rs)]
|
[" " ++ prComposCons (gId c) ["x1"] | (c,rs) <- catrules, isListCat (c,rs)]
|
||||||
++
|
++
|
||||||
[" _ -> r t"]
|
[" _ -> r t"]
|
||||||
where
|
where
|
||||||
prComposCons f xs = let vs = mkVars (length xs) in
|
prComposCons f xs = let vs = mkVars (length xs) in
|
||||||
f +++ unwords vs +++ "->" +++ rhs f (zip vs xs)
|
f +++ unwords vs +++ "->" +++ rhs f (zip vs xs)
|
||||||
rhs f vcs = "r" +++ f +++ unwords (map (prRec f) vcs)
|
rhs f vcs = "r" +++ f +++ unwords (map (prRec f) vcs)
|
||||||
prRec f (v,c)
|
prRec f (v,c)
|
||||||
| isList f = "`a` foldr (a . a (r (:)) . f) (r [])" +++ v
|
| isList f = "`a` foldr (a . a (r (:)) . f) (r [])" +++ v
|
||||||
| otherwise = "`a`" +++ "f" +++ v
|
| otherwise = "`a`" +++ "f" +++ v
|
||||||
isList f = gId "List" `isPrefixOf` f
|
isList f = (gId "List") `isPrefixOf` f
|
||||||
|
|
||||||
gfInstance :: Prefix -> (OIdent -> Bool) -> String -> (OIdent, [(OIdent, [OIdent])]) -> String
|
gfInstance :: Prefix -> (OIdent -> Bool) -> String -> (OIdent, [(OIdent, [OIdent])]) -> String
|
||||||
gfInstance gId lexical m crs = hInstance gId lexical m crs ++++ fInstance gId lexical m crs
|
gfInstance gId lexical m crs = hInstance gId lexical m crs ++++ fInstance gId lexical m crs
|
||||||
|
|
||||||
hInstance :: (String -> String) -> (String -> Bool) -> String -> (String, [(OIdent, [OIdent])]) -> String
|
|
||||||
----hInstance m ("Cn",_) = "" --- seems to belong to an old applic. AR 18/5/2004
|
----hInstance m ("Cn",_) = "" --- seems to belong to an old applic. AR 18/5/2004
|
||||||
hInstance gId _ m (cat,[]) = unlines [
|
hInstance gId _ m (cat,[]) = unlines [
|
||||||
"instance Show" +++ gId cat,
|
"instance Show" +++ gId cat,
|
||||||
@@ -223,15 +216,15 @@ hInstance gId _ m (cat,[]) = unlines [
|
|||||||
" gf _ = undefined",
|
" gf _ = undefined",
|
||||||
" fg _ = undefined"
|
" fg _ = undefined"
|
||||||
]
|
]
|
||||||
hInstance gId lexical m (cat,rules)
|
hInstance gId lexical m (cat,rules)
|
||||||
| isListCat (cat,rules) =
|
| isListCat (cat,rules) =
|
||||||
"instance Gf" +++ gId cat +++ "where" ++++
|
"instance Gf" +++ gId cat +++ "where" ++++
|
||||||
" gf (" ++ gId cat +++ "[" ++ intercalate "," baseVars ++ "])"
|
" gf (" ++ gId cat +++ "[" ++ concat (intersperse "," baseVars) ++ "])"
|
||||||
+++ "=" +++ mkRHS ("Base"++ec) baseVars ++++
|
+++ "=" +++ mkRHS ("Base"++ec) baseVars ++++
|
||||||
" gf (" ++ gId cat +++ "(x:xs)) = "
|
" gf (" ++ gId cat +++ "(x:xs)) = "
|
||||||
++ mkRHS ("Cons"++ec) ["x",prParenth (gId cat+++"xs")]
|
++ mkRHS ("Cons"++ec) ["x",prParenth (gId cat+++"xs")]
|
||||||
-- no show for GADTs
|
-- no show for GADTs
|
||||||
-- ++++ " gf (" ++ gId cat +++ "xs) = error (\"Bad " ++ cat ++ " value: \" ++ show xs)"
|
-- ++++ " gf (" ++ gId cat +++ "xs) = error (\"Bad " ++ cat ++ " value: \" ++ show xs)"
|
||||||
| otherwise =
|
| otherwise =
|
||||||
"instance Gf" +++ gId cat +++ "where\n" ++
|
"instance Gf" +++ gId cat +++ "where\n" ++
|
||||||
unlines ([mkInst f xx | (f,xx) <- nonLexicalRules (lexical cat) rules]
|
unlines ([mkInst f xx | (f,xx) <- nonLexicalRules (lexical cat) rules]
|
||||||
@@ -240,26 +233,23 @@ hInstance gId lexical m (cat,rules)
|
|||||||
ec = elemCat cat
|
ec = elemCat cat
|
||||||
baseVars = mkVars (baseSize (cat,rules))
|
baseVars = mkVars (baseSize (cat,rules))
|
||||||
mkInst f xx = let xx' = mkVars (length xx) in " gf " ++
|
mkInst f xx = let xx' = mkVars (length xx) in " gf " ++
|
||||||
(if null xx then gId f else prParenth (gId f +++ foldr1 (+++) xx')) +++
|
(if length xx == 0 then gId f else prParenth (gId f +++ foldr1 (+++) xx')) +++
|
||||||
"=" +++ mkRHS f xx'
|
"=" +++ mkRHS f xx'
|
||||||
mkRHS f vars = "mkApp (mkCId \"" ++ f ++ "\")" +++
|
mkRHS f vars = "mkApp (mkCId \"" ++ f ++ "\")" +++
|
||||||
"[" ++ prTList ", " ["gf" +++ x | x <- vars] ++ "]"
|
"[" ++ prTList ", " ["gf" +++ x | x <- vars] ++ "]"
|
||||||
|
|
||||||
mkVars :: Int -> [String]
|
|
||||||
mkVars = mkSVars "x"
|
mkVars = mkSVars "x"
|
||||||
|
|
||||||
mkSVars :: String -> Int -> [String]
|
|
||||||
mkSVars s n = [s ++ show i | i <- [1..n]]
|
mkSVars s n = [s ++ show i | i <- [1..n]]
|
||||||
|
|
||||||
----fInstance m ("Cn",_) = "" ---
|
----fInstance m ("Cn",_) = "" ---
|
||||||
fInstance _ _ m (cat,[]) = ""
|
fInstance _ _ m (cat,[]) = ""
|
||||||
fInstance gId lexical m (cat,rules) =
|
fInstance gId lexical m (cat,rules) =
|
||||||
" fg t =" ++++
|
" fg t =" ++++
|
||||||
(if isList
|
(if isList
|
||||||
then " " ++ gId cat ++ " (fgs t) where\n fgs t = case unApp t of"
|
then " " ++ gId cat ++ " (fgs t) where\n fgs t = case unApp t of"
|
||||||
else " case unApp t of") ++++
|
else " case unApp t of") ++++
|
||||||
unlines [mkInst f xx | (f,xx) <- nonLexicalRules (lexical cat) rules] ++++
|
unlines [mkInst f xx | (f,xx) <- nonLexicalRules (lexical cat) rules] ++++
|
||||||
(if lexical cat then " Just (i,[]) -> " ++ lexicalConstructor cat +++ "i" else "") ++++
|
(if lexical cat then " Just (i,[]) -> " ++ lexicalConstructor cat +++ "(showCId i)" else "") ++++
|
||||||
" _ -> error (\"no" +++ cat ++ " \" ++ show t)"
|
" _ -> error (\"no" +++ cat ++ " \" ++ show t)"
|
||||||
where
|
where
|
||||||
isList = isListCat (cat,rules)
|
isList = isListCat (cat,rules)
|
||||||
@@ -267,35 +257,31 @@ fInstance gId lexical m (cat,rules) =
|
|||||||
" Just (i," ++
|
" Just (i," ++
|
||||||
"[" ++ prTList "," xx' ++ "])" +++
|
"[" ++ prTList "," xx' ++ "])" +++
|
||||||
"| i == mkCId \"" ++ f ++ "\" ->" +++ mkRHS f xx'
|
"| i == mkCId \"" ++ f ++ "\" ->" +++ mkRHS f xx'
|
||||||
where
|
where xx' = ["x" ++ show i | (_,i) <- zip xx [1..]]
|
||||||
xx' = ["x" ++ show i | (_,i) <- zip xx [1..]]
|
mkRHS f vars
|
||||||
mkRHS f vars
|
| isList =
|
||||||
| isList =
|
if "Base" `isPrefixOf` f
|
||||||
if "Base" `isPrefixOf` f
|
then "[" ++ prTList ", " [ "fg" +++ x | x <- vars ] ++ "]"
|
||||||
then "[" ++ prTList ", " [ "fg" +++ x | x <- vars ] ++ "]"
|
else "fg" +++ (vars !! 0) +++ ":" +++ "fgs" +++ (vars !! 1)
|
||||||
else "fg" +++ (vars !! 0) +++ ":" +++ "fgs" +++ (vars !! 1)
|
| otherwise =
|
||||||
| otherwise =
|
gId f +++
|
||||||
gId f +++
|
prTList " " [prParenth ("fg" +++ x) | x <- vars]
|
||||||
prTList " " [prParenth ("fg" +++ x) | x <- vars]
|
|
||||||
|
|
||||||
--type HSkeleton = [(OIdent, [(OIdent, [OIdent])])]
|
--type HSkeleton = [(OIdent, [(OIdent, [OIdent])])]
|
||||||
hSkeleton :: PGF -> (String,HSkeleton)
|
hSkeleton :: PGF -> (String,HSkeleton)
|
||||||
hSkeleton gr =
|
hSkeleton gr =
|
||||||
(abstractName gr,
|
(showCId (absname gr),
|
||||||
let fs =
|
let fs =
|
||||||
[(c, [(f, cs) | (f, cs,_) <- fs]) |
|
[(showCId c, [(showCId f, map showCId cs) | (f, (cs,_)) <- fs]) |
|
||||||
fs@((_, _,c):_) <- fns]
|
fs@((_, (_,c)):_) <- fns]
|
||||||
in fs ++ [(c, []) | c <- cts, notElem c (["Int", "Float", "String"] ++ map fst fs)]
|
in fs ++ [(sc, []) | c <- cts, let sc = showCId c, notElem sc (["Int", "Float", "String"] ++ map fst fs)]
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
cts = categories gr
|
cts = Map.keys (cats (abstract gr))
|
||||||
fns = groupBy valtypg (sortBy valtyps (mapMaybe jty (functions gr)))
|
fns = groupBy valtypg (sortBy valtyps (map jty (Map.assocs (funs (abstract gr)))))
|
||||||
valtyps (_,_,x) (_,_,y) = compare x y
|
valtyps (_, (_,x)) (_, (_,y)) = compare x y
|
||||||
valtypg (_,_,x) (_,_,y) = x == y
|
valtypg (_, (_,x)) (_, (_,y)) = x == y
|
||||||
jty f = case functionType gr f of
|
jty (f,(ty,_,_,_)) = (f,catSkeleton ty)
|
||||||
Just ty -> let (hypos,valcat,_) = unType ty
|
|
||||||
in Just (f,[argcat | (_,_,ty) <- hypos, let (_,argcat,_) = unType ty],valcat)
|
|
||||||
Nothing -> Nothing
|
|
||||||
{-
|
{-
|
||||||
updateSkeleton :: OIdent -> HSkeleton -> (OIdent, [OIdent]) -> HSkeleton
|
updateSkeleton :: OIdent -> HSkeleton -> (OIdent, [OIdent]) -> HSkeleton
|
||||||
updateSkeleton cat skel rule =
|
updateSkeleton cat skel rule =
|
||||||
@@ -305,10 +291,9 @@ updateSkeleton cat skel rule =
|
|||||||
-}
|
-}
|
||||||
isListCat :: (OIdent, [(OIdent, [OIdent])]) -> Bool
|
isListCat :: (OIdent, [(OIdent, [OIdent])]) -> Bool
|
||||||
isListCat (cat,rules) = "List" `isPrefixOf` cat && length rules == 2
|
isListCat (cat,rules) = "List" `isPrefixOf` cat && length rules == 2
|
||||||
&& ("Base"++c) `elem` fs && ("Cons"++c) `elem` fs
|
&& ("Base"++c) `elem` fs && ("Cons"++c) `elem` fs
|
||||||
where
|
where c = elemCat cat
|
||||||
c = elemCat cat
|
fs = map fst rules
|
||||||
fs = map fst rules
|
|
||||||
|
|
||||||
-- | Gets the element category of a list category.
|
-- | Gets the element category of a list category.
|
||||||
elemCat :: OIdent -> OIdent
|
elemCat :: OIdent -> OIdent
|
||||||
@@ -325,7 +310,7 @@ baseSize (_,rules) = length bs
|
|||||||
where Just (_,bs) = find (("Base" `isPrefixOf`) . fst) rules
|
where Just (_,bs) = find (("Base" `isPrefixOf`) . fst) rules
|
||||||
|
|
||||||
composClass :: [String]
|
composClass :: [String]
|
||||||
composClass =
|
composClass =
|
||||||
[
|
[
|
||||||
"",
|
"",
|
||||||
"class Compos t where",
|
"class Compos t where",
|
||||||
@@ -352,3 +337,4 @@ composClass =
|
|||||||
"",
|
"",
|
||||||
"newtype C b a = C { unC :: b }"
|
"newtype C b a = C { unC :: b }"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
105
src/compiler/GF/Compile/PGFtoJS.hs
Normal file
105
src/compiler/GF/Compile/PGFtoJS.hs
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
module GF.Compile.PGFtoJS (pgf2js) where
|
||||||
|
|
||||||
|
import PGF(showCId)
|
||||||
|
import PGF.Internal as M
|
||||||
|
import qualified GF.JavaScript.AbsJS as JS
|
||||||
|
import qualified GF.JavaScript.PrintJS as JS
|
||||||
|
|
||||||
|
--import GF.Data.ErrM
|
||||||
|
--import GF.Infra.Option
|
||||||
|
|
||||||
|
--import Control.Monad (mplus)
|
||||||
|
--import Data.Array.Unboxed (UArray)
|
||||||
|
import qualified Data.Array.IArray as Array
|
||||||
|
--import Data.Maybe (fromMaybe)
|
||||||
|
import Data.Map (Map)
|
||||||
|
import qualified Data.Set as Set
|
||||||
|
import qualified Data.Map as Map
|
||||||
|
import qualified Data.IntMap as IntMap
|
||||||
|
|
||||||
|
pgf2js :: PGF -> String
|
||||||
|
pgf2js pgf =
|
||||||
|
JS.printTree $ JS.Program [JS.ElStmt $ JS.SDeclOrExpr $ JS.Decl [JS.DInit (JS.Ident n) grammar]]
|
||||||
|
where
|
||||||
|
n = showCId $ absname pgf
|
||||||
|
as = abstract pgf
|
||||||
|
cs = Map.assocs (concretes pgf)
|
||||||
|
start = showCId $ M.lookStartCat pgf
|
||||||
|
grammar = new "GFGrammar" [js_abstract, js_concrete]
|
||||||
|
js_abstract = abstract2js start as
|
||||||
|
js_concrete = JS.EObj $ map concrete2js cs
|
||||||
|
|
||||||
|
abstract2js :: String -> Abstr -> JS.Expr
|
||||||
|
abstract2js start ds = new "GFAbstract" [JS.EStr start, JS.EObj $ map absdef2js (Map.assocs (funs ds))]
|
||||||
|
|
||||||
|
absdef2js :: (CId,(Type,Int,Maybe ([Equation],[[M.Instr]]),Double)) -> JS.Property
|
||||||
|
absdef2js (f,(typ,_,_,_)) =
|
||||||
|
let (args,cat) = M.catSkeleton typ in
|
||||||
|
JS.Prop (JS.IdentPropName (JS.Ident (showCId f))) (new "Type" [JS.EArray [JS.EStr (showCId x) | x <- args], JS.EStr (showCId cat)])
|
||||||
|
|
||||||
|
lit2js (LStr s) = JS.EStr s
|
||||||
|
lit2js (LInt n) = JS.EInt n
|
||||||
|
lit2js (LFlt d) = JS.EDbl d
|
||||||
|
|
||||||
|
concrete2js :: (CId,Concr) -> JS.Property
|
||||||
|
concrete2js (c,cnc) =
|
||||||
|
JS.Prop l (new "GFConcrete" [mapToJSObj (lit2js) $ cflags cnc,
|
||||||
|
JS.EObj $ [JS.Prop (JS.IntPropName cat) (JS.EArray (map frule2js (Set.toList set))) | (cat,set) <- IntMap.toList (productions cnc)],
|
||||||
|
JS.EArray $ (map ffun2js (Array.elems (cncfuns cnc))),
|
||||||
|
JS.EArray $ (map seq2js (Array.elems (sequences cnc))),
|
||||||
|
JS.EObj $ map cats (Map.assocs (cnccats cnc)),
|
||||||
|
JS.EInt (totalCats cnc)])
|
||||||
|
where
|
||||||
|
l = JS.IdentPropName (JS.Ident (showCId c))
|
||||||
|
{-
|
||||||
|
litslins = [JS.Prop (JS.StringPropName "Int") (JS.EFun [children] [JS.SReturn $ new "Arr" [JS.EIndex (JS.EVar children) (JS.EInt 0)]]),
|
||||||
|
JS.Prop (JS.StringPropName "Float") (JS.EFun [children] [JS.SReturn $ new "Arr" [JS.EIndex (JS.EVar children) (JS.EInt 0)]]),
|
||||||
|
JS.Prop (JS.StringPropName "String") (JS.EFun [children] [JS.SReturn $ new "Arr" [JS.EIndex (JS.EVar children) (JS.EInt 0)]])]
|
||||||
|
-}
|
||||||
|
cats (c,CncCat start end _) = JS.Prop (JS.IdentPropName (JS.Ident (showCId c))) (JS.EObj [JS.Prop (JS.IdentPropName (JS.Ident "s")) (JS.EInt start)
|
||||||
|
,JS.Prop (JS.IdentPropName (JS.Ident "e")) (JS.EInt end)])
|
||||||
|
{-
|
||||||
|
mkStr :: String -> JS.Expr
|
||||||
|
mkStr s = new "Str" [JS.EStr s]
|
||||||
|
|
||||||
|
mkSeq :: [JS.Expr] -> JS.Expr
|
||||||
|
mkSeq [x] = x
|
||||||
|
mkSeq xs = new "Seq" xs
|
||||||
|
|
||||||
|
argIdent :: Integer -> JS.Ident
|
||||||
|
argIdent n = JS.Ident ("x" ++ show n)
|
||||||
|
-}
|
||||||
|
children :: JS.Ident
|
||||||
|
children = JS.Ident "cs"
|
||||||
|
|
||||||
|
frule2js :: Production -> JS.Expr
|
||||||
|
frule2js (PApply funid args) = new "Apply" [JS.EInt funid, JS.EArray (map farg2js args)]
|
||||||
|
frule2js (PCoerce arg) = new "Coerce" [JS.EInt arg]
|
||||||
|
|
||||||
|
farg2js (PArg hypos fid) = new "PArg" (map (JS.EInt . snd) hypos ++ [JS.EInt fid])
|
||||||
|
|
||||||
|
ffun2js (CncFun f lins) = new "CncFun" [JS.EStr (showCId f), JS.EArray (map JS.EInt (Array.elems lins))]
|
||||||
|
|
||||||
|
seq2js :: Array.Array DotPos Symbol -> JS.Expr
|
||||||
|
seq2js seq = JS.EArray [sym2js s | s <- Array.elems seq]
|
||||||
|
|
||||||
|
sym2js :: Symbol -> JS.Expr
|
||||||
|
sym2js (SymCat n l) = new "SymCat" [JS.EInt n, JS.EInt l]
|
||||||
|
sym2js (SymLit n l) = new "SymLit" [JS.EInt n, JS.EInt l]
|
||||||
|
sym2js (SymVar n l) = new "SymVar" [JS.EInt n, JS.EInt l]
|
||||||
|
sym2js (SymKS t) = new "SymKS" [JS.EStr t]
|
||||||
|
sym2js (SymKP ts alts) = new "SymKP" [JS.EArray (map sym2js ts), JS.EArray (map alt2js alts)]
|
||||||
|
sym2js SymBIND = new "SymKS" [JS.EStr "&+"]
|
||||||
|
sym2js SymSOFT_BIND = new "SymKS" [JS.EStr "&+"]
|
||||||
|
sym2js SymSOFT_SPACE = new "SymKS" [JS.EStr "&+"]
|
||||||
|
sym2js SymCAPIT = new "SymKS" [JS.EStr "&|"]
|
||||||
|
sym2js SymALL_CAPIT = new "SymKS" [JS.EStr "&|"]
|
||||||
|
sym2js SymNE = new "SymNE" []
|
||||||
|
|
||||||
|
alt2js (ps,ts) = new "Alt" [JS.EArray (map sym2js ps), JS.EArray (map JS.EStr ts)]
|
||||||
|
|
||||||
|
new :: String -> [JS.Expr] -> JS.Expr
|
||||||
|
new f xs = JS.ENew (JS.Ident f) xs
|
||||||
|
|
||||||
|
mapToJSObj :: (a -> JS.Expr) -> Map CId a -> JS.Expr
|
||||||
|
mapToJSObj f m = JS.EObj [ JS.Prop (JS.IdentPropName (JS.Ident (showCId k))) (f v) | (k,v) <- Map.toList m ]
|
||||||
@@ -1,110 +1,156 @@
|
|||||||
module GF.Compile.PGFtoJSON (pgf2json) where
|
module GF.Compile.PGFtoJSON (pgf2json) where
|
||||||
|
|
||||||
import PGF2
|
import PGF (showCId)
|
||||||
import PGF2.Internal
|
import qualified PGF.Internal as M
|
||||||
import Text.JSON
|
import PGF.Internal (
|
||||||
|
Abstr,
|
||||||
|
CId,
|
||||||
|
CncCat(..),
|
||||||
|
CncFun(..),
|
||||||
|
Concr,
|
||||||
|
DotPos,
|
||||||
|
Equation(..),
|
||||||
|
Literal(..),
|
||||||
|
PArg(..),
|
||||||
|
PGF,
|
||||||
|
Production(..),
|
||||||
|
Symbol(..),
|
||||||
|
Type,
|
||||||
|
absname,
|
||||||
|
abstract,
|
||||||
|
cflags,
|
||||||
|
cnccats,
|
||||||
|
cncfuns,
|
||||||
|
concretes,
|
||||||
|
funs,
|
||||||
|
productions,
|
||||||
|
sequences,
|
||||||
|
totalCats
|
||||||
|
)
|
||||||
|
|
||||||
|
import qualified Text.JSON as JSON
|
||||||
|
import Text.JSON (JSValue(..))
|
||||||
|
|
||||||
|
import qualified Data.Array.IArray as Array
|
||||||
|
import Data.Map (Map)
|
||||||
|
import qualified Data.Set as Set
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
|
import qualified Data.IntMap as IntMap
|
||||||
|
|
||||||
pgf2json :: PGF -> String
|
pgf2json :: PGF -> String
|
||||||
pgf2json pgf =
|
pgf2json pgf =
|
||||||
encode $ makeObj
|
JSON.encode $ JSON.makeObj
|
||||||
[ ("abstract", abstract2json pgf)
|
[ ("abstract", json_abstract)
|
||||||
, ("concretes", makeObj $ map concrete2json
|
, ("concretes", json_concretes)
|
||||||
(Map.toList (languages pgf)))
|
]
|
||||||
|
where
|
||||||
|
n = showCId $ absname pgf
|
||||||
|
as = abstract pgf
|
||||||
|
cs = Map.assocs (concretes pgf)
|
||||||
|
start = showCId $ M.lookStartCat pgf
|
||||||
|
json_abstract = abstract2json n start as
|
||||||
|
json_concretes = JSON.makeObj $ map concrete2json cs
|
||||||
|
|
||||||
|
abstract2json :: String -> String -> Abstr -> JSValue
|
||||||
|
abstract2json name start ds =
|
||||||
|
JSON.makeObj
|
||||||
|
[ ("name", mkJSStr name)
|
||||||
|
, ("startcat", mkJSStr start)
|
||||||
|
, ("funs", JSON.makeObj $ map absdef2json (Map.assocs (funs ds)))
|
||||||
]
|
]
|
||||||
|
|
||||||
abstract2json :: PGF -> JSValue
|
absdef2json :: (CId,(Type,Int,Maybe ([Equation],[[M.Instr]]),Double)) -> (String,JSValue)
|
||||||
abstract2json pgf =
|
absdef2json (f,(typ,_,_,_)) = (showCId f,sig)
|
||||||
makeObj
|
|
||||||
[ ("name", showJSON (abstractName pgf))
|
|
||||||
, ("startcat", showJSON (showType [] (startCat pgf)))
|
|
||||||
, ("funs", makeObj $ map (absdef2json pgf) (functions pgf))
|
|
||||||
]
|
|
||||||
|
|
||||||
absdef2json :: PGF -> Fun -> (String,JSValue)
|
|
||||||
absdef2json pgf f = (f,sig)
|
|
||||||
where
|
where
|
||||||
Just (hypos,cat,_) = fmap unType (functionType pgf f)
|
(args,cat) = M.catSkeleton typ
|
||||||
sig = makeObj
|
sig = JSON.makeObj
|
||||||
[ ("args", showJSON $ map (\(_,_,ty) -> showType [] ty) hypos)
|
[ ("args", JSArray $ map (mkJSStr.showCId) args)
|
||||||
, ("cat", showJSON cat)
|
, ("cat", mkJSStr $ showCId cat)
|
||||||
]
|
]
|
||||||
|
|
||||||
lit2json :: Literal -> JSValue
|
lit2json :: Literal -> JSValue
|
||||||
lit2json (LStr s) = showJSON s
|
lit2json (LStr s) = mkJSStr s
|
||||||
lit2json (LInt n) = showJSON n
|
lit2json (LInt n) = mkJSInt n
|
||||||
lit2json (LFlt d) = showJSON d
|
lit2json (LFlt d) = JSRational True (toRational d)
|
||||||
|
|
||||||
concrete2json :: (ConcName,Concr) -> (String,JSValue)
|
concrete2json :: (CId,Concr) -> (String,JSValue)
|
||||||
concrete2json (c,cnc) = (c,obj)
|
concrete2json (c,cnc) = (showCId c,obj)
|
||||||
where
|
where
|
||||||
obj = makeObj
|
obj = JSON.makeObj
|
||||||
[ ("flags", makeObj [(k, lit2json v) | (k,v) <- concrFlags cnc])
|
[ ("flags", JSON.makeObj [ (showCId k, lit2json v) | (k,v) <- Map.toList (cflags cnc) ])
|
||||||
, ("productions", makeObj [(show fid, showJSON (map frule2json (concrProductions cnc fid))) | (_,start,end,_) <- concrCategories cnc, fid <- [start..end]])
|
, ("productions", JSON.makeObj [ (show cat, JSArray (map frule2json (Set.toList set))) | (cat,set) <- IntMap.toList (productions cnc)])
|
||||||
, ("functions", showJSON [ffun2json funid (concrFunction cnc funid) | funid <- [0..concrTotalFuns cnc-1]])
|
, ("functions", JSArray (map ffun2json (Array.elems (cncfuns cnc))))
|
||||||
, ("sequences", showJSON [seq2json seqid (concrSequence cnc seqid) | seqid <- [0..concrTotalSeqs cnc-1]])
|
, ("sequences", JSArray (map seq2json (Array.elems (sequences cnc))))
|
||||||
, ("categories", makeObj $ map cat2json (concrCategories cnc))
|
, ("categories", JSON.makeObj $ map cats2json (Map.assocs (cnccats cnc)))
|
||||||
, ("totalfids", showJSON (concrTotalCats cnc))
|
, ("totalfids", mkJSInt (totalCats cnc))
|
||||||
]
|
]
|
||||||
|
|
||||||
cat2json :: (Cat,FId,FId,[String]) -> (String,JSValue)
|
cats2json :: (CId, CncCat) -> (String,JSValue)
|
||||||
cat2json (cat,start,end,_) = (cat, ixs)
|
cats2json (c,CncCat start end _) = (showCId c, ixs)
|
||||||
where
|
where
|
||||||
ixs = makeObj
|
ixs = JSON.makeObj
|
||||||
[ ("start", showJSON start)
|
[ ("start", mkJSInt start)
|
||||||
, ("end", showJSON end)
|
, ("end", mkJSInt end)
|
||||||
]
|
]
|
||||||
|
|
||||||
frule2json :: Production -> JSValue
|
frule2json :: Production -> JSValue
|
||||||
frule2json (PApply fid args) =
|
frule2json (PApply fid args) =
|
||||||
makeObj
|
JSON.makeObj
|
||||||
[ ("type", showJSON "Apply")
|
[ ("type", mkJSStr "Apply")
|
||||||
, ("fid", showJSON fid)
|
, ("fid", mkJSInt fid)
|
||||||
, ("args", showJSON (map farg2json args))
|
, ("args", JSArray (map farg2json args))
|
||||||
]
|
]
|
||||||
frule2json (PCoerce arg) =
|
frule2json (PCoerce arg) =
|
||||||
makeObj
|
JSON.makeObj
|
||||||
[ ("type", showJSON "Coerce")
|
[ ("type", mkJSStr "Coerce")
|
||||||
, ("arg", showJSON arg)
|
, ("arg", mkJSInt arg)
|
||||||
]
|
]
|
||||||
|
|
||||||
farg2json :: PArg -> JSValue
|
farg2json :: PArg -> JSValue
|
||||||
farg2json (PArg hypos fid) =
|
farg2json (PArg hypos fid) =
|
||||||
makeObj
|
JSON.makeObj
|
||||||
[ ("type", showJSON "PArg")
|
[ ("type", mkJSStr "PArg")
|
||||||
, ("hypos", JSArray $ map (showJSON . snd) hypos)
|
, ("hypos", JSArray $ map (mkJSInt . snd) hypos)
|
||||||
, ("fid", showJSON fid)
|
, ("fid", mkJSInt fid)
|
||||||
]
|
]
|
||||||
|
|
||||||
ffun2json :: FunId -> (Fun,[SeqId]) -> JSValue
|
ffun2json :: CncFun -> JSValue
|
||||||
ffun2json funid (fun,seqids) =
|
ffun2json (CncFun f lins) =
|
||||||
makeObj
|
JSON.makeObj
|
||||||
[ ("name", showJSON fun)
|
[ ("name", mkJSStr $ showCId f)
|
||||||
, ("lins", showJSON seqids)
|
, ("lins", JSArray (map mkJSInt (Array.elems lins)))
|
||||||
]
|
]
|
||||||
|
|
||||||
seq2json :: SeqId -> [Symbol] -> JSValue
|
seq2json :: Array.Array DotPos Symbol -> JSValue
|
||||||
seq2json seqid seq = showJSON [sym2json sym | sym <- seq]
|
seq2json seq = JSArray [sym2json s | s <- Array.elems seq]
|
||||||
|
|
||||||
sym2json :: Symbol -> JSValue
|
sym2json :: Symbol -> JSValue
|
||||||
sym2json (SymCat n l) = new "SymCat" [showJSON n, showJSON l]
|
sym2json (SymCat n l) = new "SymCat" [mkJSInt n, mkJSInt l]
|
||||||
sym2json (SymLit n l) = new "SymLit" [showJSON n, showJSON l]
|
sym2json (SymLit n l) = new "SymLit" [mkJSInt n, mkJSInt l]
|
||||||
sym2json (SymVar n l) = new "SymVar" [showJSON n, showJSON l]
|
sym2json (SymVar n l) = new "SymVar" [mkJSInt n, mkJSInt l]
|
||||||
sym2json (SymKS t) = new "SymKS" [showJSON t]
|
sym2json (SymKS t) = new "SymKS" [mkJSStr t]
|
||||||
sym2json (SymKP ts alts) = new "SymKP" [JSArray (map sym2json ts), JSArray (map alt2json alts)]
|
sym2json (SymKP ts alts) = new "SymKP" [JSArray (map sym2json ts), JSArray (map alt2json alts)]
|
||||||
sym2json SymBIND = new "SymKS" [showJSON "&+"]
|
sym2json SymBIND = new "SymKS" [mkJSStr "&+"]
|
||||||
sym2json SymSOFT_BIND = new "SymKS" [showJSON "&+"]
|
sym2json SymSOFT_BIND = new "SymKS" [mkJSStr "&+"]
|
||||||
sym2json SymSOFT_SPACE = new "SymKS" [showJSON "&+"]
|
sym2json SymSOFT_SPACE = new "SymKS" [mkJSStr "&+"]
|
||||||
sym2json SymCAPIT = new "SymKS" [showJSON "&|"]
|
sym2json SymCAPIT = new "SymKS" [mkJSStr "&|"]
|
||||||
sym2json SymALL_CAPIT = new "SymKS" [showJSON "&|"]
|
sym2json SymALL_CAPIT = new "SymKS" [mkJSStr "&|"]
|
||||||
sym2json SymNE = new "SymNE" []
|
sym2json SymNE = new "SymNE" []
|
||||||
|
|
||||||
alt2json :: ([Symbol],[String]) -> JSValue
|
alt2json :: ([Symbol],[String]) -> JSValue
|
||||||
alt2json (ps,ts) = new "Alt" [showJSON (map sym2json ps), showJSON ts]
|
alt2json (ps,ts) = new "Alt" [JSArray (map sym2json ps), JSArray (map mkJSStr ts)]
|
||||||
|
|
||||||
new :: String -> [JSValue] -> JSValue
|
new :: String -> [JSValue] -> JSValue
|
||||||
new f xs =
|
new f xs =
|
||||||
makeObj
|
JSON.makeObj
|
||||||
[ ("type", showJSON f)
|
[ ("type", mkJSStr f)
|
||||||
, ("args", showJSON xs)
|
, ("args", JSArray xs)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
-- | Make JSON value from string
|
||||||
|
mkJSStr :: String -> JSValue
|
||||||
|
mkJSStr = JSString . JSON.toJSString
|
||||||
|
|
||||||
|
-- | Make JSON value from integer
|
||||||
|
mkJSInt :: Integral a => a -> JSValue
|
||||||
|
mkJSInt = JSRational False . toRational
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
module GF.Compile.PGFtoJava (grammar2java) where
|
module GF.Compile.PGFtoJava (grammar2java) where
|
||||||
|
|
||||||
import PGF2
|
import PGF
|
||||||
import Data.Maybe(maybe)
|
import Data.Maybe(maybe)
|
||||||
import Data.List(intercalate)
|
import Data.List(intercalate)
|
||||||
import GF.Infra.Option
|
import GF.Infra.Option
|
||||||
@@ -24,8 +24,9 @@ javaPreamble name =
|
|||||||
]
|
]
|
||||||
|
|
||||||
javaMethod gr fun =
|
javaMethod gr fun =
|
||||||
" public static Expr "++fun++"("++arg_decls++") { return new Expr("++show fun++args++"); }"
|
" public static Expr "++name++"("++arg_decls++") { return new Expr("++show name++args++"); }"
|
||||||
where
|
where
|
||||||
|
name = showCId fun
|
||||||
arity = maybe 0 getArrity (functionType gr fun)
|
arity = maybe 0 getArrity (functionType gr fun)
|
||||||
vars = ['e':show i | i <- [1..arity]]
|
vars = ['e':show i | i <- [1..arity]]
|
||||||
|
|
||||||
|
|||||||
262
src/compiler/GF/Compile/PGFtoProlog.hs
Normal file
262
src/compiler/GF/Compile/PGFtoProlog.hs
Normal file
@@ -0,0 +1,262 @@
|
|||||||
|
----------------------------------------------------------------------
|
||||||
|
-- |
|
||||||
|
-- Module : PGFtoProlog
|
||||||
|
-- Maintainer : Peter Ljunglöf
|
||||||
|
--
|
||||||
|
-- exports a GF grammar into a Prolog module
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
module GF.Compile.PGFtoProlog (grammar2prolog) where
|
||||||
|
|
||||||
|
import PGF(mkCId,wildCId,showCId)
|
||||||
|
import PGF.Internal
|
||||||
|
--import PGF.Macros
|
||||||
|
|
||||||
|
import GF.Data.Operations
|
||||||
|
|
||||||
|
import qualified Data.Array.IArray as Array
|
||||||
|
import qualified Data.Set as Set
|
||||||
|
import qualified Data.Map as Map
|
||||||
|
import qualified Data.IntMap as IntMap
|
||||||
|
import Data.Char (isAlphaNum, isAscii, isAsciiLower, isAsciiUpper, ord)
|
||||||
|
import Data.List (isPrefixOf, mapAccumL)
|
||||||
|
|
||||||
|
grammar2prolog :: PGF -> String
|
||||||
|
grammar2prolog pgf
|
||||||
|
= ("%% This file was automatically generated by GF" +++++
|
||||||
|
":- style_check(-singleton)." +++++
|
||||||
|
plFacts wildCId "abstract" 1 "(?AbstractName)"
|
||||||
|
[[plp name]] ++++
|
||||||
|
plFacts wildCId "concrete" 2 "(?AbstractName, ?ConcreteName)"
|
||||||
|
[[plp name, plp cncname] |
|
||||||
|
cncname <- Map.keys (concretes pgf)] ++++
|
||||||
|
plFacts wildCId "flag" 2 "(?Flag, ?Value): global flags"
|
||||||
|
[[plp f, plp v] |
|
||||||
|
(f, v) <- Map.assocs (gflags pgf)] ++++
|
||||||
|
plAbstract name (abstract pgf) ++++
|
||||||
|
unlines (map plConcrete (Map.assocs (concretes pgf)))
|
||||||
|
)
|
||||||
|
where name = absname pgf
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
-- abstract syntax
|
||||||
|
|
||||||
|
plAbstract :: CId -> Abstr -> String
|
||||||
|
plAbstract name abs
|
||||||
|
= (plHeader "Abstract syntax" ++++
|
||||||
|
plFacts name "flag" 2 "(?Flag, ?Value): flags for abstract syntax"
|
||||||
|
[[plp f, plp v] |
|
||||||
|
(f, v) <- Map.assocs (aflags abs)] ++++
|
||||||
|
plFacts name "cat" 2 "(?Type, ?[X:Type,...])"
|
||||||
|
[[plType cat args, plHypos hypos'] |
|
||||||
|
(cat, (hypos,_,_)) <- Map.assocs (cats abs),
|
||||||
|
let ((_, subst), hypos') = mapAccumL alphaConvertHypo emptyEnv hypos,
|
||||||
|
let args = reverse [EFun x | (_,x) <- subst]] ++++
|
||||||
|
plFacts name "fun" 3 "(?Fun, ?Type, ?[X:Type,...])"
|
||||||
|
[[plp fun, plType cat args, plHypos hypos] |
|
||||||
|
(fun, (typ, _, _, _)) <- Map.assocs (funs abs),
|
||||||
|
let (_, DTyp hypos cat args) = alphaConvert emptyEnv typ] ++++
|
||||||
|
plFacts name "def" 2 "(?Fun, ?Expr)"
|
||||||
|
[[plp fun, plp expr] |
|
||||||
|
(fun, (_, _, Just (eqs,_), _)) <- Map.assocs (funs abs),
|
||||||
|
let (_, expr) = alphaConvert emptyEnv eqs]
|
||||||
|
)
|
||||||
|
where plType cat args = plTerm (plp cat) (map plp args)
|
||||||
|
plHypos hypos = plList [plOper ":" (plp x) (plp ty) | (_, x, ty) <- hypos]
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
-- concrete syntax
|
||||||
|
|
||||||
|
plConcrete :: (CId, Concr) -> String
|
||||||
|
plConcrete (name, cnc)
|
||||||
|
= (plHeader ("Concrete syntax: " ++ plp name) ++++
|
||||||
|
plFacts name "flag" 2 "(?Flag, ?Value): flags for concrete syntax"
|
||||||
|
[[plp f, plp v] |
|
||||||
|
(f, v) <- Map.assocs (cflags cnc)] ++++
|
||||||
|
plFacts name "printname" 2 "(?AbsFun/AbsCat, ?Atom)"
|
||||||
|
[[plp f, plp n] |
|
||||||
|
(f, n) <- Map.assocs (printnames cnc)] ++++
|
||||||
|
plFacts name "lindef" 2 "(?CncCat, ?CncFun)"
|
||||||
|
[[plCat cat, plFun fun] |
|
||||||
|
(cat, funs) <- IntMap.assocs (lindefs cnc),
|
||||||
|
fun <- funs] ++++
|
||||||
|
plFacts name "prod" 3 "(?CncCat, ?CncFun, ?[CncCat])"
|
||||||
|
[[plCat cat, fun, plTerm "c" (map plCat args)] |
|
||||||
|
(cat, set) <- IntMap.toList (productions cnc),
|
||||||
|
(fun, args) <- map plProduction (Set.toList set)] ++++
|
||||||
|
plFacts name "cncfun" 3 "(?CncFun, ?[Seq,...], ?AbsFun)"
|
||||||
|
[[plFun fun, plTerm "s" (map plSeq (Array.elems lins)), plp absfun] |
|
||||||
|
(fun, CncFun absfun lins) <- Array.assocs (cncfuns cnc)] ++++
|
||||||
|
plFacts name "seq" 2 "(?Seq, ?[Term])"
|
||||||
|
[[plSeq seq, plp (Array.elems symbols)] |
|
||||||
|
(seq, symbols) <- Array.assocs (sequences cnc)] ++++
|
||||||
|
plFacts name "cnccat" 2 "(?AbsCat, ?[CnCCat])"
|
||||||
|
[[plp cat, plList (map plCat [start..end])] |
|
||||||
|
(cat, CncCat start end _) <- Map.assocs (cnccats cnc)]
|
||||||
|
)
|
||||||
|
where plProduction (PCoerce arg) = ("-", [arg])
|
||||||
|
plProduction (PApply funid args) = (plFun funid, [fid | PArg hypos fid <- args])
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
-- prolog-printing pgf datatypes
|
||||||
|
|
||||||
|
instance PLPrint Type where
|
||||||
|
plp (DTyp hypos cat args)
|
||||||
|
| null hypos = result
|
||||||
|
| otherwise = plOper " -> " plHypos result
|
||||||
|
where result = plTerm (plp cat) (map plp args)
|
||||||
|
plHypos = plList [plOper ":" (plp x) (plp ty) | (_,x,ty) <- hypos]
|
||||||
|
|
||||||
|
instance PLPrint Expr where
|
||||||
|
plp (EFun x) = plp x
|
||||||
|
plp (EAbs _ x e)= plOper "^" (plp x) (plp e)
|
||||||
|
plp (EApp e e') = plOper " * " (plp e) (plp e')
|
||||||
|
plp (ELit lit) = plp lit
|
||||||
|
plp (EMeta n) = "Meta_" ++ show n
|
||||||
|
|
||||||
|
instance PLPrint Patt where
|
||||||
|
plp (PVar x) = plp x
|
||||||
|
plp (PApp f ps) = plOper " * " (plp f) (plp ps)
|
||||||
|
plp (PLit lit) = plp lit
|
||||||
|
|
||||||
|
instance PLPrint Equation where
|
||||||
|
plp (Equ patterns result) = plOper ":" (plp patterns) (plp result)
|
||||||
|
|
||||||
|
instance PLPrint CId where
|
||||||
|
plp cid | isLogicalVariable str || cid == wildCId = plVar str
|
||||||
|
| otherwise = plAtom str
|
||||||
|
where str = showCId cid
|
||||||
|
|
||||||
|
instance PLPrint Literal where
|
||||||
|
plp (LStr s) = plp s
|
||||||
|
plp (LInt n) = plp (show n)
|
||||||
|
plp (LFlt f) = plp (show f)
|
||||||
|
|
||||||
|
instance PLPrint Symbol where
|
||||||
|
plp (SymCat n l) = plOper ":" (show n) (show l)
|
||||||
|
plp (SymLit n l) = plTerm "lit" [show n, show l]
|
||||||
|
plp (SymVar n l) = plTerm "var" [show n, show l]
|
||||||
|
plp (SymKS t) = plAtom t
|
||||||
|
plp (SymKP ts alts) = plTerm "pre" [plList (map plp ts), plList (map plAlt alts)]
|
||||||
|
where plAlt (ps,ts) = plOper "/" (plList (map plp ps)) (plList (map plAtom ts))
|
||||||
|
|
||||||
|
class PLPrint a where
|
||||||
|
plp :: a -> String
|
||||||
|
plps :: [a] -> String
|
||||||
|
plps = plList . map plp
|
||||||
|
|
||||||
|
instance PLPrint Char where
|
||||||
|
plp c = plAtom [c]
|
||||||
|
plps s = plAtom s
|
||||||
|
|
||||||
|
instance PLPrint a => PLPrint [a] where
|
||||||
|
plp = plps
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
-- other prolog-printing functions
|
||||||
|
|
||||||
|
plCat :: Int -> String
|
||||||
|
plCat n = plAtom ('c' : show n)
|
||||||
|
|
||||||
|
plFun :: Int -> String
|
||||||
|
plFun n = plAtom ('f' : show n)
|
||||||
|
|
||||||
|
plSeq :: Int -> String
|
||||||
|
plSeq n = plAtom ('s' : show n)
|
||||||
|
|
||||||
|
plHeader :: String -> String
|
||||||
|
plHeader hdr = "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n%% " ++ hdr ++ "\n"
|
||||||
|
|
||||||
|
plFacts :: CId -> String -> Int -> String -> [[String]] -> String
|
||||||
|
plFacts mod pred arity comment facts = "%% " ++ pred ++ comment ++++ clauses
|
||||||
|
where clauses = (if facts == [] then ":- dynamic " ++ pred ++ "/" ++ show arity ++ ".\n"
|
||||||
|
else unlines [mod' ++ plTerm pred args ++ "." | args <- facts])
|
||||||
|
mod' = if mod == wildCId then "" else plp mod ++ ": "
|
||||||
|
|
||||||
|
plTerm :: String -> [String] -> String
|
||||||
|
plTerm fun args = plAtom fun ++ prParenth (prTList ", " args)
|
||||||
|
|
||||||
|
plList :: [String] -> String
|
||||||
|
plList xs = prBracket (prTList "," xs)
|
||||||
|
|
||||||
|
plOper :: String -> String -> String -> String
|
||||||
|
plOper op a b = prParenth (a ++ op ++ b)
|
||||||
|
|
||||||
|
plVar :: String -> String
|
||||||
|
plVar = varPrefix . concatMap changeNonAlphaNum
|
||||||
|
where varPrefix var@(c:_) | isAsciiUpper c || c=='_' = var
|
||||||
|
| otherwise = "_" ++ var
|
||||||
|
changeNonAlphaNum c | isAlphaNumUnderscore c = [c]
|
||||||
|
| otherwise = "_" ++ show (ord c) ++ "_"
|
||||||
|
|
||||||
|
plAtom :: String -> String
|
||||||
|
plAtom "" = "''"
|
||||||
|
plAtom atom@(c:cs) | isAsciiLower c && all isAlphaNumUnderscore cs
|
||||||
|
|| c == '\'' && cs /= "" && last cs == '\'' = atom
|
||||||
|
| otherwise = "'" ++ changeQuote atom ++ "'"
|
||||||
|
where changeQuote ('\'':cs) = '\\' : '\'' : changeQuote cs
|
||||||
|
changeQuote ('\\':cs) = '\\' : '\\' : changeQuote cs
|
||||||
|
changeQuote (c:cs) = c : changeQuote cs
|
||||||
|
changeQuote "" = ""
|
||||||
|
|
||||||
|
isAlphaNumUnderscore :: Char -> Bool
|
||||||
|
isAlphaNumUnderscore c = (isAscii c && isAlphaNum c) || c == '_'
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
-- prolog variables
|
||||||
|
|
||||||
|
createLogicalVariable :: Int -> CId
|
||||||
|
createLogicalVariable n = mkCId (logicalVariablePrefix ++ show n)
|
||||||
|
|
||||||
|
isLogicalVariable :: String -> Bool
|
||||||
|
isLogicalVariable = isPrefixOf logicalVariablePrefix
|
||||||
|
|
||||||
|
logicalVariablePrefix :: String
|
||||||
|
logicalVariablePrefix = "X"
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
-- alpha convert variables to (unique) logical variables
|
||||||
|
-- * this is needed if we want to translate variables to Prolog variables
|
||||||
|
-- * used for abstract syntax, not concrete
|
||||||
|
-- * not (yet?) used for variables bound in pattern equations
|
||||||
|
|
||||||
|
type ConvertEnv = (Int, [(CId,CId)])
|
||||||
|
|
||||||
|
emptyEnv :: ConvertEnv
|
||||||
|
emptyEnv = (0, [])
|
||||||
|
|
||||||
|
class AlphaConvert a where
|
||||||
|
alphaConvert :: ConvertEnv -> a -> (ConvertEnv, a)
|
||||||
|
|
||||||
|
instance AlphaConvert a => AlphaConvert [a] where
|
||||||
|
alphaConvert env [] = (env, [])
|
||||||
|
alphaConvert env (a:as) = (env'', a':as')
|
||||||
|
where (env', a') = alphaConvert env a
|
||||||
|
(env'', as') = alphaConvert env' as
|
||||||
|
|
||||||
|
instance AlphaConvert Type where
|
||||||
|
alphaConvert env@(_,subst) (DTyp hypos cat args)
|
||||||
|
= ((ctr,subst), DTyp hypos' cat args')
|
||||||
|
where (env', hypos') = mapAccumL alphaConvertHypo env hypos
|
||||||
|
((ctr,_), args') = alphaConvert env' args
|
||||||
|
|
||||||
|
alphaConvertHypo env (b,x,typ) = ((ctr+1,(x,x'):subst), (b,x',typ'))
|
||||||
|
where ((ctr,subst), typ') = alphaConvert env typ
|
||||||
|
x' = createLogicalVariable ctr
|
||||||
|
|
||||||
|
instance AlphaConvert Expr where
|
||||||
|
alphaConvert (ctr,subst) (EAbs b x e) = ((ctr',subst), EAbs b x' e')
|
||||||
|
where ((ctr',_), e') = alphaConvert (ctr+1,(x,x'):subst) e
|
||||||
|
x' = createLogicalVariable ctr
|
||||||
|
alphaConvert env (EApp e1 e2) = (env'', EApp e1' e2')
|
||||||
|
where (env', e1') = alphaConvert env e1
|
||||||
|
(env'', e2') = alphaConvert env' e2
|
||||||
|
alphaConvert env expr@(EFun i) = (env, maybe expr EFun (lookup i (snd env)))
|
||||||
|
alphaConvert env expr = (env, expr)
|
||||||
|
|
||||||
|
-- pattern variables are not alpha converted
|
||||||
|
-- (but they probably should be...)
|
||||||
|
instance AlphaConvert Equation where
|
||||||
|
alphaConvert env@(_,subst) (Equ patterns result)
|
||||||
|
= ((ctr,subst), Equ patterns result')
|
||||||
|
where ((ctr,_), result') = alphaConvert env result
|
||||||
122
src/compiler/GF/Compile/PGFtoPython.hs
Normal file
122
src/compiler/GF/Compile/PGFtoPython.hs
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
----------------------------------------------------------------------
|
||||||
|
-- |
|
||||||
|
-- Module : PGFtoPython
|
||||||
|
-- Maintainer : Peter Ljunglöf
|
||||||
|
--
|
||||||
|
-- exports a GF grammar into a Python module
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
|
module GF.Compile.PGFtoPython (pgf2python) where
|
||||||
|
|
||||||
|
import PGF(showCId)
|
||||||
|
import PGF.Internal as M
|
||||||
|
|
||||||
|
import GF.Data.Operations
|
||||||
|
|
||||||
|
import qualified Data.Array.IArray as Array
|
||||||
|
import qualified Data.Set as Set
|
||||||
|
import qualified Data.Map as Map
|
||||||
|
import qualified Data.IntMap as IntMap
|
||||||
|
--import Data.List (intersperse)
|
||||||
|
|
||||||
|
pgf2python :: PGF -> String
|
||||||
|
pgf2python pgf = ("# -*- coding: utf-8 -*-" ++++
|
||||||
|
"# This file was automatically generated by GF" +++++
|
||||||
|
showCId name +++ "=" +++
|
||||||
|
pyDict 1 pyStr id [
|
||||||
|
("flags", pyDict 2 pyCId pyLiteral (Map.assocs (gflags pgf))),
|
||||||
|
("abstract", pyDict 2 pyStr id [
|
||||||
|
("name", pyCId name),
|
||||||
|
("start", pyCId start),
|
||||||
|
("flags", pyDict 3 pyCId pyLiteral (Map.assocs (aflags abs))),
|
||||||
|
("funs", pyDict 3 pyCId pyAbsdef (Map.assocs (funs abs)))
|
||||||
|
]),
|
||||||
|
("concretes", pyDict 2 pyCId pyConcrete (Map.assocs cncs))
|
||||||
|
] ++ "\n")
|
||||||
|
where
|
||||||
|
name = absname pgf
|
||||||
|
start = M.lookStartCat pgf
|
||||||
|
abs = abstract pgf
|
||||||
|
cncs = concretes pgf
|
||||||
|
|
||||||
|
pyAbsdef :: (Type, Int, Maybe ([Equation], [[M.Instr]]), Double) -> String
|
||||||
|
pyAbsdef (typ, _, _, _) = pyTuple 0 id [pyCId cat, pyList 0 pyCId args]
|
||||||
|
where (args, cat) = M.catSkeleton typ
|
||||||
|
|
||||||
|
pyLiteral :: Literal -> String
|
||||||
|
pyLiteral (LStr s) = pyStr s
|
||||||
|
pyLiteral (LInt n) = show n
|
||||||
|
pyLiteral (LFlt d) = show d
|
||||||
|
|
||||||
|
pyConcrete :: Concr -> String
|
||||||
|
pyConcrete cnc = pyDict 3 pyStr id [
|
||||||
|
("flags", pyDict 0 pyCId pyLiteral (Map.assocs (cflags cnc))),
|
||||||
|
("printnames", pyDict 4 pyCId pyStr (Map.assocs (printnames cnc))),
|
||||||
|
("lindefs", pyDict 4 pyCat (pyList 0 pyFun) (IntMap.assocs (lindefs cnc))),
|
||||||
|
("productions", pyDict 4 pyCat pyProds (IntMap.assocs (productions cnc))),
|
||||||
|
("cncfuns", pyDict 4 pyFun pyCncFun (Array.assocs (cncfuns cnc))),
|
||||||
|
("sequences", pyDict 4 pySeq pySymbols (Array.assocs (sequences cnc))),
|
||||||
|
("cnccats", pyDict 4 pyCId pyCncCat (Map.assocs (cnccats cnc))),
|
||||||
|
("size", show (totalCats cnc))
|
||||||
|
]
|
||||||
|
where pyProds prods = pyList 5 pyProduction (Set.toList prods)
|
||||||
|
pyCncCat (CncCat start end _) = pyList 0 pyCat [start..end]
|
||||||
|
pyCncFun (CncFun f lins) = pyTuple 0 id [pyList 0 pySeq (Array.elems lins), pyCId f]
|
||||||
|
pySymbols syms = pyList 0 pySymbol (Array.elems syms)
|
||||||
|
|
||||||
|
pyProduction :: Production -> String
|
||||||
|
pyProduction (PCoerce arg) = pyTuple 0 id [pyStr "", pyList 0 pyCat [arg]]
|
||||||
|
pyProduction (PApply funid args) = pyTuple 0 id [pyFun funid, pyList 0 pyPArg args]
|
||||||
|
where pyPArg (PArg [] fid) = pyCat fid
|
||||||
|
pyPArg (PArg hypos fid) = pyTuple 0 pyCat (fid : map snd hypos)
|
||||||
|
|
||||||
|
pySymbol :: Symbol -> String
|
||||||
|
pySymbol (SymCat n l) = pyTuple 0 show [n, l]
|
||||||
|
pySymbol (SymLit n l) = pyDict 0 pyStr id [("lit", pyTuple 0 show [n, l])]
|
||||||
|
pySymbol (SymVar n l) = pyDict 0 pyStr id [("var", pyTuple 0 show [n, l])]
|
||||||
|
pySymbol (SymKS t) = pyStr t
|
||||||
|
pySymbol (SymKP ts alts) = pyDict 0 pyStr id [("pre", pyList 0 pySymbol ts), ("alts", pyList 0 alt2py alts)]
|
||||||
|
where alt2py (ps,ts) = pyTuple 0 (pyList 0 pyStr) [map pySymbol ps, ts]
|
||||||
|
pySymbol SymBIND = pyStr "&+"
|
||||||
|
pySymbol SymSOFT_BIND = pyStr "&+"
|
||||||
|
pySymbol SymSOFT_SPACE = pyStr "&+"
|
||||||
|
pySymbol SymCAPIT = pyStr "&|"
|
||||||
|
pySymbol SymALL_CAPIT = pyStr "&|"
|
||||||
|
pySymbol SymNE = pyDict 0 pyStr id [("nonExist", pyTuple 0 id [])]
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
-- python helpers
|
||||||
|
|
||||||
|
pyDict :: Int -> (k -> String) -> (v -> String) -> [(k, v)] -> String
|
||||||
|
pyDict n pk pv [] = "{}"
|
||||||
|
pyDict n pk pv kvlist = prCurly (pyIndent n ++ prTList ("," ++ pyIndent n) (map pyKV kvlist) ++ pyIndent n)
|
||||||
|
where pyKV (k, v) = pk k ++ ":" ++ pv v
|
||||||
|
|
||||||
|
pyList :: Int -> (v -> String) -> [v] -> String
|
||||||
|
pyList n pv [] = "[]"
|
||||||
|
pyList n pv xs = prBracket (pyIndent n ++ prTList ("," ++ pyIndent n) (map pv xs) ++ pyIndent n)
|
||||||
|
|
||||||
|
pyTuple :: Int -> (v -> String) -> [v] -> String
|
||||||
|
pyTuple n pv [] = "()"
|
||||||
|
pyTuple n pv [x] = prParenth (pyIndent n ++ pv x ++ "," ++ pyIndent n)
|
||||||
|
pyTuple n pv xs = prParenth (pyIndent n ++ prTList ("," ++ pyIndent n) (map pv xs) ++ pyIndent n)
|
||||||
|
|
||||||
|
pyCat :: Int -> String
|
||||||
|
pyCat n = pyStr ('C' : show n)
|
||||||
|
|
||||||
|
pyFun :: Int -> String
|
||||||
|
pyFun n = pyStr ('F' : show n)
|
||||||
|
|
||||||
|
pySeq :: Int -> String
|
||||||
|
pySeq n = pyStr ('S' : show n)
|
||||||
|
|
||||||
|
pyStr :: String -> String
|
||||||
|
pyStr s = 'u' : prQuotedString s
|
||||||
|
|
||||||
|
pyCId :: CId -> String
|
||||||
|
pyCId = pyStr . showCId
|
||||||
|
|
||||||
|
pyIndent :: Int -> String
|
||||||
|
pyIndent n | n > 0 = "\n" ++ replicate n ' '
|
||||||
|
| otherwise = ""
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
-- Stability : (stable)
|
-- Stability : (stable)
|
||||||
-- Portability : (portable)
|
-- Portability : (portable)
|
||||||
--
|
--
|
||||||
-- > CVS $Date: 2005/05/30 18:39:44 $
|
-- > CVS $Date: 2005/05/30 18:39:44 $
|
||||||
-- > CVS $Author: aarne $
|
-- > CVS $Author: aarne $
|
||||||
-- > CVS $Revision: 1.19 $
|
-- > CVS $Revision: 1.19 $
|
||||||
--
|
--
|
||||||
@@ -23,9 +23,9 @@
|
|||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
|
|
||||||
module GF.Compile.Rename (
|
module GF.Compile.Rename (
|
||||||
renameSourceTerm,
|
renameSourceTerm,
|
||||||
renameModule
|
renameModule
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import GF.Infra.Ident
|
import GF.Infra.Ident
|
||||||
import GF.Infra.CheckM
|
import GF.Infra.CheckM
|
||||||
@@ -39,7 +39,6 @@ import GF.Data.Operations
|
|||||||
|
|
||||||
import Control.Monad
|
import Control.Monad
|
||||||
import Data.List (nub,(\\))
|
import Data.List (nub,(\\))
|
||||||
import qualified Data.List as L
|
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
import Data.Maybe(mapMaybe)
|
import Data.Maybe(mapMaybe)
|
||||||
import GF.Text.Pretty
|
import GF.Text.Pretty
|
||||||
@@ -68,7 +67,7 @@ renameIdentTerm env = accumulateError (renameIdentTerm' env)
|
|||||||
|
|
||||||
-- Fails immediately on error, makes it possible to try other possibilities
|
-- Fails immediately on error, makes it possible to try other possibilities
|
||||||
renameIdentTerm' :: Status -> Term -> Check Term
|
renameIdentTerm' :: Status -> Term -> Check Term
|
||||||
renameIdentTerm' env@(act,imps) t0 =
|
renameIdentTerm' env@(act,imps) t0 =
|
||||||
case t0 of
|
case t0 of
|
||||||
Vr c -> ident predefAbs c
|
Vr c -> ident predefAbs c
|
||||||
Cn c -> ident (\_ s -> checkError s) c
|
Cn c -> ident (\_ s -> checkError s) c
|
||||||
@@ -85,8 +84,8 @@ renameIdentTerm' env@(act,imps) t0 =
|
|||||||
_ -> return t0
|
_ -> return t0
|
||||||
where
|
where
|
||||||
opens = [st | (OSimple _,st) <- imps]
|
opens = [st | (OSimple _,st) <- imps]
|
||||||
qualifs = [(m, st) | (OQualif m _, st) <- imps] ++
|
qualifs = [(m, st) | (OQualif m _, st) <- imps] ++
|
||||||
[(m, st) | (OQualif _ m, st) <- imps] ++
|
[(m, st) | (OQualif _ m, st) <- imps] ++
|
||||||
[(m, st) | (OSimple m, st) <- imps] -- qualif is always possible
|
[(m, st) | (OSimple m, st) <- imps] -- qualif is always possible
|
||||||
|
|
||||||
-- this facility is mainly for BWC with GF1: you need not import PredefAbs
|
-- this facility is mainly for BWC with GF1: you need not import PredefAbs
|
||||||
@@ -94,7 +93,7 @@ renameIdentTerm' env@(act,imps) t0 =
|
|||||||
| isPredefCat c = return (Q (cPredefAbs,c))
|
| isPredefCat c = return (Q (cPredefAbs,c))
|
||||||
| otherwise = checkError s
|
| otherwise = checkError s
|
||||||
|
|
||||||
ident alt c =
|
ident alt c =
|
||||||
case Map.lookup c act of
|
case Map.lookup c act of
|
||||||
Just f -> return (f c)
|
Just f -> return (f c)
|
||||||
_ -> case mapMaybe (Map.lookup c) opens of
|
_ -> case mapMaybe (Map.lookup c) opens of
|
||||||
@@ -106,26 +105,7 @@ renameIdentTerm' env@(act,imps) t0 =
|
|||||||
ts@(t:_) -> do checkWarn ("atomic term" <+> ppTerm Qualified 0 t0 $$
|
ts@(t:_) -> do checkWarn ("atomic term" <+> ppTerm Qualified 0 t0 $$
|
||||||
"conflict" <+> hsep (punctuate ',' (map (ppTerm Qualified 0) ts)) $$
|
"conflict" <+> hsep (punctuate ',' (map (ppTerm Qualified 0) ts)) $$
|
||||||
"given" <+> fsep (punctuate ',' (map fst qualifs)))
|
"given" <+> fsep (punctuate ',' (map fst qualifs)))
|
||||||
return (bestTerm ts) -- Heuristic for resource grammar. Returns t for all others.
|
return t
|
||||||
where
|
|
||||||
-- Hotfix for https://github.com/GrammaticalFramework/gf-core/issues/56
|
|
||||||
-- Real bug is probably somewhere deeper in recognising excluded functions. /IL 2020-06-06
|
|
||||||
notFromCommonModule :: Term -> Bool
|
|
||||||
notFromCommonModule term =
|
|
||||||
let t = render $ ppTerm Qualified 0 term :: String
|
|
||||||
in not $ any (\moduleName -> moduleName `L.isPrefixOf` t)
|
|
||||||
["CommonX", "ConstructX", "ExtendFunctor"
|
|
||||||
,"MarkHTMLX", "ParamX", "TenseX", "TextX"]
|
|
||||||
|
|
||||||
-- If one of the terms comes from the common modules,
|
|
||||||
-- we choose the other one, because that's defined in the grammar.
|
|
||||||
bestTerm :: [Term] -> Term
|
|
||||||
bestTerm [] = error "constant not found" -- not reached: bestTerm is only called for case ts@(t:_)
|
|
||||||
bestTerm ts@(t:_) =
|
|
||||||
let notCommon = [t | t <- ts, notFromCommonModule t]
|
|
||||||
in case notCommon of
|
|
||||||
[] -> t -- All terms are from common modules, return first of original list
|
|
||||||
(u:_) -> u -- ≥1 terms are not from common modules, return first of those
|
|
||||||
|
|
||||||
info2status :: Maybe ModuleName -> Ident -> Info -> StatusInfo
|
info2status :: Maybe ModuleName -> Ident -> Info -> StatusInfo
|
||||||
info2status mq c i = case i of
|
info2status mq c i = case i of
|
||||||
@@ -157,7 +137,7 @@ modInfo2status (o,mo) = (o,tree2status o (jments mo))
|
|||||||
self2status :: ModuleName -> ModuleInfo -> StatusMap
|
self2status :: ModuleName -> ModuleInfo -> StatusMap
|
||||||
self2status c m = Map.mapWithKey (info2status (Just c)) (jments m)
|
self2status c m = Map.mapWithKey (info2status (Just c)) (jments m)
|
||||||
|
|
||||||
|
|
||||||
renameInfo :: FilePath -> Status -> Module -> Ident -> Info -> Check Info
|
renameInfo :: FilePath -> Status -> Module -> Ident -> Info -> Check Info
|
||||||
renameInfo cwd status (m,mi) i info =
|
renameInfo cwd status (m,mi) i info =
|
||||||
case info of
|
case info of
|
||||||
@@ -208,7 +188,7 @@ renameTerm env vars = ren vars where
|
|||||||
Abs b x t -> liftM (Abs b x) (ren (x:vs) t)
|
Abs b x t -> liftM (Abs b x) (ren (x:vs) t)
|
||||||
Prod bt x a b -> liftM2 (Prod bt x) (ren vs a) (ren (x:vs) b)
|
Prod bt x a b -> liftM2 (Prod bt x) (ren vs a) (ren (x:vs) b)
|
||||||
Typed a b -> liftM2 Typed (ren vs a) (ren vs b)
|
Typed a b -> liftM2 Typed (ren vs a) (ren vs b)
|
||||||
Vr x
|
Vr x
|
||||||
| elem x vs -> return trm
|
| elem x vs -> return trm
|
||||||
| otherwise -> renid trm
|
| otherwise -> renid trm
|
||||||
Cn _ -> renid trm
|
Cn _ -> renid trm
|
||||||
@@ -219,7 +199,7 @@ renameTerm env vars = ren vars where
|
|||||||
i' <- case i of
|
i' <- case i of
|
||||||
TTyped ty -> liftM TTyped $ ren vs ty -- the only annotation in source
|
TTyped ty -> liftM TTyped $ ren vs ty -- the only annotation in source
|
||||||
_ -> return i
|
_ -> return i
|
||||||
liftM (T i') $ mapM (renCase vs) cs
|
liftM (T i') $ mapM (renCase vs) cs
|
||||||
|
|
||||||
Let (x,(m,a)) b -> do
|
Let (x,(m,a)) b -> do
|
||||||
m' <- case m of
|
m' <- case m of
|
||||||
@@ -229,7 +209,7 @@ renameTerm env vars = ren vars where
|
|||||||
b' <- ren (x:vs) b
|
b' <- ren (x:vs) b
|
||||||
return $ Let (x,(m',a')) b'
|
return $ Let (x,(m',a')) b'
|
||||||
|
|
||||||
P t@(Vr r) l -- Here we have $r.l$ and this is ambiguous it could be either
|
P t@(Vr r) l -- Here we have $r.l$ and this is ambiguous it could be either
|
||||||
-- record projection from variable or constant $r$ or qualified expression with module $r$
|
-- record projection from variable or constant $r$ or qualified expression with module $r$
|
||||||
| elem r vs -> return trm -- try var proj first ..
|
| elem r vs -> return trm -- try var proj first ..
|
||||||
| otherwise -> checks [ renid' (Q (MN r,label2ident l)) -- .. and qualified expression second.
|
| otherwise -> checks [ renid' (Q (MN r,label2ident l)) -- .. and qualified expression second.
|
||||||
@@ -331,7 +311,7 @@ renamePattern env patt =
|
|||||||
renameContext :: Status -> Context -> Check Context
|
renameContext :: Status -> Context -> Check Context
|
||||||
renameContext b = renc [] where
|
renameContext b = renc [] where
|
||||||
renc vs cont = case cont of
|
renc vs cont = case cont of
|
||||||
(bt,x,t) : xts
|
(bt,x,t) : xts
|
||||||
| isWildIdent x -> do
|
| isWildIdent x -> do
|
||||||
t' <- ren vs t
|
t' <- ren vs t
|
||||||
xts' <- renc vs xts
|
xts' <- renc vs xts
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ module GF.Compile.ToAPI
|
|||||||
(stringToAPI,exprToAPI)
|
(stringToAPI,exprToAPI)
|
||||||
where
|
where
|
||||||
|
|
||||||
import PGF2
|
import PGF.Internal
|
||||||
|
import PGF(showCId)
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
--import System.IO
|
--import System.IO
|
||||||
--import Control.Monad
|
--import Control.Monad
|
||||||
@@ -46,12 +47,12 @@ exprToFunc :: Expr -> APIfunc
|
|||||||
exprToFunc expr =
|
exprToFunc expr =
|
||||||
case unApp expr of
|
case unApp expr of
|
||||||
Just (cid,l) ->
|
Just (cid,l) ->
|
||||||
case Map.lookup cid syntaxFuncs of
|
case Map.lookup (showCId cid) syntaxFuncs of
|
||||||
Just sig -> mkAPI True (fst sig,expr)
|
Just sig -> mkAPI True (fst sig,expr)
|
||||||
_ -> case l of
|
_ -> case l of
|
||||||
[] -> BasicFunc cid
|
[] -> BasicFunc (showCId cid)
|
||||||
_ -> let es = map exprToFunc l
|
_ -> let es = map exprToFunc l
|
||||||
in AppFunc cid es
|
in AppFunc (showCId cid) es
|
||||||
_ -> BasicFunc (showExpr [] expr)
|
_ -> BasicFunc (showExpr [] expr)
|
||||||
|
|
||||||
|
|
||||||
@@ -68,8 +69,8 @@ mkAPI opt (ty,expr) =
|
|||||||
where
|
where
|
||||||
rephraseSentence ty expr =
|
rephraseSentence ty expr =
|
||||||
case unApp expr of
|
case unApp expr of
|
||||||
Just (cid,es) -> if isPrefixOf "Use" cid then
|
Just (cid,es) -> if isPrefixOf "Use" (showCId cid) then
|
||||||
let newCat = drop 3 cid
|
let newCat = drop 3 (showCId cid)
|
||||||
afClause = mkAPI True (newCat, es !! 2)
|
afClause = mkAPI True (newCat, es !! 2)
|
||||||
afPol = mkAPI True ("Pol",es !! 1)
|
afPol = mkAPI True ("Pol",es !! 1)
|
||||||
lTense = mkAPI True ("Temp", head es)
|
lTense = mkAPI True ("Temp", head es)
|
||||||
@@ -97,9 +98,9 @@ mkAPI opt (ty,expr) =
|
|||||||
computeAPI :: (String,Expr) -> APIfunc
|
computeAPI :: (String,Expr) -> APIfunc
|
||||||
computeAPI (ty,expr) =
|
computeAPI (ty,expr) =
|
||||||
case (unApp expr) of
|
case (unApp expr) of
|
||||||
Just (cid,[]) -> getSimpCat cid ty
|
Just (cid,[]) -> getSimpCat (showCId cid) ty
|
||||||
Just (cid,es) ->
|
Just (cid,es) ->
|
||||||
let p = specFunction cid es
|
let p = specFunction (showCId cid) es
|
||||||
in if isJust p then fromJust p
|
in if isJust p then fromJust p
|
||||||
else case Map.lookup (show cid) syntaxFuncs of
|
else case Map.lookup (show cid) syntaxFuncs of
|
||||||
Nothing -> exprToFunc expr
|
Nothing -> exprToFunc expr
|
||||||
@@ -146,23 +147,23 @@ optimize expr = optimizeNP expr
|
|||||||
optimizeNP expr =
|
optimizeNP expr =
|
||||||
case unApp expr of
|
case unApp expr of
|
||||||
Just (cid,es) ->
|
Just (cid,es) ->
|
||||||
if cid == "MassNP" then let afs = nounAsCN (head es)
|
if showCId cid == "MassNP" then let afs = nounAsCN (head es)
|
||||||
in AppFunc "mkNP" [afs]
|
in AppFunc "mkNP" [afs]
|
||||||
else if cid == "DetCN" then let quants = quantAsDet (head es)
|
else if showCId cid == "DetCN" then let quants = quantAsDet (head es)
|
||||||
ns = nounAsCN (head $ tail es)
|
ns = nounAsCN (head $ tail es)
|
||||||
in AppFunc "mkNP" (quants ++ [ns])
|
in AppFunc "mkNP" (quants ++ [ns])
|
||||||
else mkAPI False ("NP",expr)
|
else mkAPI False ("NP",expr)
|
||||||
_ -> error $ "incorrect expression " ++ (showExpr [] expr)
|
_ -> error $ "incorrect expression " ++ (showExpr [] expr)
|
||||||
where
|
where
|
||||||
nounAsCN expr =
|
nounAsCN expr =
|
||||||
case unApp expr of
|
case unApp expr of
|
||||||
Just (cid,es) -> if cid == "UseN" then (mkAPI False) ("N",head es)
|
Just (cid,es) -> if showCId cid == "UseN" then (mkAPI False) ("N",head es)
|
||||||
else (mkAPI False) ("CN",expr)
|
else (mkAPI False) ("CN",expr)
|
||||||
_ -> error $ "incorrect expression "++ (showExpr [] expr)
|
_ -> error $ "incorrect expression "++ (showExpr [] expr)
|
||||||
|
|
||||||
quantAsDet expr =
|
quantAsDet expr =
|
||||||
case unApp expr of
|
case unApp expr of
|
||||||
Just (cid,es) -> if cid == "DetQuant" then map (mkAPI False) [("Quant", head es),("Num",head $ tail es)]
|
Just (cid,es) -> if showCId cid == "DetQuant" then map (mkAPI False) [("Quant", head es),("Num",head $ tail es)]
|
||||||
else [mkAPI False ("Det",expr)]
|
else [mkAPI False ("Det",expr)]
|
||||||
|
|
||||||
_ -> error $ "incorrect expression "++ (showExpr [] expr)
|
_ -> error $ "incorrect expression "++ (showExpr [] expr)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
-- Stability : (stable)
|
-- Stability : (stable)
|
||||||
-- Portability : (portable)
|
-- Portability : (portable)
|
||||||
--
|
--
|
||||||
-- > CVS $Date: 2005/09/15 16:22:02 $
|
-- > CVS $Date: 2005/09/15 16:22:02 $
|
||||||
-- > CVS $Author: aarne $
|
-- > CVS $Author: aarne $
|
||||||
-- > CVS $Revision: 1.16 $
|
-- > CVS $Revision: 1.16 $
|
||||||
--
|
--
|
||||||
@@ -13,11 +13,11 @@
|
|||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
|
|
||||||
module GF.Compile.TypeCheck.Abstract (-- * top-level type checking functions; TC should not be called directly.
|
module GF.Compile.TypeCheck.Abstract (-- * top-level type checking functions; TC should not be called directly.
|
||||||
checkContext,
|
checkContext,
|
||||||
checkTyp,
|
checkTyp,
|
||||||
checkDef,
|
checkDef,
|
||||||
checkConstrs,
|
checkConstrs,
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import GF.Data.Operations
|
import GF.Data.Operations
|
||||||
|
|
||||||
@@ -33,8 +33,8 @@ import GF.Text.Pretty
|
|||||||
--import Control.Monad (foldM, liftM, liftM2)
|
--import Control.Monad (foldM, liftM, liftM2)
|
||||||
|
|
||||||
-- | invariant way of creating TCEnv from context
|
-- | invariant way of creating TCEnv from context
|
||||||
initTCEnv gamma =
|
initTCEnv gamma =
|
||||||
(length gamma,[(x,VGen i x) | ((x,_),i) <- zip gamma [0..]], gamma)
|
(length gamma,[(x,VGen i x) | ((x,_),i) <- zip gamma [0..]], gamma)
|
||||||
|
|
||||||
-- interface to TC type checker
|
-- interface to TC type checker
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
{-# LANGUAGE PatternGuards #-}
|
{-# LANGUAGE PatternGuards #-}
|
||||||
module GF.Compile.TypeCheck.Concrete( checkLType, inferLType, computeLType, ppType ) where
|
module GF.Compile.TypeCheck.Concrete( {-checkLType, inferLType, computeLType, ppType-} ) where
|
||||||
import Prelude hiding ((<>)) -- GHC 8.4.1 clash with Text.PrettyPrint
|
{-
|
||||||
|
|
||||||
import GF.Infra.CheckM
|
import GF.Infra.CheckM
|
||||||
import GF.Data.Operations
|
import GF.Data.Operations
|
||||||
|
|
||||||
@@ -23,16 +22,10 @@ computeLType gr g0 t = comp (reverse [(b,x, Vr x) | (b,x,_) <- g0] ++ g0) t
|
|||||||
_ | Just _ <- isTypeInts ty -> return ty ---- shouldn't be needed
|
_ | Just _ <- isTypeInts ty -> return ty ---- shouldn't be needed
|
||||||
| isPredefConstant ty -> return ty ---- shouldn't be needed
|
| isPredefConstant ty -> return ty ---- shouldn't be needed
|
||||||
|
|
||||||
Q (m,ident) -> checkIn ("module" <+> m) $ do
|
Q (m,ident) -> checkIn (text "module" <+> ppIdent m) $ do
|
||||||
ty' <- lookupResDef gr (m,ident)
|
ty' <- lookupResDef gr (m,ident)
|
||||||
if ty' == ty then return ty else comp g ty' --- is this necessary to test?
|
if ty' == ty then return ty else comp g ty' --- is this necessary to test?
|
||||||
|
|
||||||
AdHocOverload ts -> do
|
|
||||||
over <- getOverload gr g (Just typeType) t
|
|
||||||
case over of
|
|
||||||
Just (tr,_) -> return tr
|
|
||||||
_ -> checkError ("unresolved overloading of constants" <+> ppTerm Qualified 0 t)
|
|
||||||
|
|
||||||
Vr ident -> checkLookup ident g -- never needed to compute!
|
Vr ident -> checkLookup ident g -- never needed to compute!
|
||||||
|
|
||||||
App f a -> do
|
App f a -> do
|
||||||
@@ -69,6 +62,7 @@ computeLType gr g0 t = comp (reverse [(b,x, Vr x) | (b,x,_) <- g0] ++ g0) t
|
|||||||
lockRecType c t' ---- locking to be removed AR 20/6/2009
|
lockRecType c t' ---- locking to be removed AR 20/6/2009
|
||||||
|
|
||||||
_ | ty == typeTok -> return typeStr
|
_ | ty == typeTok -> return typeStr
|
||||||
|
_ | isPredefConstant ty -> return ty
|
||||||
|
|
||||||
_ -> composOp (comp g) ty
|
_ -> composOp (comp g) ty
|
||||||
|
|
||||||
@@ -79,26 +73,26 @@ inferLType gr g trm = case trm of
|
|||||||
|
|
||||||
Q (m,ident) | isPredef m -> termWith trm $ case typPredefined ident of
|
Q (m,ident) | isPredef m -> termWith trm $ case typPredefined ident of
|
||||||
Just ty -> return ty
|
Just ty -> return ty
|
||||||
Nothing -> checkError ("unknown in Predef:" <+> ident)
|
Nothing -> checkError (text "unknown in Predef:" <+> ppIdent ident)
|
||||||
|
|
||||||
Q ident -> checks [
|
Q ident -> checks [
|
||||||
termWith trm $ lookupResType gr ident >>= computeLType gr g
|
termWith trm $ lookupResType gr ident >>= computeLType gr g
|
||||||
,
|
,
|
||||||
lookupResDef gr ident >>= inferLType gr g
|
lookupResDef gr ident >>= inferLType gr g
|
||||||
,
|
,
|
||||||
checkError ("cannot infer type of constant" <+> ppTerm Unqualified 0 trm)
|
checkError (text "cannot infer type of constant" <+> ppTerm Unqualified 0 trm)
|
||||||
]
|
]
|
||||||
|
|
||||||
QC (m,ident) | isPredef m -> termWith trm $ case typPredefined ident of
|
QC (m,ident) | isPredef m -> termWith trm $ case typPredefined ident of
|
||||||
Just ty -> return ty
|
Just ty -> return ty
|
||||||
Nothing -> checkError ("unknown in Predef:" <+> ident)
|
Nothing -> checkError (text "unknown in Predef:" <+> ppIdent ident)
|
||||||
|
|
||||||
QC ident -> checks [
|
QC ident -> checks [
|
||||||
termWith trm $ lookupResType gr ident >>= computeLType gr g
|
termWith trm $ lookupResType gr ident >>= computeLType gr g
|
||||||
,
|
,
|
||||||
lookupResDef gr ident >>= inferLType gr g
|
lookupResDef gr ident >>= inferLType gr g
|
||||||
,
|
,
|
||||||
checkError ("cannot infer type of canonical constant" <+> ppTerm Unqualified 0 trm)
|
checkError (text "cannot infer type of canonical constant" <+> ppTerm Unqualified 0 trm)
|
||||||
]
|
]
|
||||||
|
|
||||||
Vr ident -> termWith trm $ checkLookup ident g
|
Vr ident -> termWith trm $ checkLookup ident g
|
||||||
@@ -106,12 +100,7 @@ inferLType gr g trm = case trm of
|
|||||||
Typed e t -> do
|
Typed e t -> do
|
||||||
t' <- computeLType gr g t
|
t' <- computeLType gr g t
|
||||||
checkLType gr g e t'
|
checkLType gr g e t'
|
||||||
|
return (e,t')
|
||||||
AdHocOverload ts -> do
|
|
||||||
over <- getOverload gr g Nothing trm
|
|
||||||
case over of
|
|
||||||
Just trty -> return trty
|
|
||||||
_ -> checkError ("unresolved overloading of constants" <+> ppTerm Qualified 0 trm)
|
|
||||||
|
|
||||||
App f a -> do
|
App f a -> do
|
||||||
over <- getOverload gr g Nothing trm
|
over <- getOverload gr g Nothing trm
|
||||||
@@ -121,17 +110,13 @@ inferLType gr g trm = case trm of
|
|||||||
(f',fty) <- inferLType gr g f
|
(f',fty) <- inferLType gr g f
|
||||||
fty' <- computeLType gr g fty
|
fty' <- computeLType gr g fty
|
||||||
case fty' of
|
case fty' of
|
||||||
Prod bt z arg val -> do
|
Prod bt z arg val -> do
|
||||||
a' <- justCheck g a arg
|
a' <- justCheck g a arg
|
||||||
ty <- if isWildIdent z
|
ty <- if isWildIdent z
|
||||||
then return val
|
then return val
|
||||||
else substituteLType [(bt,z,a')] val
|
else substituteLType [(bt,z,a')] val
|
||||||
return (App f' a',ty)
|
return (App f' a',ty)
|
||||||
_ ->
|
_ -> checkError (text "A function type is expected for" <+> ppTerm Unqualified 0 f <+> text "instead of type" <+> ppType fty)
|
||||||
let term = ppTerm Unqualified 0 f
|
|
||||||
funName = pp . head . words .render $ term
|
|
||||||
in checkError ("A function type is expected for" <+> term <+> "instead of type" <+> ppType fty $$
|
|
||||||
"\n ** Maybe you gave too many arguments to" <+> funName <+> "\n")
|
|
||||||
|
|
||||||
S f x -> do
|
S f x -> do
|
||||||
(f', fty) <- inferLType gr g f
|
(f', fty) <- inferLType gr g f
|
||||||
@@ -139,7 +124,7 @@ inferLType gr g trm = case trm of
|
|||||||
Table arg val -> do
|
Table arg val -> do
|
||||||
x'<- justCheck g x arg
|
x'<- justCheck g x arg
|
||||||
return (S f' x', val)
|
return (S f' x', val)
|
||||||
_ -> checkError ("table lintype expected for the table in" $$ nest 2 (ppTerm Unqualified 0 trm))
|
_ -> checkError (text "table lintype expected for the table in" $$ nest 2 (ppTerm Unqualified 0 trm))
|
||||||
|
|
||||||
P t i -> do
|
P t i -> do
|
||||||
(t',ty) <- inferLType gr g t --- ??
|
(t',ty) <- inferLType gr g t --- ??
|
||||||
@@ -147,16 +132,16 @@ inferLType gr g trm = case trm of
|
|||||||
let tr2 = P t' i
|
let tr2 = P t' i
|
||||||
termWith tr2 $ case ty' of
|
termWith tr2 $ case ty' of
|
||||||
RecType ts -> case lookup i ts of
|
RecType ts -> case lookup i ts of
|
||||||
Nothing -> checkError ("unknown label" <+> i <+> "in" $$ nest 2 (ppTerm Unqualified 0 ty'))
|
Nothing -> checkError (text "unknown label" <+> ppLabel i <+> text "in" $$ nest 2 (ppTerm Unqualified 0 ty'))
|
||||||
Just x -> return x
|
Just x -> return x
|
||||||
_ -> checkError ("record type expected for:" <+> ppTerm Unqualified 0 t $$
|
_ -> checkError (text "record type expected for:" <+> ppTerm Unqualified 0 t $$
|
||||||
" instead of the inferred:" <+> ppTerm Unqualified 0 ty')
|
text " instead of the inferred:" <+> ppTerm Unqualified 0 ty')
|
||||||
|
|
||||||
R r -> do
|
R r -> do
|
||||||
let (ls,fs) = unzip r
|
let (ls,fs) = unzip r
|
||||||
fsts <- mapM inferM fs
|
fsts <- mapM inferM fs
|
||||||
let ts = [ty | (Just ty,_) <- fsts]
|
let ts = [ty | (Just ty,_) <- fsts]
|
||||||
checkCond ("cannot infer type of record" $$ nest 2 (ppTerm Unqualified 0 trm)) (length ts == length fsts)
|
checkCond (text "cannot infer type of record" $$ nest 2 (ppTerm Unqualified 0 trm)) (length ts == length fsts)
|
||||||
return $ (R (zip ls fsts), RecType (zip ls ts))
|
return $ (R (zip ls fsts), RecType (zip ls ts))
|
||||||
|
|
||||||
T (TTyped arg) pts -> do
|
T (TTyped arg) pts -> do
|
||||||
@@ -167,10 +152,10 @@ inferLType gr g trm = case trm of
|
|||||||
checkLType gr g trm (Table arg val)
|
checkLType gr g trm (Table arg val)
|
||||||
T ti pts -> do -- tries to guess: good in oper type inference
|
T ti pts -> do -- tries to guess: good in oper type inference
|
||||||
let pts' = [pt | pt@(p,_) <- pts, isConstPatt p]
|
let pts' = [pt | pt@(p,_) <- pts, isConstPatt p]
|
||||||
case pts' of
|
case pts' of
|
||||||
[] -> checkError ("cannot infer table type of" <+> ppTerm Unqualified 0 trm)
|
[] -> checkError (text "cannot infer table type of" <+> ppTerm Unqualified 0 trm)
|
||||||
---- PInt k : _ -> return $ Ints $ max [i | PInt i <- pts']
|
---- PInt k : _ -> return $ Ints $ max [i | PInt i <- pts']
|
||||||
_ -> do
|
_ -> do
|
||||||
(arg,val) <- checks $ map (inferCase Nothing) pts'
|
(arg,val) <- checks $ map (inferCase Nothing) pts'
|
||||||
checkLType gr g trm (Table arg val)
|
checkLType gr g trm (Table arg val)
|
||||||
V arg pts -> do
|
V arg pts -> do
|
||||||
@@ -181,9 +166,9 @@ inferLType gr g trm = case trm of
|
|||||||
K s -> do
|
K s -> do
|
||||||
if elem ' ' s
|
if elem ' ' s
|
||||||
then do
|
then do
|
||||||
let ss = foldr C Empty (map K (words s))
|
let ss = foldr C Empty (map K (words s))
|
||||||
----- removed irritating warning AR 24/5/2008
|
----- removed irritating warning AR 24/5/2008
|
||||||
----- checkWarn ("token \"" ++ s ++
|
----- checkWarn ("token \"" ++ s ++
|
||||||
----- "\" converted to token list" ++ prt ss)
|
----- "\" converted to token list" ++ prt ss)
|
||||||
return (ss, typeStr)
|
return (ss, typeStr)
|
||||||
else return (trm, typeStr)
|
else return (trm, typeStr)
|
||||||
@@ -194,56 +179,50 @@ inferLType gr g trm = case trm of
|
|||||||
|
|
||||||
Empty -> return (trm, typeStr)
|
Empty -> return (trm, typeStr)
|
||||||
|
|
||||||
C s1 s2 ->
|
C s1 s2 ->
|
||||||
check2 (flip (justCheck g) typeStr) C s1 s2 typeStr
|
check2 (flip (justCheck g) typeStr) C s1 s2 typeStr
|
||||||
|
|
||||||
Glue s1 s2 ->
|
Glue s1 s2 ->
|
||||||
check2 (flip (justCheck g) typeStr) Glue s1 s2 typeStr ---- typeTok
|
check2 (flip (justCheck g) typeStr) Glue s1 s2 typeStr ---- typeTok
|
||||||
|
|
||||||
---- hack from Rename.identRenameTerm, to live with files with naming conflicts 18/6/2007
|
---- hack from Rename.identRenameTerm, to live with files with naming conflicts 18/6/2007
|
||||||
Strs (Cn c : ts) | c == cConflict -> do
|
Strs (Cn c : ts) | c == cConflict -> do
|
||||||
checkWarn ("unresolved constant, could be any of" <+> hcat (map (ppTerm Unqualified 0) ts))
|
checkWarn (text "unresolved constant, could be any of" <+> hcat (map (ppTerm Unqualified 0) ts))
|
||||||
inferLType gr g (head ts)
|
inferLType gr g (head ts)
|
||||||
|
|
||||||
Strs ts -> do
|
Strs ts -> do
|
||||||
ts' <- mapM (\t -> justCheck g t typeStr) ts
|
ts' <- mapM (\t -> justCheck g t typeStr) ts
|
||||||
return (Strs ts', typeStrs)
|
return (Strs ts', typeStrs)
|
||||||
|
|
||||||
Alts t aa -> do
|
Alts t aa -> do
|
||||||
t' <- justCheck g t typeStr
|
t' <- justCheck g t typeStr
|
||||||
aa' <- flip mapM aa (\ (c,v) -> do
|
aa' <- flip mapM aa (\ (c,v) -> do
|
||||||
c' <- justCheck g c typeStr
|
c' <- justCheck g c typeStr
|
||||||
v' <- checks $ map (justCheck g v) [typeStrs, EPattType typeStr]
|
v' <- checks $ map (justCheck g v) [typeStrs, EPattType typeStr]
|
||||||
return (c',v'))
|
return (c',v'))
|
||||||
return (Alts t' aa', typeStr)
|
return (Alts t' aa', typeStr)
|
||||||
|
|
||||||
RecType r -> do
|
RecType r -> do
|
||||||
let (ls,ts) = unzip r
|
let (ls,ts) = unzip r
|
||||||
ts' <- mapM (flip (justCheck g) typeType) ts
|
ts' <- mapM (flip (justCheck g) typeType) ts
|
||||||
return (RecType (zip ls ts'), typeType)
|
return (RecType (zip ls ts'), typeType)
|
||||||
|
|
||||||
ExtR r s -> do
|
ExtR r s -> do
|
||||||
|
(r',rT) <- inferLType gr g r
|
||||||
--- over <- getOverload gr g Nothing r
|
|
||||||
--- let r1 = maybe r fst over
|
|
||||||
let r1 = r ---
|
|
||||||
|
|
||||||
(r',rT) <- inferLType gr g r1
|
|
||||||
rT' <- computeLType gr g rT
|
rT' <- computeLType gr g rT
|
||||||
|
|
||||||
(s',sT) <- inferLType gr g s
|
(s',sT) <- inferLType gr g s
|
||||||
sT' <- computeLType gr g sT
|
sT' <- computeLType gr g sT
|
||||||
|
|
||||||
let trm' = ExtR r' s'
|
let trm' = ExtR r' s'
|
||||||
|
---- trm' <- plusRecord r' s'
|
||||||
case (rT', sT') of
|
case (rT', sT') of
|
||||||
(RecType rs, RecType ss) -> do
|
(RecType rs, RecType ss) -> do
|
||||||
let rt = RecType ([field | field@(l,_) <- rs, notElem l (map fst ss)] ++ ss) -- select types of later fields
|
rt <- plusRecType rT' sT'
|
||||||
checkLType gr g trm' rt ---- return (trm', rt)
|
checkLType gr g trm' rt ---- return (trm', rt)
|
||||||
_ | rT' == typeType && sT' == typeType -> do
|
_ | rT' == typeType && sT' == typeType -> return (trm', typeType)
|
||||||
return (trm', typeType)
|
_ -> checkError (text "records or record types expected in" <+> ppTerm Unqualified 0 trm)
|
||||||
_ -> checkError ("records or record types expected in" <+> ppTerm Unqualified 0 trm)
|
|
||||||
|
|
||||||
Sort _ ->
|
Sort _ ->
|
||||||
termWith trm $ return typeType
|
termWith trm $ return typeType
|
||||||
|
|
||||||
Prod bt x a b -> do
|
Prod bt x a b -> do
|
||||||
@@ -252,7 +231,7 @@ inferLType gr g trm = case trm of
|
|||||||
return (Prod bt x a' b', typeType)
|
return (Prod bt x a' b', typeType)
|
||||||
|
|
||||||
Table p t -> do
|
Table p t -> do
|
||||||
p' <- justCheck g p typeType --- check p partype!
|
p' <- justCheck g p typeType --- check p partype!
|
||||||
t' <- justCheck g t typeType
|
t' <- justCheck g t typeType
|
||||||
return $ (Table p' t', typeType)
|
return $ (Table p' t', typeType)
|
||||||
|
|
||||||
@@ -271,9 +250,9 @@ inferLType gr g trm = case trm of
|
|||||||
ELin c trm -> do
|
ELin c trm -> do
|
||||||
(trm',ty) <- inferLType gr g trm
|
(trm',ty) <- inferLType gr g trm
|
||||||
ty' <- lockRecType c ty ---- lookup c; remove lock AR 20/6/2009
|
ty' <- lockRecType c ty ---- lookup c; remove lock AR 20/6/2009
|
||||||
return $ (ELin c trm', ty')
|
return $ (ELin c trm', ty')
|
||||||
|
|
||||||
_ -> checkError ("cannot infer lintype of" <+> ppTerm Unqualified 0 trm)
|
_ -> checkError (text "cannot infer lintype of" <+> ppTerm Unqualified 0 trm)
|
||||||
|
|
||||||
where
|
where
|
||||||
isPredef m = elem m [cPredef,cPredefAbs]
|
isPredef m = elem m [cPredef,cPredefAbs]
|
||||||
@@ -320,6 +299,7 @@ inferLType gr g trm = case trm of
|
|||||||
PChars _ -> return $ typeStr
|
PChars _ -> return $ typeStr
|
||||||
_ -> inferLType gr g (patt2term p) >>= return . snd
|
_ -> inferLType gr g (patt2term p) >>= return . snd
|
||||||
|
|
||||||
|
|
||||||
-- type inference: Nothing, type checking: Just t
|
-- type inference: Nothing, type checking: Just t
|
||||||
-- the latter permits matching with value type
|
-- the latter permits matching with value type
|
||||||
getOverload :: SourceGrammar -> Context -> Maybe Type -> Term -> Check (Maybe (Term,Type))
|
getOverload :: SourceGrammar -> Context -> Maybe Type -> Term -> Check (Maybe (Term,Type))
|
||||||
@@ -330,28 +310,15 @@ getOverload gr g mt ot = case appForm ot of
|
|||||||
v <- matchOverload f typs ttys
|
v <- matchOverload f typs ttys
|
||||||
return $ Just v
|
return $ Just v
|
||||||
_ -> return Nothing
|
_ -> return Nothing
|
||||||
(AdHocOverload cs@(f:_), ts) -> do --- the function name f is only used in error messages
|
|
||||||
let typs = concatMap collectOverloads cs
|
|
||||||
ttys <- mapM (inferLType gr g) ts
|
|
||||||
v <- matchOverload f typs ttys
|
|
||||||
return $ Just v
|
|
||||||
_ -> return Nothing
|
_ -> return Nothing
|
||||||
|
|
||||||
where
|
where
|
||||||
collectOverloads tr@(Q c) = case lookupOverload gr c of
|
|
||||||
Ok typs -> typs
|
|
||||||
_ -> case lookupResType gr c of
|
|
||||||
Ok ty -> let (args,val) = typeFormCnc ty in [(map (\(b,x,t) -> t) args,(val,tr))]
|
|
||||||
_ -> []
|
|
||||||
collectOverloads _ = [] --- constructors QC
|
|
||||||
|
|
||||||
matchOverload f typs ttys = do
|
matchOverload f typs ttys = do
|
||||||
let (tts,tys) = unzip ttys
|
let (tts,tys) = unzip ttys
|
||||||
let vfs = lookupOverloadInstance tys typs
|
let vfs = lookupOverloadInstance tys typs
|
||||||
let matches = [vf | vf@((_,v,_),_) <- vfs, matchVal mt v]
|
let matches = [vf | vf@((_,v,_),_) <- vfs, matchVal mt v]
|
||||||
let showTypes ty = hsep (map ppType ty)
|
let showTypes ty = hsep (map ppType ty)
|
||||||
|
|
||||||
|
|
||||||
let (stys,styps) = (showTypes tys, [showTypes ty | (ty,_) <- typs])
|
let (stys,styps) = (showTypes tys, [showTypes ty | (ty,_) <- typs])
|
||||||
|
|
||||||
-- to avoid strange error msg e.g. in case of unmatch record extension, show whole types if needed AR 28/1/2013
|
-- to avoid strange error msg e.g. in case of unmatch record extension, show whole types if needed AR 28/1/2013
|
||||||
@@ -362,57 +329,50 @@ getOverload gr g mt ot = case appForm ot of
|
|||||||
case ([vf | (vf,True) <- matches],[vf | (vf,False) <- matches]) of
|
case ([vf | (vf,True) <- matches],[vf | (vf,False) <- matches]) of
|
||||||
([(_,val,fun)],_) -> return (mkApp fun tts, val)
|
([(_,val,fun)],_) -> return (mkApp fun tts, val)
|
||||||
([],[(pre,val,fun)]) -> do
|
([],[(pre,val,fun)]) -> do
|
||||||
checkWarn $ "ignoring lock fields in resolving" <+> ppTerm Unqualified 0 ot $$
|
checkWarn $ text "ignoring lock fields in resolving" <+> ppTerm Unqualified 0 ot $$
|
||||||
"for" $$
|
text "for" $$
|
||||||
nest 2 (showTypes tys) $$
|
nest 2 (showTypes tys) $$
|
||||||
"using" $$
|
text "using" $$
|
||||||
nest 2 (showTypes pre)
|
nest 2 (showTypes pre)
|
||||||
return (mkApp fun tts, val)
|
return (mkApp fun tts, val)
|
||||||
([],[]) -> do
|
([],[]) -> do
|
||||||
checkError $ "no overload instance of" <+> ppTerm Qualified 0 f $$
|
checkError $ text "no overload instance of" <+> ppTerm Unqualified 0 f $$
|
||||||
maybe empty (\x -> "with value type" <+> ppType x) mt $$
|
text "for" $$
|
||||||
"for argument list" $$
|
|
||||||
nest 2 stysError $$
|
nest 2 stysError $$
|
||||||
"among alternatives" $$
|
text "among" $$
|
||||||
nest 2 (vcat stypsError)
|
nest 2 (vcat stypsError) $$
|
||||||
|
maybe empty (\x -> text "with value type" <+> ppType x) mt
|
||||||
|
|
||||||
(vfs1,vfs2) -> case (noProds vfs1,noProds vfs2) of
|
(vfs1,vfs2) -> case (noProds vfs1,noProds vfs2) of
|
||||||
([(val,fun)],_) -> do
|
([(val,fun)],_) -> do
|
||||||
return (mkApp fun tts, val)
|
return (mkApp fun tts, val)
|
||||||
([],[(val,fun)]) -> do
|
([],[(val,fun)]) -> do
|
||||||
checkWarn ("ignoring lock fields in resolving" <+> ppTerm Unqualified 0 ot)
|
checkWarn (text "ignoring lock fields in resolving" <+> ppTerm Unqualified 0 ot)
|
||||||
return (mkApp fun tts, val)
|
return (mkApp fun tts, val)
|
||||||
|
|
||||||
----- unsafely exclude irritating warning AR 24/5/2008
|
----- unsafely exclude irritating warning AR 24/5/2008
|
||||||
----- checkWarn $ "overloading of" +++ prt f +++
|
----- checkWarn $ "overloading of" +++ prt f +++
|
||||||
----- "resolved by excluding partial applications:" ++++
|
----- "resolved by excluding partial applications:" ++++
|
||||||
----- unlines [prtType env ty | (ty,_) <- vfs', not (noProd ty)]
|
----- unlines [prtType env ty | (ty,_) <- vfs', not (noProd ty)]
|
||||||
|
|
||||||
--- now forgiving ambiguity with a warning AR 1/2/2014
|
|
||||||
-- This gives ad hoc overloading the same behaviour as the choice of the first match in renaming did before.
|
_ -> checkError $ text "ambiguous overloading of" <+> ppTerm Unqualified 0 f <+>
|
||||||
-- But it also gives a chance to ambiguous overloadings that were banned before.
|
text "for" <+> hsep (map ppType tys) $$
|
||||||
(nps1,nps2) -> do
|
text "with alternatives" $$
|
||||||
checkWarn $ "ambiguous overloading of" <+> ppTerm Unqualified 0 f <+>
|
nest 2 (vcat [ppType ty | (_,ty,_) <- if null vfs1 then vfs2 else vfs2])
|
||||||
---- "with argument types" <+> hsep (map (ppTerm Qualified 0) tys) $$
|
|
||||||
"resolved by selecting the first of the alternatives" $$
|
|
||||||
nest 2 (vcat [ppTerm Qualified 0 fun | (_,ty,fun) <- vfs1 ++ if null vfs1 then vfs2 else []])
|
|
||||||
case [(mkApp fun tts,val) | (val,fun) <- nps1 ++ nps2] of
|
|
||||||
[] -> checkError $ "no alternatives left when resolving" <+> ppTerm Unqualified 0 f
|
|
||||||
h:_ -> return h
|
|
||||||
|
|
||||||
matchVal mt v = elem mt [Nothing,Just v,Just (unlocked v)]
|
matchVal mt v = elem mt [Nothing,Just v,Just (unlocked v)]
|
||||||
|
|
||||||
unlocked v = case v of
|
unlocked v = case v of
|
||||||
RecType fs -> RecType $ filter (not . isLockLabel . fst) (sortRec fs)
|
RecType fs -> RecType $ filter (not . isLockLabel . fst) fs
|
||||||
_ -> v
|
_ -> v
|
||||||
---- TODO: accept subtypes
|
---- TODO: accept subtypes
|
||||||
---- TODO: use a trie
|
---- TODO: use a trie
|
||||||
lookupOverloadInstance tys typs =
|
lookupOverloadInstance tys typs =
|
||||||
[((pre,mkFunType rest val, t),isExact) |
|
[((pre,mkFunType rest val, t),isExact) |
|
||||||
let lt = length tys,
|
let lt = length tys,
|
||||||
(ty,(val,t)) <- typs, length ty >= lt,
|
(ty,(val,t)) <- typs, length ty >= lt,
|
||||||
let (pre,rest) = splitAt lt ty,
|
let (pre,rest) = splitAt lt ty,
|
||||||
let isExact = pre == tys,
|
let isExact = pre == tys,
|
||||||
isExact || map unlocked pre == map unlocked tys
|
isExact || map unlocked pre == map unlocked tys
|
||||||
]
|
]
|
||||||
@@ -425,21 +385,20 @@ getOverload gr g mt ot = case appForm ot of
|
|||||||
|
|
||||||
checkLType :: SourceGrammar -> Context -> Term -> Type -> Check (Term, Type)
|
checkLType :: SourceGrammar -> Context -> Term -> Type -> Check (Term, Type)
|
||||||
checkLType gr g trm typ0 = do
|
checkLType gr g trm typ0 = do
|
||||||
|
|
||||||
typ <- computeLType gr g typ0
|
typ <- computeLType gr g typ0
|
||||||
|
|
||||||
case trm of
|
case trm of
|
||||||
|
|
||||||
Abs bt x c -> do
|
Abs bt x c -> do
|
||||||
case typ of
|
case typ of
|
||||||
Prod bt' z a b -> do
|
Prod bt' z a b -> do
|
||||||
(c',b') <- if isWildIdent z
|
(c',b') <- if isWildIdent z
|
||||||
then checkLType gr ((bt,x,a):g) c b
|
then checkLType gr ((bt,x,a):g) c b
|
||||||
else do b' <- checkIn (pp "abs") $ substituteLType [(bt',z,Vr x)] b
|
else do b' <- checkIn (text "abs") $ substituteLType [(bt',z,Vr x)] b
|
||||||
checkLType gr ((bt,x,a):g) c b'
|
checkLType gr ((bt,x,a):g) c b'
|
||||||
return $ (Abs bt x c', Prod bt' z a b')
|
return $ (Abs bt x c', Prod bt' x a b')
|
||||||
_ -> checkError $ "function type expected instead of" <+> ppType typ $$
|
_ -> checkError $ text "function type expected instead of" <+> ppType typ
|
||||||
"\n ** Double-check that the type signature of the operation" $$
|
|
||||||
"matches the number of arguments given to it.\n"
|
|
||||||
|
|
||||||
App f a -> do
|
App f a -> do
|
||||||
over <- getOverload gr g (Just typ) trm
|
over <- getOverload gr g (Just typ) trm
|
||||||
@@ -449,12 +408,6 @@ checkLType gr g trm typ0 = do
|
|||||||
(trm',ty') <- inferLType gr g trm
|
(trm',ty') <- inferLType gr g trm
|
||||||
termWith trm' $ checkEqLType gr g typ ty' trm'
|
termWith trm' $ checkEqLType gr g typ ty' trm'
|
||||||
|
|
||||||
AdHocOverload ts -> do
|
|
||||||
over <- getOverload gr g Nothing trm
|
|
||||||
case over of
|
|
||||||
Just trty -> return trty
|
|
||||||
_ -> checkError ("unresolved overloading of constants" <+> ppTerm Qualified 0 trm)
|
|
||||||
|
|
||||||
Q _ -> do
|
Q _ -> do
|
||||||
over <- getOverload gr g (Just typ) trm
|
over <- getOverload gr g (Just typ) trm
|
||||||
case over of
|
case over of
|
||||||
@@ -464,21 +417,21 @@ checkLType gr g trm typ0 = do
|
|||||||
termWith trm' $ checkEqLType gr g typ ty' trm'
|
termWith trm' $ checkEqLType gr g typ ty' trm'
|
||||||
|
|
||||||
T _ [] ->
|
T _ [] ->
|
||||||
checkError ("found empty table in type" <+> ppTerm Unqualified 0 typ)
|
checkError (text "found empty table in type" <+> ppTerm Unqualified 0 typ)
|
||||||
T _ cs -> case typ of
|
T _ cs -> case typ of
|
||||||
Table arg val -> do
|
Table arg val -> do
|
||||||
case allParamValues gr arg of
|
case allParamValues gr arg of
|
||||||
Ok vs -> do
|
Ok vs -> do
|
||||||
let ps0 = map fst cs
|
let ps0 = map fst cs
|
||||||
ps <- testOvershadow ps0 vs
|
ps <- testOvershadow ps0 vs
|
||||||
if null ps
|
if null ps
|
||||||
then return ()
|
then return ()
|
||||||
else checkWarn ("patterns never reached:" $$
|
else checkWarn (text "patterns never reached:" $$
|
||||||
nest 2 (vcat (map (ppPatt Unqualified 0) ps)))
|
nest 2 (vcat (map (ppPatt Unqualified 0) ps)))
|
||||||
_ -> return () -- happens with variable types
|
_ -> return () -- happens with variable types
|
||||||
cs' <- mapM (checkCase arg val) cs
|
cs' <- mapM (checkCase arg val) cs
|
||||||
return (T (TTyped arg) cs', typ)
|
return (T (TTyped arg) cs', typ)
|
||||||
_ -> checkError $ "table type expected for table instead of" $$ nest 2 (ppType typ)
|
_ -> checkError $ text "table type expected for table instead of" $$ nest 2 (ppType typ)
|
||||||
V arg0 vs ->
|
V arg0 vs ->
|
||||||
case typ of
|
case typ of
|
||||||
Table arg1 val ->
|
Table arg1 val ->
|
||||||
@@ -486,54 +439,51 @@ checkLType gr g trm typ0 = do
|
|||||||
vs1 <- allParamValues gr arg1
|
vs1 <- allParamValues gr arg1
|
||||||
if length vs1 == length vs
|
if length vs1 == length vs
|
||||||
then return ()
|
then return ()
|
||||||
else checkError $ "wrong number of values in table" <+> ppTerm Unqualified 0 trm
|
else checkError $ text "wrong number of values in table" <+> ppTerm Unqualified 0 trm
|
||||||
vs' <- map fst `fmap` sequence [checkLType gr g v val|v<-vs]
|
vs' <- map fst `fmap` sequence [checkLType gr g v val|v<-vs]
|
||||||
return (V arg' vs',typ)
|
return (V arg' vs',typ)
|
||||||
|
|
||||||
R r -> case typ of --- why needed? because inference may be too difficult
|
R r -> case typ of --- why needed? because inference may be too difficult
|
||||||
RecType rr -> do
|
RecType rr -> do
|
||||||
--let (ls,_) = unzip rr -- labels of expected type
|
let (ls,_) = unzip rr -- labels of expected type
|
||||||
fsts <- mapM (checkM r) rr -- check that they are found in the record
|
fsts <- mapM (checkM r) rr -- check that they are found in the record
|
||||||
return $ (R fsts, typ) -- normalize record
|
return $ (R fsts, typ) -- normalize record
|
||||||
|
|
||||||
_ -> checkError ("record type expected in type checking instead of" $$ nest 2 (ppTerm Unqualified 0 typ))
|
_ -> checkError (text "record type expected in type checking instead of" $$ nest 2 (ppTerm Unqualified 0 typ))
|
||||||
|
|
||||||
ExtR r s -> case typ of
|
ExtR r s -> case typ of
|
||||||
_ | typ == typeType -> do
|
_ | typ == typeType -> do
|
||||||
trm' <- computeLType gr g trm
|
trm' <- computeLType gr g trm
|
||||||
case trm' of
|
case trm' of
|
||||||
RecType _ -> termWith trm' $ return typeType
|
RecType _ -> termWith trm $ return typeType
|
||||||
ExtR (Vr _) (RecType _) -> termWith trm' $ return typeType
|
ExtR (Vr _) (RecType _) -> termWith trm $ return typeType
|
||||||
-- ext t = t ** ...
|
-- ext t = t ** ...
|
||||||
_ -> checkError ("invalid record type extension" <+> nest 2 (ppTerm Unqualified 0 trm))
|
_ -> checkError (text "invalid record type extension" <+> nest 2 (ppTerm Unqualified 0 trm))
|
||||||
|
|
||||||
RecType rr -> do
|
RecType rr -> do
|
||||||
|
(r',ty,s') <- checks [
|
||||||
|
do (r',ty) <- inferLType gr g r
|
||||||
|
return (r',ty,s)
|
||||||
|
,
|
||||||
|
do (s',ty) <- inferLType gr g s
|
||||||
|
return (s',ty,r)
|
||||||
|
]
|
||||||
|
|
||||||
ll2 <- case s of
|
case ty of
|
||||||
R ss -> return $ map fst ss
|
RecType rr1 -> do
|
||||||
_ -> do
|
let (rr0,rr2) = recParts rr rr1
|
||||||
(s',typ2) <- inferLType gr g s
|
r2 <- justCheck g r' rr0
|
||||||
case typ2 of
|
s2 <- justCheck g s' rr2
|
||||||
RecType ss -> return $ map fst ss
|
return $ (ExtR r2 s2, typ)
|
||||||
_ -> checkError ("cannot get labels from" $$ nest 2 (ppTerm Unqualified 0 typ2))
|
_ -> checkError (text "record type expected in extension of" <+> ppTerm Unqualified 0 r $$
|
||||||
let ll1 = [l | (l,_) <- rr, notElem l ll2]
|
text "but found" <+> ppTerm Unqualified 0 ty)
|
||||||
|
|
||||||
--- over <- getOverload gr g Nothing r --- this would solve #66 but fail ParadigmsAra. AR 6/7/2020
|
|
||||||
--- let r1 = maybe r fst over
|
|
||||||
let r1 = r ---
|
|
||||||
|
|
||||||
(r',_) <- checkLType gr g r1 (RecType [field | field@(l,_) <- rr, elem l ll1])
|
|
||||||
(s',_) <- checkLType gr g s (RecType [field | field@(l,_) <- rr, elem l ll2])
|
|
||||||
|
|
||||||
let rec = R ([(l,(Nothing,P r' l)) | l <- ll1] ++ [(l,(Nothing,P s' l)) | l <- ll2])
|
|
||||||
return (rec, typ)
|
|
||||||
|
|
||||||
ExtR ty ex -> do
|
ExtR ty ex -> do
|
||||||
r' <- justCheck g r ty
|
r' <- justCheck g r ty
|
||||||
s' <- justCheck g s ex
|
s' <- justCheck g s ex
|
||||||
return $ (ExtR r' s', typ) --- is this all? it assumes the same division in trm and typ
|
return $ (ExtR r' s', typ) --- is this all? it assumes the same division in trm and typ
|
||||||
|
|
||||||
_ -> checkError ("record extension not meaningful for" <+> ppTerm Unqualified 0 typ)
|
_ -> checkError (text "record extension not meaningful for" <+> ppTerm Unqualified 0 typ)
|
||||||
|
|
||||||
FV vs -> do
|
FV vs -> do
|
||||||
ttys <- mapM (flip (checkLType gr g) typ) vs
|
ttys <- mapM (flip (checkLType gr g) typ) vs
|
||||||
@@ -548,7 +498,7 @@ checkLType gr g trm typ0 = do
|
|||||||
(arg',val) <- checkLType gr g arg p
|
(arg',val) <- checkLType gr g arg p
|
||||||
checkEqLType gr g typ t trm
|
checkEqLType gr g typ t trm
|
||||||
return (S tab' arg', t)
|
return (S tab' arg', t)
|
||||||
_ -> checkError ("table type expected for applied table instead of" <+> ppType ty')
|
_ -> checkError (text "table type expected for applied table instead of" <+> ppType ty')
|
||||||
, do
|
, do
|
||||||
(arg',ty) <- inferLType gr g arg
|
(arg',ty) <- inferLType gr g arg
|
||||||
ty' <- computeLType gr g ty
|
ty' <- computeLType gr g ty
|
||||||
@@ -557,8 +507,7 @@ checkLType gr g trm typ0 = do
|
|||||||
]
|
]
|
||||||
Let (x,(mty,def)) body -> case mty of
|
Let (x,(mty,def)) body -> case mty of
|
||||||
Just ty -> do
|
Just ty -> do
|
||||||
(ty0,_) <- checkLType gr g ty typeType
|
(def',ty') <- checkLType gr g def ty
|
||||||
(def',ty') <- checkLType gr g def ty0
|
|
||||||
body' <- justCheck ((Explicit,x,ty'):g) body typ
|
body' <- justCheck ((Explicit,x,ty'):g) body typ
|
||||||
return (Let (x,(Just ty',def')) body', typ)
|
return (Let (x,(Just ty',def')) body', typ)
|
||||||
_ -> do
|
_ -> do
|
||||||
@@ -574,10 +523,10 @@ checkLType gr g trm typ0 = do
|
|||||||
termWith trm' $ checkEqLType gr g typ ty' trm'
|
termWith trm' $ checkEqLType gr g typ ty' trm'
|
||||||
where
|
where
|
||||||
justCheck g ty te = checkLType gr g ty te >>= return . fst
|
justCheck g ty te = checkLType gr g ty te >>= return . fst
|
||||||
{-
|
|
||||||
recParts rr t = (RecType rr1,RecType rr2) where
|
recParts rr t = (RecType rr1,RecType rr2) where
|
||||||
(rr1,rr2) = partition (flip elem (map fst t) . fst) rr
|
(rr1,rr2) = partition (flip elem (map fst t) . fst) rr
|
||||||
-}
|
|
||||||
checkM rms (l,ty) = case lookup l rms of
|
checkM rms (l,ty) = case lookup l rms of
|
||||||
Just (Just ty0,t) -> do
|
Just (Just ty0,t) -> do
|
||||||
checkEqLType gr g ty ty0 t
|
checkEqLType gr g ty ty0 t
|
||||||
@@ -586,12 +535,12 @@ checkLType gr g trm typ0 = do
|
|||||||
Just (_,t) -> do
|
Just (_,t) -> do
|
||||||
(t',ty') <- checkLType gr g t ty
|
(t',ty') <- checkLType gr g t ty
|
||||||
return (l,(Just ty',t'))
|
return (l,(Just ty',t'))
|
||||||
_ -> checkError $
|
_ -> checkError $
|
||||||
if isLockLabel l
|
if isLockLabel l
|
||||||
then let cat = drop 5 (showIdent (label2ident l))
|
then let cat = drop 5 (showIdent (label2ident l))
|
||||||
in ppTerm Unqualified 0 (R rms) <+> "is not in the lincat of" <+> cat <>
|
in ppTerm Unqualified 0 (R rms) <+> text "is not in the lincat of" <+> text cat <>
|
||||||
"; try wrapping it with lin" <+> cat
|
text "; try wrapping it with lin" <+> text cat
|
||||||
else "cannot find value for label" <+> l <+> "in" <+> ppTerm Unqualified 0 (R rms)
|
else text "cannot find value for label" <+> ppLabel l <+> text "in" <+> ppTerm Unqualified 0 (R rms)
|
||||||
|
|
||||||
checkCase arg val (p,t) = do
|
checkCase arg val (p,t) = do
|
||||||
cont <- pattContext gr g arg p
|
cont <- pattContext gr g arg p
|
||||||
@@ -604,7 +553,7 @@ pattContext env g typ p = case p of
|
|||||||
PP (q,c) ps | q /= cPredef -> do ---- why this /=? AR 6/1/2006
|
PP (q,c) ps | q /= cPredef -> do ---- why this /=? AR 6/1/2006
|
||||||
t <- lookupResType env (q,c)
|
t <- lookupResType env (q,c)
|
||||||
let (cont,v) = typeFormCnc t
|
let (cont,v) = typeFormCnc t
|
||||||
checkCond ("wrong number of arguments for constructor in" <+> ppPatt Unqualified 0 p)
|
checkCond (text "wrong number of arguments for constructor in" <+> ppPatt Unqualified 0 p)
|
||||||
(length cont == length ps)
|
(length cont == length ps)
|
||||||
checkEqLType env g typ v (patt2term p)
|
checkEqLType env g typ v (patt2term p)
|
||||||
mapM (\((_,_,ty),p) -> pattContext env g ty p) (zip cont ps) >>= return . concat
|
mapM (\((_,_,ty),p) -> pattContext env g ty p) (zip cont ps) >>= return . concat
|
||||||
@@ -615,7 +564,7 @@ pattContext env g typ p = case p of
|
|||||||
let pts = [(ty,tr) | (l,tr) <- r, Just ty <- [lookup l t]]
|
let pts = [(ty,tr) | (l,tr) <- r, Just ty <- [lookup l t]]
|
||||||
----- checkWarn $ prt p ++++ show pts ----- debug
|
----- checkWarn $ prt p ++++ show pts ----- debug
|
||||||
mapM (uncurry (pattContext env g)) pts >>= return . concat
|
mapM (uncurry (pattContext env g)) pts >>= return . concat
|
||||||
_ -> checkError ("record type expected for pattern instead of" <+> ppTerm Unqualified 0 typ')
|
_ -> checkError (text "record type expected for pattern instead of" <+> ppTerm Unqualified 0 typ')
|
||||||
PT t p' -> do
|
PT t p' -> do
|
||||||
checkEqLType env g typ t (patt2term p')
|
checkEqLType env g typ t (patt2term p')
|
||||||
pattContext env g typ p'
|
pattContext env g typ p'
|
||||||
@@ -628,10 +577,10 @@ pattContext env g typ p = case p of
|
|||||||
g1 <- pattContext env g typ p'
|
g1 <- pattContext env g typ p'
|
||||||
g2 <- pattContext env g typ q
|
g2 <- pattContext env g typ q
|
||||||
let pts = nub ([x | pt@(_,x,_) <- g1, notElem pt g2] ++ [x | pt@(_,x,_) <- g2, notElem pt g1])
|
let pts = nub ([x | pt@(_,x,_) <- g1, notElem pt g2] ++ [x | pt@(_,x,_) <- g2, notElem pt g1])
|
||||||
checkCond
|
checkCond
|
||||||
("incompatible bindings of" <+>
|
(text "incompatible bindings of" <+>
|
||||||
fsep pts <+>
|
fsep (map ppIdent pts) <+>
|
||||||
"in pattern alterantives" <+> ppPatt Unqualified 0 p) (null pts)
|
text "in pattern alterantives" <+> ppPatt Unqualified 0 p) (null pts)
|
||||||
return g1 -- must be g1 == g2
|
return g1 -- must be g1 == g2
|
||||||
PSeq p q -> do
|
PSeq p q -> do
|
||||||
g1 <- pattContext env g typ p
|
g1 <- pattContext env g typ p
|
||||||
@@ -641,11 +590,11 @@ pattContext env g typ p = case p of
|
|||||||
PNeg p' -> noBind typ p'
|
PNeg p' -> noBind typ p'
|
||||||
|
|
||||||
_ -> return [] ---- check types!
|
_ -> return [] ---- check types!
|
||||||
where
|
where
|
||||||
noBind typ p' = do
|
noBind typ p' = do
|
||||||
co <- pattContext env g typ p'
|
co <- pattContext env g typ p'
|
||||||
if not (null co)
|
if not (null co)
|
||||||
then checkWarn ("no variable bound inside pattern" <+> ppPatt Unqualified 0 p)
|
then checkWarn (text "no variable bound inside pattern" <+> ppPatt Unqualified 0 p)
|
||||||
>> return []
|
>> return []
|
||||||
else return []
|
else return []
|
||||||
|
|
||||||
@@ -654,31 +603,9 @@ checkEqLType gr g t u trm = do
|
|||||||
(b,t',u',s) <- checkIfEqLType gr g t u trm
|
(b,t',u',s) <- checkIfEqLType gr g t u trm
|
||||||
case b of
|
case b of
|
||||||
True -> return t'
|
True -> return t'
|
||||||
False ->
|
False -> checkError $ text s <+> text "type of" <+> ppTerm Unqualified 0 trm $$
|
||||||
let inferredType = ppTerm Qualified 0 u
|
text "expected:" <+> ppType t $$
|
||||||
expectedType = ppTerm Qualified 0 t
|
text "inferred:" <+> ppType u
|
||||||
term = ppTerm Unqualified 0 trm
|
|
||||||
funName = pp . head . words .render $ term
|
|
||||||
helpfulMsg =
|
|
||||||
case (arrows inferredType, arrows expectedType) of
|
|
||||||
(0,0) -> pp "" -- None of the types is a function
|
|
||||||
_ -> "\n **" <+>
|
|
||||||
if expectedType `isLessApplied` inferredType
|
|
||||||
then "Maybe you gave too few arguments to" <+> funName
|
|
||||||
else pp "Double-check that type signature and number of arguments match."
|
|
||||||
in checkError $ s <+> "type of" <+> term $$
|
|
||||||
"expected:" <+> expectedType $$ -- ppqType t u $$
|
|
||||||
"inferred:" <+> inferredType $$ -- ppqType u t
|
|
||||||
helpfulMsg
|
|
||||||
where
|
|
||||||
-- count the number of arrows in the prettyprinted term
|
|
||||||
arrows :: Doc -> Int
|
|
||||||
arrows = length . filter (=="->") . words . render
|
|
||||||
|
|
||||||
-- If prettyprinted type t has fewer arrows then prettyprinted type u,
|
|
||||||
-- then t is "less applied", and we can print out more helpful error msg.
|
|
||||||
isLessApplied :: Doc -> Doc -> Bool
|
|
||||||
isLessApplied t u = arrows t < arrows u
|
|
||||||
|
|
||||||
checkIfEqLType :: SourceGrammar -> Context -> Type -> Type -> Term -> Check (Bool,Type,Type,String)
|
checkIfEqLType :: SourceGrammar -> Context -> Type -> Type -> Term -> Check (Bool,Type,Type,String)
|
||||||
checkIfEqLType gr g t u trm = do
|
checkIfEqLType gr g t u trm = do
|
||||||
@@ -690,62 +617,60 @@ checkIfEqLType gr g t u trm = do
|
|||||||
--- better: use a flag to forgive? (AR 31/1/2006)
|
--- better: use a flag to forgive? (AR 31/1/2006)
|
||||||
_ -> case missingLock [] t' u' of
|
_ -> case missingLock [] t' u' of
|
||||||
Ok lo -> do
|
Ok lo -> do
|
||||||
checkWarn $ "missing lock field" <+> fsep lo
|
checkWarn $ text "missing lock field" <+> fsep (map ppLabel lo)
|
||||||
return (True,t',u',[])
|
return (True,t',u',[])
|
||||||
Bad s -> return (False,t',u',s)
|
Bad s -> return (False,t',u',s)
|
||||||
|
|
||||||
where
|
where
|
||||||
|
|
||||||
-- check that u is a subtype of t
|
-- t is a subtype of u
|
||||||
--- quick hack version of TC.eqVal
|
--- quick hack version of TC.eqVal
|
||||||
alpha g t u = case (t,u) of
|
alpha g t u = case (t,u) of
|
||||||
|
|
||||||
-- error (the empty type!) is subtype of any other type
|
-- error (the empty type!) is subtype of any other type
|
||||||
(_,u) | u == typeError -> True
|
(_,u) | u == typeError -> True
|
||||||
|
|
||||||
-- contravariance
|
-- contravariance
|
||||||
(Prod _ x a b, Prod _ y c d) -> alpha g c a && alpha ((x,y):g) b d
|
(Prod _ x a b, Prod _ y c d) -> alpha g c a && alpha ((x,y):g) b d
|
||||||
|
|
||||||
-- record subtyping
|
-- record subtyping
|
||||||
(RecType rs, RecType ts) -> all (\ (l,a) ->
|
(RecType rs, RecType ts) -> all (\ (l,a) ->
|
||||||
any (\ (k,b) -> l == k && alpha g a b) ts) rs
|
any (\ (k,b) -> alpha g a b && l == k) ts) rs
|
||||||
(ExtR r s, ExtR r' s') -> alpha g r r' && alpha g s s'
|
(ExtR r s, ExtR r' s') -> alpha g r r' && alpha g s s'
|
||||||
(ExtR r s, t) -> alpha g r t || alpha g s t
|
(ExtR r s, t) -> alpha g r t || alpha g s t
|
||||||
|
|
||||||
-- the following say that Ints n is a subset of Int and of Ints m >= n
|
-- the following say that Ints n is a subset of Int and of Ints m >= n
|
||||||
-- But why does it also allow Int as a subtype of Ints m? /TH 2014-04-04
|
(t,u) | Just m <- isTypeInts t, Just n <- isTypeInts t -> m >= n
|
||||||
(t,u) | Just m <- isTypeInts t, Just n <- isTypeInts u -> m >= n
|
|
||||||
| Just _ <- isTypeInts t, u == typeInt -> True ---- check size!
|
| Just _ <- isTypeInts t, u == typeInt -> True ---- check size!
|
||||||
| t == typeInt, Just _ <- isTypeInts u -> True ---- why this ???? AR 11/12/2005
|
| t == typeInt, Just _ <- isTypeInts u -> True ---- why this ???? AR 11/12/2005
|
||||||
|
|
||||||
---- this should be made in Rename
|
---- this should be made in Rename
|
||||||
(Q (m,a), Q (n,b)) | a == b -> elem m (allExtendsPlus gr n)
|
(Q (m,a), Q (n,b)) | a == b -> elem m (allExtendsPlus gr n)
|
||||||
|| elem n (allExtendsPlus gr m)
|
|| elem n (allExtendsPlus gr m)
|
||||||
|| m == n --- for Predef
|
|| m == n --- for Predef
|
||||||
(QC (m,a), QC (n,b)) | a == b -> elem m (allExtendsPlus gr n)
|
(QC (m,a), QC (n,b)) | a == b -> elem m (allExtendsPlus gr n)
|
||||||
|| elem n (allExtendsPlus gr m)
|
|| elem n (allExtendsPlus gr m)
|
||||||
(QC (m,a), Q (n,b)) | a == b -> elem m (allExtendsPlus gr n)
|
(QC (m,a), Q (n,b)) | a == b -> elem m (allExtendsPlus gr n)
|
||||||
|| elem n (allExtendsPlus gr m)
|
|| elem n (allExtendsPlus gr m)
|
||||||
(Q (m,a), QC (n,b)) | a == b -> elem m (allExtendsPlus gr n)
|
(Q (m,a), QC (n,b)) | a == b -> elem m (allExtendsPlus gr n)
|
||||||
|| elem n (allExtendsPlus gr m)
|
|| elem n (allExtendsPlus gr m)
|
||||||
|
|
||||||
-- contravariance
|
(Table a b, Table c d) -> alpha g a c && alpha g b d
|
||||||
(Table a b, Table c d) -> alpha g c a && alpha g b d
|
|
||||||
(Vr x, Vr y) -> x == y || elem (x,y) g || elem (y,x) g
|
(Vr x, Vr y) -> x == y || elem (x,y) g || elem (y,x) g
|
||||||
_ -> t == u
|
_ -> t == u
|
||||||
--- the following should be one-way coercions only. AR 4/1/2001
|
--- the following should be one-way coercions only. AR 4/1/2001
|
||||||
|| elem t sTypes && elem u sTypes
|
|| elem t sTypes && elem u sTypes
|
||||||
|| (t == typeType && u == typePType)
|
|| (t == typeType && u == typePType)
|
||||||
|| (u == typeType && t == typePType)
|
|| (u == typeType && t == typePType)
|
||||||
|
|
||||||
missingLock g t u = case (t,u) of
|
missingLock g t u = case (t,u) of
|
||||||
(RecType rs, RecType ts) ->
|
(RecType rs, RecType ts) ->
|
||||||
let
|
let
|
||||||
ls = [l | (l,a) <- rs,
|
ls = [l | (l,a) <- rs,
|
||||||
not (any (\ (k,b) -> alpha g a b && l == k) ts)]
|
not (any (\ (k,b) -> alpha g a b && l == k) ts)]
|
||||||
(locks,others) = partition isLockLabel ls
|
(locks,others) = partition isLockLabel ls
|
||||||
in case others of
|
in case others of
|
||||||
_:_ -> Bad $ render ("missing record fields:" <+> fsep (punctuate ',' (others)))
|
_:_ -> Bad $ render (text "missing record fields:" <+> fsep (punctuate comma (map ppLabel others)))
|
||||||
_ -> return locks
|
_ -> return locks
|
||||||
-- contravariance
|
-- contravariance
|
||||||
(Prod _ x a b, Prod _ y c d) -> do
|
(Prod _ x a b, Prod _ y c d) -> do
|
||||||
@@ -771,7 +696,7 @@ termWith t ct = do
|
|||||||
return (t,ty)
|
return (t,ty)
|
||||||
|
|
||||||
-- | compositional check\/infer of binary operations
|
-- | compositional check\/infer of binary operations
|
||||||
check2 :: (Term -> Check Term) -> (Term -> Term -> Term) ->
|
check2 :: (Term -> Check Term) -> (Term -> Term -> Term) ->
|
||||||
Term -> Term -> Type -> Check (Term,Type)
|
Term -> Term -> Type -> Check (Term,Type)
|
||||||
check2 chk con a b t = do
|
check2 chk con a b t = do
|
||||||
a' <- chk a
|
a' <- chk a
|
||||||
@@ -783,18 +708,14 @@ ppType :: Type -> Doc
|
|||||||
ppType ty =
|
ppType ty =
|
||||||
case ty of
|
case ty of
|
||||||
RecType fs -> case filter isLockLabel $ map fst fs of
|
RecType fs -> case filter isLockLabel $ map fst fs of
|
||||||
[lock] -> pp (drop 5 (showIdent (label2ident lock)))
|
[lock] -> text (drop 5 (showIdent (label2ident lock)))
|
||||||
_ -> ppTerm Unqualified 0 ty
|
_ -> ppTerm Unqualified 0 ty
|
||||||
Prod _ x a b -> ppType a <+> "->" <+> ppType b
|
Prod _ x a b -> ppType a <+> text "->" <+> ppType b
|
||||||
_ -> ppTerm Unqualified 0 ty
|
_ -> ppTerm Unqualified 0 ty
|
||||||
{-
|
|
||||||
ppqType :: Type -> Type -> Doc
|
|
||||||
ppqType t u = case (ppType t, ppType u) of
|
|
||||||
(pt,pu) | render pt == render pu -> ppTerm Qualified 0 t
|
|
||||||
(pt,_) -> pt
|
|
||||||
-}
|
|
||||||
checkLookup :: Ident -> Context -> Check Type
|
checkLookup :: Ident -> Context -> Check Type
|
||||||
checkLookup x g =
|
checkLookup x g =
|
||||||
case [ty | (b,y,ty) <- g, x == y] of
|
case [ty | (b,y,ty) <- g, x == y] of
|
||||||
[] -> checkError ("unknown variable" <+> x)
|
[] -> checkError (text "unknown variable" <+> ppIdent x)
|
||||||
(ty:_) -> return ty
|
(ty:_) -> return ty
|
||||||
|
-}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import GF.Grammar hiding (Env, VGen, VApp, VRecType)
|
|||||||
import GF.Grammar.Lookup
|
import GF.Grammar.Lookup
|
||||||
import GF.Grammar.Predef
|
import GF.Grammar.Predef
|
||||||
import GF.Grammar.Lockfield
|
import GF.Grammar.Lockfield
|
||||||
import GF.Compile.Compute.Concrete
|
import GF.Compile.Compute.ConcreteNew
|
||||||
import GF.Compile.Compute.Predef(predef,predefName)
|
import GF.Compile.Compute.Predef(predef,predefName)
|
||||||
import GF.Infra.CheckM
|
import GF.Infra.CheckM
|
||||||
import GF.Data.Operations
|
import GF.Data.Operations
|
||||||
@@ -133,7 +133,7 @@ tcRho ge scope t@(RecType rs) (Just ty) = do
|
|||||||
[] -> unifyVar ge scope i env vs vtypePType
|
[] -> unifyVar ge scope i env vs vtypePType
|
||||||
_ -> return ()
|
_ -> return ()
|
||||||
ty -> do ty <- zonkTerm =<< tc_value2term (geLoc ge) (scopeVars scope) ty
|
ty -> do ty <- zonkTerm =<< tc_value2term (geLoc ge) (scopeVars scope) ty
|
||||||
tcError ("The record type" <+> ppTerm Unqualified 0 t $$
|
tcError ("The record type" <+> ppTerm Unqualified 0 t $$
|
||||||
"cannot be of type" <+> ppTerm Unqualified 0 ty)
|
"cannot be of type" <+> ppTerm Unqualified 0 ty)
|
||||||
(rs,mb_ty) <- tcRecTypeFields ge scope rs (Just ty')
|
(rs,mb_ty) <- tcRecTypeFields ge scope rs (Just ty')
|
||||||
return (f (RecType rs),ty)
|
return (f (RecType rs),ty)
|
||||||
@@ -187,7 +187,7 @@ tcRho ge scope (R rs) (Just ty) = do
|
|||||||
case ty' of
|
case ty' of
|
||||||
(VRecType ltys) -> do lttys <- checkRecFields ge scope rs ltys
|
(VRecType ltys) -> do lttys <- checkRecFields ge scope rs ltys
|
||||||
rs <- mapM (\(l,t,ty) -> tc_value2term (geLoc ge) (scopeVars scope) ty >>= \ty -> return (l, (Just ty, t))) lttys
|
rs <- mapM (\(l,t,ty) -> tc_value2term (geLoc ge) (scopeVars scope) ty >>= \ty -> return (l, (Just ty, t))) lttys
|
||||||
return ((f . R) rs,
|
return ((f . R) rs,
|
||||||
VRecType [(l, ty) | (l,t,ty) <- lttys]
|
VRecType [(l, ty) | (l,t,ty) <- lttys]
|
||||||
)
|
)
|
||||||
ty -> do lttys <- inferRecFields ge scope rs
|
ty -> do lttys <- inferRecFields ge scope rs
|
||||||
@@ -277,11 +277,11 @@ tcApp ge scope (App fun arg) = -- APP2
|
|||||||
varg <- liftErr (eval ge (scopeEnv scope) arg)
|
varg <- liftErr (eval ge (scopeEnv scope) arg)
|
||||||
return (App fun arg, res_ty varg)
|
return (App fun arg, res_ty varg)
|
||||||
tcApp ge scope (Q id) = -- VAR (global)
|
tcApp ge scope (Q id) = -- VAR (global)
|
||||||
mkTcA (lookupOverloadTypes (geGrammar ge) id) `bindTcA` \(t,ty) ->
|
mkTcA (lookupOverloadTypes (geGrammar ge) id) `bindTcA` \(t,ty) ->
|
||||||
do ty <- liftErr (eval ge [] ty)
|
do ty <- liftErr (eval ge [] ty)
|
||||||
return (t,ty)
|
return (t,ty)
|
||||||
tcApp ge scope (QC id) = -- VAR (global)
|
tcApp ge scope (QC id) = -- VAR (global)
|
||||||
mkTcA (lookupOverloadTypes (geGrammar ge) id) `bindTcA` \(t,ty) ->
|
mkTcA (lookupOverloadTypes (geGrammar ge) id) `bindTcA` \(t,ty) ->
|
||||||
do ty <- liftErr (eval ge [] ty)
|
do ty <- liftErr (eval ge [] ty)
|
||||||
return (t,ty)
|
return (t,ty)
|
||||||
tcApp ge scope t =
|
tcApp ge scope t =
|
||||||
@@ -350,7 +350,7 @@ tcPatt ge scope (PM q) ty0 = do
|
|||||||
Bad err -> tcError (pp err)
|
Bad err -> tcError (pp err)
|
||||||
tcPatt ge scope p ty = unimplemented ("tcPatt "++show p)
|
tcPatt ge scope p ty = unimplemented ("tcPatt "++show p)
|
||||||
|
|
||||||
inferRecFields ge scope rs =
|
inferRecFields ge scope rs =
|
||||||
mapM (\(l,r) -> tcRecField ge scope l r Nothing) rs
|
mapM (\(l,r) -> tcRecField ge scope l r Nothing) rs
|
||||||
|
|
||||||
checkRecFields ge scope [] ltys
|
checkRecFields ge scope [] ltys
|
||||||
@@ -368,7 +368,7 @@ checkRecFields ge scope ((l,t):lts) ltys =
|
|||||||
where
|
where
|
||||||
takeIt l1 [] = (Nothing, [])
|
takeIt l1 [] = (Nothing, [])
|
||||||
takeIt l1 (lty@(l2,ty):ltys)
|
takeIt l1 (lty@(l2,ty):ltys)
|
||||||
| l1 == l2 = (Just ty,ltys)
|
| l1 == l2 = (Just ty,ltys)
|
||||||
| otherwise = let (mb_ty,ltys') = takeIt l1 ltys
|
| otherwise = let (mb_ty,ltys') = takeIt l1 ltys
|
||||||
in (mb_ty,lty:ltys')
|
in (mb_ty,lty:ltys')
|
||||||
|
|
||||||
@@ -390,13 +390,13 @@ tcRecTypeFields ge scope ((l,ty):rs) mb_ty = do
|
|||||||
| s == cPType -> return mb_ty
|
| s == cPType -> return mb_ty
|
||||||
VMeta _ _ _ -> return mb_ty
|
VMeta _ _ _ -> return mb_ty
|
||||||
_ -> do sort <- zonkTerm =<< tc_value2term (geLoc ge) (scopeVars scope) sort
|
_ -> do sort <- zonkTerm =<< tc_value2term (geLoc ge) (scopeVars scope) sort
|
||||||
tcError ("The record type field" <+> l <+> ':' <+> ppTerm Unqualified 0 ty $$
|
tcError ("The record type field" <+> l <+> ':' <+> ppTerm Unqualified 0 ty $$
|
||||||
"cannot be of type" <+> ppTerm Unqualified 0 sort)
|
"cannot be of type" <+> ppTerm Unqualified 0 sort)
|
||||||
(rs,mb_ty) <- tcRecTypeFields ge scope rs mb_ty
|
(rs,mb_ty) <- tcRecTypeFields ge scope rs mb_ty
|
||||||
return ((l,ty):rs,mb_ty)
|
return ((l,ty):rs,mb_ty)
|
||||||
|
|
||||||
-- | Invariant: if the third argument is (Just rho),
|
-- | Invariant: if the third argument is (Just rho),
|
||||||
-- then rho is in weak-prenex form
|
-- then rho is in weak-prenex form
|
||||||
instSigma :: GlobalEnv -> Scope -> Term -> Sigma -> Maybe Rho -> TcM (Term, Rho)
|
instSigma :: GlobalEnv -> Scope -> Term -> Sigma -> Maybe Rho -> TcM (Term, Rho)
|
||||||
instSigma ge scope t ty1 Nothing = return (t,ty1) -- INST1
|
instSigma ge scope t ty1 Nothing = return (t,ty1) -- INST1
|
||||||
instSigma ge scope t ty1 (Just ty2) = do -- INST2
|
instSigma ge scope t ty1 (Just ty2) = do -- INST2
|
||||||
@@ -444,11 +444,11 @@ subsCheckRho ge scope t (VApp p1 _) (VApp p2 _) -- Rule
|
|||||||
| predefName p1 == cInts && predefName p2 == cInt = return t
|
| predefName p1 == cInts && predefName p2 == cInt = return t
|
||||||
subsCheckRho ge scope t (VApp p1 [VInt i]) (VApp p2 [VInt j]) -- Rule INT2
|
subsCheckRho ge scope t (VApp p1 [VInt i]) (VApp p2 [VInt j]) -- Rule INT2
|
||||||
| predefName p1 == cInts && predefName p2 == cInts =
|
| predefName p1 == cInts && predefName p2 == cInts =
|
||||||
if i <= j
|
if i <= j
|
||||||
then return t
|
then return t
|
||||||
else tcError ("Ints" <+> i <+> "is not a subtype of" <+> "Ints" <+> j)
|
else tcError ("Ints" <+> i <+> "is not a subtype of" <+> "Ints" <+> j)
|
||||||
subsCheckRho ge scope t ty1@(VRecType rs1) ty2@(VRecType rs2) = do -- Rule REC
|
subsCheckRho ge scope t ty1@(VRecType rs1) ty2@(VRecType rs2) = do -- Rule REC
|
||||||
let mkAccess scope t =
|
let mkAccess scope t =
|
||||||
case t of
|
case t of
|
||||||
ExtR t1 t2 -> do (scope,mkProj1,mkWrap1) <- mkAccess scope t1
|
ExtR t1 t2 -> do (scope,mkProj1,mkWrap1) <- mkAccess scope t1
|
||||||
(scope,mkProj2,mkWrap2) <- mkAccess scope t2
|
(scope,mkProj2,mkWrap2) <- mkAccess scope t2
|
||||||
@@ -557,7 +557,7 @@ unify ge scope v (VMeta i env vs) = unifyVar ge scope i env vs v
|
|||||||
unify ge scope v1 v2 = do
|
unify ge scope v1 v2 = do
|
||||||
t1 <- zonkTerm =<< tc_value2term (geLoc ge) (scopeVars scope) v1
|
t1 <- zonkTerm =<< tc_value2term (geLoc ge) (scopeVars scope) v1
|
||||||
t2 <- zonkTerm =<< tc_value2term (geLoc ge) (scopeVars scope) v2
|
t2 <- zonkTerm =<< tc_value2term (geLoc ge) (scopeVars scope) v2
|
||||||
tcError ("Cannot unify terms:" <+> (ppTerm Unqualified 0 t1 $$
|
tcError ("Cannot unify terms:" <+> (ppTerm Unqualified 0 t1 $$
|
||||||
ppTerm Unqualified 0 t2))
|
ppTerm Unqualified 0 t2))
|
||||||
|
|
||||||
-- | Invariant: tv1 is a flexible type variable
|
-- | Invariant: tv1 is a flexible type variable
|
||||||
@@ -568,9 +568,9 @@ unifyVar ge scope i env vs ty2 = do -- Check whether i is bound
|
|||||||
Bound ty1 -> do v <- liftErr (eval ge env ty1)
|
Bound ty1 -> do v <- liftErr (eval ge env ty1)
|
||||||
unify ge scope (vapply (geLoc ge) v vs) ty2
|
unify ge scope (vapply (geLoc ge) v vs) ty2
|
||||||
Unbound scope' _ -> case value2term (geLoc ge) (scopeVars scope') ty2 of
|
Unbound scope' _ -> case value2term (geLoc ge) (scopeVars scope') ty2 of
|
||||||
-- Left i -> let (v,_) = reverse scope !! i
|
Left i -> let (v,_) = reverse scope !! i
|
||||||
-- in tcError ("Variable" <+> pp v <+> "has escaped")
|
in tcError ("Variable" <+> pp v <+> "has escaped")
|
||||||
ty2' -> do ms2 <- getMetaVars (geLoc ge) [(scope,ty2)]
|
Right ty2' -> do ms2 <- getMetaVars (geLoc ge) [(scope,ty2)]
|
||||||
if i `elem` ms2
|
if i `elem` ms2
|
||||||
then tcError ("Occurs check for" <+> ppMeta i <+> "in:" $$
|
then tcError ("Occurs check for" <+> ppMeta i <+> "in:" $$
|
||||||
nest 2 (ppTerm Unqualified 0 ty2'))
|
nest 2 (ppTerm Unqualified 0 ty2'))
|
||||||
@@ -609,7 +609,7 @@ quantify ge scope t tvs ty0 = do
|
|||||||
ty <- tc_value2term (geLoc ge) (scopeVars scope) ty0
|
ty <- tc_value2term (geLoc ge) (scopeVars scope) ty0
|
||||||
let used_bndrs = nub (bndrs ty) -- Avoid quantified type variables in use
|
let used_bndrs = nub (bndrs ty) -- Avoid quantified type variables in use
|
||||||
new_bndrs = take (length tvs) (allBinders \\ used_bndrs)
|
new_bndrs = take (length tvs) (allBinders \\ used_bndrs)
|
||||||
mapM_ bind (tvs `zip` new_bndrs) -- 'bind' is just a cunning way
|
mapM_ bind (tvs `zip` new_bndrs) -- 'bind' is just a cunning way
|
||||||
ty <- zonkTerm ty -- of doing the substitution
|
ty <- zonkTerm ty -- of doing the substitution
|
||||||
vty <- liftErr (eval ge [] (foldr (\v ty -> Prod Implicit v typeType ty) ty new_bndrs))
|
vty <- liftErr (eval ge [] (foldr (\v ty -> Prod Implicit v typeType ty) ty new_bndrs))
|
||||||
return (foldr (Abs Implicit) t new_bndrs,vty)
|
return (foldr (Abs Implicit) t new_bndrs,vty)
|
||||||
@@ -619,7 +619,7 @@ quantify ge scope t tvs ty0 = do
|
|||||||
bndrs (Prod _ x t1 t2) = [x] ++ bndrs t1 ++ bndrs t2
|
bndrs (Prod _ x t1 t2) = [x] ++ bndrs t1 ++ bndrs t2
|
||||||
bndrs _ = []
|
bndrs _ = []
|
||||||
|
|
||||||
allBinders :: [Ident] -- a,b,..z, a1, b1,... z1, a2, b2,...
|
allBinders :: [Ident] -- a,b,..z, a1, b1,... z1, a2, b2,...
|
||||||
allBinders = [ identS [x] | x <- ['a'..'z'] ] ++
|
allBinders = [ identS [x] | x <- ['a'..'z'] ] ++
|
||||||
[ identS (x : show i) | i <- [1 :: Integer ..], x <- ['a'..'z']]
|
[ identS (x : show i) | i <- [1 :: Integer ..], x <- ['a'..'z']]
|
||||||
|
|
||||||
@@ -631,8 +631,8 @@ allBinders = [ identS [x] | x <- ['a'..'z'] ] ++
|
|||||||
type Scope = [(Ident,Value)]
|
type Scope = [(Ident,Value)]
|
||||||
|
|
||||||
type Sigma = Value
|
type Sigma = Value
|
||||||
type Rho = Value -- No top-level ForAll
|
type Rho = Value -- No top-level ForAll
|
||||||
type Tau = Value -- No ForAlls anywhere
|
type Tau = Value -- No ForAlls anywhere
|
||||||
|
|
||||||
data MetaValue
|
data MetaValue
|
||||||
= Unbound Scope Sigma
|
= Unbound Scope Sigma
|
||||||
@@ -688,12 +688,12 @@ runTcM f = case unTcM f IntMap.empty [] of
|
|||||||
TcFail (msg:msgs) -> do checkWarnings msgs; checkError msg
|
TcFail (msg:msgs) -> do checkWarnings msgs; checkError msg
|
||||||
|
|
||||||
newMeta :: Scope -> Sigma -> TcM MetaId
|
newMeta :: Scope -> Sigma -> TcM MetaId
|
||||||
newMeta scope ty = TcM (\ms msgs ->
|
newMeta scope ty = TcM (\ms msgs ->
|
||||||
let i = IntMap.size ms
|
let i = IntMap.size ms
|
||||||
in TcOk i (IntMap.insert i (Unbound scope ty) ms) msgs)
|
in TcOk i (IntMap.insert i (Unbound scope ty) ms) msgs)
|
||||||
|
|
||||||
getMeta :: MetaId -> TcM MetaValue
|
getMeta :: MetaId -> TcM MetaValue
|
||||||
getMeta i = TcM (\ms msgs ->
|
getMeta i = TcM (\ms msgs ->
|
||||||
case IntMap.lookup i ms of
|
case IntMap.lookup i ms of
|
||||||
Just mv -> TcOk mv ms msgs
|
Just mv -> TcOk mv ms msgs
|
||||||
Nothing -> TcFail (("Unknown metavariable" <+> ppMeta i) : msgs))
|
Nothing -> TcFail (("Unknown metavariable" <+> ppMeta i) : msgs))
|
||||||
@@ -702,7 +702,7 @@ setMeta :: MetaId -> MetaValue -> TcM ()
|
|||||||
setMeta i mv = TcM (\ms msgs -> TcOk () (IntMap.insert i mv ms) msgs)
|
setMeta i mv = TcM (\ms msgs -> TcOk () (IntMap.insert i mv ms) msgs)
|
||||||
|
|
||||||
newVar :: Scope -> Ident
|
newVar :: Scope -> Ident
|
||||||
newVar scope = head [x | i <- [1..],
|
newVar scope = head [x | i <- [1..],
|
||||||
let x = identS ('v':show i),
|
let x = identS ('v':show i),
|
||||||
isFree scope x]
|
isFree scope x]
|
||||||
where
|
where
|
||||||
@@ -721,11 +721,11 @@ getMetaVars loc sc_tys = do
|
|||||||
return (foldr go [] tys)
|
return (foldr go [] tys)
|
||||||
where
|
where
|
||||||
-- Get the MetaIds from a term; no duplicates in result
|
-- Get the MetaIds from a term; no duplicates in result
|
||||||
go (Vr tv) acc = acc
|
go (Vr tv) acc = acc
|
||||||
go (App x y) acc = go x (go y acc)
|
go (App x y) acc = go x (go y acc)
|
||||||
go (Meta i) acc
|
go (Meta i) acc
|
||||||
| i `elem` acc = acc
|
| i `elem` acc = acc
|
||||||
| otherwise = i : acc
|
| otherwise = i : acc
|
||||||
go (Q _) acc = acc
|
go (Q _) acc = acc
|
||||||
go (QC _) acc = acc
|
go (QC _) acc = acc
|
||||||
go (Sort _) acc = acc
|
go (Sort _) acc = acc
|
||||||
@@ -741,10 +741,10 @@ getFreeVars loc sc_tys = do
|
|||||||
tys <- mapM (\(scope,ty) -> zonkTerm =<< tc_value2term loc (scopeVars scope) ty) sc_tys
|
tys <- mapM (\(scope,ty) -> zonkTerm =<< tc_value2term loc (scopeVars scope) ty) sc_tys
|
||||||
return (foldr (go []) [] tys)
|
return (foldr (go []) [] tys)
|
||||||
where
|
where
|
||||||
go bound (Vr tv) acc
|
go bound (Vr tv) acc
|
||||||
| tv `elem` bound = acc
|
| tv `elem` bound = acc
|
||||||
| tv `elem` acc = acc
|
| tv `elem` acc = acc
|
||||||
| otherwise = tv : acc
|
| otherwise = tv : acc
|
||||||
go bound (App x y) acc = go bound x (go bound y acc)
|
go bound (App x y) acc = go bound x (go bound y acc)
|
||||||
go bound (Meta _) acc = acc
|
go bound (Meta _) acc = acc
|
||||||
go bound (Q _) acc = acc
|
go bound (Q _) acc = acc
|
||||||
@@ -765,13 +765,13 @@ zonkTerm (Meta i) = do
|
|||||||
zonkTerm t = composOp zonkTerm t
|
zonkTerm t = composOp zonkTerm t
|
||||||
|
|
||||||
tc_value2term loc xs v =
|
tc_value2term loc xs v =
|
||||||
return $ value2term loc xs v
|
case value2term loc xs v of
|
||||||
-- Old value2term error message:
|
Left i -> tcError ("Variable #" <+> pp i <+> "has escaped")
|
||||||
-- Left i -> tcError ("Variable #" <+> pp i <+> "has escaped")
|
Right t -> return t
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
data TcA x a
|
data TcA x a
|
||||||
= TcSingle (MetaStore -> [Message] -> TcResult a)
|
= TcSingle (MetaStore -> [Message] -> TcResult a)
|
||||||
| TcMany [x] (MetaStore -> [Message] -> [(a,MetaStore,[Message])])
|
| TcMany [x] (MetaStore -> [Message] -> [(a,MetaStore,[Message])])
|
||||||
|
|
||||||
|
|||||||
801
src/compiler/GF/Compile/TypeCheck/RConcrete.hs
Normal file
801
src/compiler/GF/Compile/TypeCheck/RConcrete.hs
Normal file
@@ -0,0 +1,801 @@
|
|||||||
|
{-# LANGUAGE PatternGuards #-}
|
||||||
|
module GF.Compile.TypeCheck.RConcrete( checkLType, inferLType, computeLType, ppType ) where
|
||||||
|
import Prelude hiding ((<>)) -- GHC 8.4.1 clash with Text.PrettyPrint
|
||||||
|
|
||||||
|
import GF.Infra.CheckM
|
||||||
|
import GF.Data.Operations
|
||||||
|
|
||||||
|
import GF.Grammar
|
||||||
|
import GF.Grammar.Lookup
|
||||||
|
import GF.Grammar.Predef
|
||||||
|
import GF.Grammar.PatternMatch
|
||||||
|
import GF.Grammar.Lockfield (isLockLabel, lockRecType, unlockRecord)
|
||||||
|
import GF.Compile.TypeCheck.Primitives
|
||||||
|
|
||||||
|
import Data.List
|
||||||
|
import Control.Monad
|
||||||
|
import GF.Text.Pretty
|
||||||
|
|
||||||
|
computeLType :: SourceGrammar -> Context -> Type -> Check Type
|
||||||
|
computeLType gr g0 t = comp (reverse [(b,x, Vr x) | (b,x,_) <- g0] ++ g0) t
|
||||||
|
where
|
||||||
|
comp g ty = case ty of
|
||||||
|
_ | Just _ <- isTypeInts ty -> return ty ---- shouldn't be needed
|
||||||
|
| isPredefConstant ty -> return ty ---- shouldn't be needed
|
||||||
|
|
||||||
|
Q (m,ident) -> checkIn ("module" <+> m) $ do
|
||||||
|
ty' <- lookupResDef gr (m,ident)
|
||||||
|
if ty' == ty then return ty else comp g ty' --- is this necessary to test?
|
||||||
|
|
||||||
|
AdHocOverload ts -> do
|
||||||
|
over <- getOverload gr g (Just typeType) t
|
||||||
|
case over of
|
||||||
|
Just (tr,_) -> return tr
|
||||||
|
_ -> checkError ("unresolved overloading of constants" <+> ppTerm Qualified 0 t)
|
||||||
|
|
||||||
|
Vr ident -> checkLookup ident g -- never needed to compute!
|
||||||
|
|
||||||
|
App f a -> do
|
||||||
|
f' <- comp g f
|
||||||
|
a' <- comp g a
|
||||||
|
case f' of
|
||||||
|
Abs b x t -> comp ((b,x,a'):g) t
|
||||||
|
_ -> return $ App f' a'
|
||||||
|
|
||||||
|
Prod bt x a b -> do
|
||||||
|
a' <- comp g a
|
||||||
|
b' <- comp ((bt,x,Vr x) : g) b
|
||||||
|
return $ Prod bt x a' b'
|
||||||
|
|
||||||
|
Abs bt x b -> do
|
||||||
|
b' <- comp ((bt,x,Vr x):g) b
|
||||||
|
return $ Abs bt x b'
|
||||||
|
|
||||||
|
Let (x,(_,a)) b -> comp ((Explicit,x,a):g) b
|
||||||
|
|
||||||
|
ExtR r s -> do
|
||||||
|
r' <- comp g r
|
||||||
|
s' <- comp g s
|
||||||
|
case (r',s') of
|
||||||
|
(RecType rs, RecType ss) -> plusRecType r' s' >>= comp g
|
||||||
|
_ -> return $ ExtR r' s'
|
||||||
|
|
||||||
|
RecType fs -> do
|
||||||
|
let fs' = sortRec fs
|
||||||
|
liftM RecType $ mapPairsM (comp g) fs'
|
||||||
|
|
||||||
|
ELincat c t -> do
|
||||||
|
t' <- comp g t
|
||||||
|
lockRecType c t' ---- locking to be removed AR 20/6/2009
|
||||||
|
|
||||||
|
_ | ty == typeTok -> return typeStr
|
||||||
|
_ | isPredefConstant ty -> return ty
|
||||||
|
|
||||||
|
_ -> composOp (comp g) ty
|
||||||
|
|
||||||
|
-- the underlying algorithms
|
||||||
|
|
||||||
|
inferLType :: SourceGrammar -> Context -> Term -> Check (Term, Type)
|
||||||
|
inferLType gr g trm = case trm of
|
||||||
|
|
||||||
|
Q (m,ident) | isPredef m -> termWith trm $ case typPredefined ident of
|
||||||
|
Just ty -> return ty
|
||||||
|
Nothing -> checkError ("unknown in Predef:" <+> ident)
|
||||||
|
|
||||||
|
Q ident -> checks [
|
||||||
|
termWith trm $ lookupResType gr ident >>= computeLType gr g
|
||||||
|
,
|
||||||
|
lookupResDef gr ident >>= inferLType gr g
|
||||||
|
,
|
||||||
|
checkError ("cannot infer type of constant" <+> ppTerm Unqualified 0 trm)
|
||||||
|
]
|
||||||
|
|
||||||
|
QC (m,ident) | isPredef m -> termWith trm $ case typPredefined ident of
|
||||||
|
Just ty -> return ty
|
||||||
|
Nothing -> checkError ("unknown in Predef:" <+> ident)
|
||||||
|
|
||||||
|
QC ident -> checks [
|
||||||
|
termWith trm $ lookupResType gr ident >>= computeLType gr g
|
||||||
|
,
|
||||||
|
lookupResDef gr ident >>= inferLType gr g
|
||||||
|
,
|
||||||
|
checkError ("cannot infer type of canonical constant" <+> ppTerm Unqualified 0 trm)
|
||||||
|
]
|
||||||
|
|
||||||
|
Vr ident -> termWith trm $ checkLookup ident g
|
||||||
|
|
||||||
|
Typed e t -> do
|
||||||
|
t' <- computeLType gr g t
|
||||||
|
checkLType gr g e t'
|
||||||
|
|
||||||
|
AdHocOverload ts -> do
|
||||||
|
over <- getOverload gr g Nothing trm
|
||||||
|
case over of
|
||||||
|
Just trty -> return trty
|
||||||
|
_ -> checkError ("unresolved overloading of constants" <+> ppTerm Qualified 0 trm)
|
||||||
|
|
||||||
|
App f a -> do
|
||||||
|
over <- getOverload gr g Nothing trm
|
||||||
|
case over of
|
||||||
|
Just trty -> return trty
|
||||||
|
_ -> do
|
||||||
|
(f',fty) <- inferLType gr g f
|
||||||
|
fty' <- computeLType gr g fty
|
||||||
|
case fty' of
|
||||||
|
Prod bt z arg val -> do
|
||||||
|
a' <- justCheck g a arg
|
||||||
|
ty <- if isWildIdent z
|
||||||
|
then return val
|
||||||
|
else substituteLType [(bt,z,a')] val
|
||||||
|
return (App f' a',ty)
|
||||||
|
_ ->
|
||||||
|
let term = ppTerm Unqualified 0 f
|
||||||
|
funName = pp . head . words .render $ term
|
||||||
|
in checkError ("A function type is expected for" <+> term <+> "instead of type" <+> ppType fty $$
|
||||||
|
"\n ** Maybe you gave too many arguments to" <+> funName <+> "\n")
|
||||||
|
|
||||||
|
S f x -> do
|
||||||
|
(f', fty) <- inferLType gr g f
|
||||||
|
case fty of
|
||||||
|
Table arg val -> do
|
||||||
|
x'<- justCheck g x arg
|
||||||
|
return (S f' x', val)
|
||||||
|
_ -> checkError ("table lintype expected for the table in" $$ nest 2 (ppTerm Unqualified 0 trm))
|
||||||
|
|
||||||
|
P t i -> do
|
||||||
|
(t',ty) <- inferLType gr g t --- ??
|
||||||
|
ty' <- computeLType gr g ty
|
||||||
|
let tr2 = P t' i
|
||||||
|
termWith tr2 $ case ty' of
|
||||||
|
RecType ts -> case lookup i ts of
|
||||||
|
Nothing -> checkError ("unknown label" <+> i <+> "in" $$ nest 2 (ppTerm Unqualified 0 ty'))
|
||||||
|
Just x -> return x
|
||||||
|
_ -> checkError ("record type expected for:" <+> ppTerm Unqualified 0 t $$
|
||||||
|
" instead of the inferred:" <+> ppTerm Unqualified 0 ty')
|
||||||
|
|
||||||
|
R r -> do
|
||||||
|
let (ls,fs) = unzip r
|
||||||
|
fsts <- mapM inferM fs
|
||||||
|
let ts = [ty | (Just ty,_) <- fsts]
|
||||||
|
checkCond ("cannot infer type of record" $$ nest 2 (ppTerm Unqualified 0 trm)) (length ts == length fsts)
|
||||||
|
return $ (R (zip ls fsts), RecType (zip ls ts))
|
||||||
|
|
||||||
|
T (TTyped arg) pts -> do
|
||||||
|
(_,val) <- checks $ map (inferCase (Just arg)) pts
|
||||||
|
checkLType gr g trm (Table arg val)
|
||||||
|
T (TComp arg) pts -> do
|
||||||
|
(_,val) <- checks $ map (inferCase (Just arg)) pts
|
||||||
|
checkLType gr g trm (Table arg val)
|
||||||
|
T ti pts -> do -- tries to guess: good in oper type inference
|
||||||
|
let pts' = [pt | pt@(p,_) <- pts, isConstPatt p]
|
||||||
|
case pts' of
|
||||||
|
[] -> checkError ("cannot infer table type of" <+> ppTerm Unqualified 0 trm)
|
||||||
|
---- PInt k : _ -> return $ Ints $ max [i | PInt i <- pts']
|
||||||
|
_ -> do
|
||||||
|
(arg,val) <- checks $ map (inferCase Nothing) pts'
|
||||||
|
checkLType gr g trm (Table arg val)
|
||||||
|
V arg pts -> do
|
||||||
|
(_,val) <- checks $ map (inferLType gr g) pts
|
||||||
|
-- return (trm, Table arg val) -- old, caused issue 68
|
||||||
|
checkLType gr g trm (Table arg val)
|
||||||
|
|
||||||
|
K s -> do
|
||||||
|
if elem ' ' s
|
||||||
|
then do
|
||||||
|
let ss = foldr C Empty (map K (words s))
|
||||||
|
----- removed irritating warning AR 24/5/2008
|
||||||
|
----- checkWarn ("token \"" ++ s ++
|
||||||
|
----- "\" converted to token list" ++ prt ss)
|
||||||
|
return (ss, typeStr)
|
||||||
|
else return (trm, typeStr)
|
||||||
|
|
||||||
|
EInt i -> return (trm, typeInt)
|
||||||
|
|
||||||
|
EFloat i -> return (trm, typeFloat)
|
||||||
|
|
||||||
|
Empty -> return (trm, typeStr)
|
||||||
|
|
||||||
|
C s1 s2 ->
|
||||||
|
check2 (flip (justCheck g) typeStr) C s1 s2 typeStr
|
||||||
|
|
||||||
|
Glue s1 s2 ->
|
||||||
|
check2 (flip (justCheck g) typeStr) Glue s1 s2 typeStr ---- typeTok
|
||||||
|
|
||||||
|
---- hack from Rename.identRenameTerm, to live with files with naming conflicts 18/6/2007
|
||||||
|
Strs (Cn c : ts) | c == cConflict -> do
|
||||||
|
checkWarn ("unresolved constant, could be any of" <+> hcat (map (ppTerm Unqualified 0) ts))
|
||||||
|
inferLType gr g (head ts)
|
||||||
|
|
||||||
|
Strs ts -> do
|
||||||
|
ts' <- mapM (\t -> justCheck g t typeStr) ts
|
||||||
|
return (Strs ts', typeStrs)
|
||||||
|
|
||||||
|
Alts t aa -> do
|
||||||
|
t' <- justCheck g t typeStr
|
||||||
|
aa' <- flip mapM aa (\ (c,v) -> do
|
||||||
|
c' <- justCheck g c typeStr
|
||||||
|
v' <- checks $ map (justCheck g v) [typeStrs, EPattType typeStr]
|
||||||
|
return (c',v'))
|
||||||
|
return (Alts t' aa', typeStr)
|
||||||
|
|
||||||
|
RecType r -> do
|
||||||
|
let (ls,ts) = unzip r
|
||||||
|
ts' <- mapM (flip (justCheck g) typeType) ts
|
||||||
|
return (RecType (zip ls ts'), typeType)
|
||||||
|
|
||||||
|
ExtR r s -> do
|
||||||
|
|
||||||
|
--- over <- getOverload gr g Nothing r
|
||||||
|
--- let r1 = maybe r fst over
|
||||||
|
let r1 = r ---
|
||||||
|
|
||||||
|
(r',rT) <- inferLType gr g r1
|
||||||
|
rT' <- computeLType gr g rT
|
||||||
|
|
||||||
|
(s',sT) <- inferLType gr g s
|
||||||
|
sT' <- computeLType gr g sT
|
||||||
|
|
||||||
|
let trm' = ExtR r' s'
|
||||||
|
case (rT', sT') of
|
||||||
|
(RecType rs, RecType ss) -> do
|
||||||
|
let rt = RecType ([field | field@(l,_) <- rs, notElem l (map fst ss)] ++ ss) -- select types of later fields
|
||||||
|
checkLType gr g trm' rt ---- return (trm', rt)
|
||||||
|
_ | rT' == typeType && sT' == typeType -> do
|
||||||
|
return (trm', typeType)
|
||||||
|
_ -> checkError ("records or record types expected in" <+> ppTerm Unqualified 0 trm)
|
||||||
|
|
||||||
|
Sort _ ->
|
||||||
|
termWith trm $ return typeType
|
||||||
|
|
||||||
|
Prod bt x a b -> do
|
||||||
|
a' <- justCheck g a typeType
|
||||||
|
b' <- justCheck ((bt,x,a'):g) b typeType
|
||||||
|
return (Prod bt x a' b', typeType)
|
||||||
|
|
||||||
|
Table p t -> do
|
||||||
|
p' <- justCheck g p typeType --- check p partype!
|
||||||
|
t' <- justCheck g t typeType
|
||||||
|
return $ (Table p' t', typeType)
|
||||||
|
|
||||||
|
FV vs -> do
|
||||||
|
(_,ty) <- checks $ map (inferLType gr g) vs
|
||||||
|
--- checkIfComplexVariantType trm ty
|
||||||
|
checkLType gr g trm ty
|
||||||
|
|
||||||
|
EPattType ty -> do
|
||||||
|
ty' <- justCheck g ty typeType
|
||||||
|
return (EPattType ty',typeType)
|
||||||
|
EPatt p -> do
|
||||||
|
ty <- inferPatt p
|
||||||
|
return (trm, EPattType ty)
|
||||||
|
|
||||||
|
ELin c trm -> do
|
||||||
|
(trm',ty) <- inferLType gr g trm
|
||||||
|
ty' <- lockRecType c ty ---- lookup c; remove lock AR 20/6/2009
|
||||||
|
return $ (ELin c trm', ty')
|
||||||
|
|
||||||
|
_ -> checkError ("cannot infer lintype of" <+> ppTerm Unqualified 0 trm)
|
||||||
|
|
||||||
|
where
|
||||||
|
isPredef m = elem m [cPredef,cPredefAbs]
|
||||||
|
|
||||||
|
justCheck g ty te = checkLType gr g ty te >>= return . fst
|
||||||
|
|
||||||
|
-- for record fields, which may be typed
|
||||||
|
inferM (mty, t) = do
|
||||||
|
(t', ty') <- case mty of
|
||||||
|
Just ty -> checkLType gr g t ty
|
||||||
|
_ -> inferLType gr g t
|
||||||
|
return (Just ty',t')
|
||||||
|
|
||||||
|
inferCase mty (patt,term) = do
|
||||||
|
arg <- maybe (inferPatt patt) return mty
|
||||||
|
cont <- pattContext gr g arg patt
|
||||||
|
(_,val) <- inferLType gr (reverse cont ++ g) term
|
||||||
|
return (arg,val)
|
||||||
|
isConstPatt p = case p of
|
||||||
|
PC _ ps -> True --- all isConstPatt ps
|
||||||
|
PP _ ps -> True --- all isConstPatt ps
|
||||||
|
PR ps -> all (isConstPatt . snd) ps
|
||||||
|
PT _ p -> isConstPatt p
|
||||||
|
PString _ -> True
|
||||||
|
PInt _ -> True
|
||||||
|
PFloat _ -> True
|
||||||
|
PChar -> True
|
||||||
|
PChars _ -> True
|
||||||
|
PSeq p q -> isConstPatt p && isConstPatt q
|
||||||
|
PAlt p q -> isConstPatt p && isConstPatt q
|
||||||
|
PRep p -> isConstPatt p
|
||||||
|
PNeg p -> isConstPatt p
|
||||||
|
PAs _ p -> isConstPatt p
|
||||||
|
_ -> False
|
||||||
|
|
||||||
|
inferPatt p = case p of
|
||||||
|
PP (q,c) ps | q /= cPredef -> liftM valTypeCnc (lookupResType gr (q,c))
|
||||||
|
PAs _ p -> inferPatt p
|
||||||
|
PNeg p -> inferPatt p
|
||||||
|
PAlt p q -> checks [inferPatt p, inferPatt q]
|
||||||
|
PSeq _ _ -> return $ typeStr
|
||||||
|
PRep _ -> return $ typeStr
|
||||||
|
PChar -> return $ typeStr
|
||||||
|
PChars _ -> return $ typeStr
|
||||||
|
_ -> inferLType gr g (patt2term p) >>= return . snd
|
||||||
|
|
||||||
|
-- type inference: Nothing, type checking: Just t
|
||||||
|
-- the latter permits matching with value type
|
||||||
|
getOverload :: SourceGrammar -> Context -> Maybe Type -> Term -> Check (Maybe (Term,Type))
|
||||||
|
getOverload gr g mt ot = case appForm ot of
|
||||||
|
(f@(Q c), ts) -> case lookupOverload gr c of
|
||||||
|
Ok typs -> do
|
||||||
|
ttys <- mapM (inferLType gr g) ts
|
||||||
|
v <- matchOverload f typs ttys
|
||||||
|
return $ Just v
|
||||||
|
_ -> return Nothing
|
||||||
|
(AdHocOverload cs@(f:_), ts) -> do --- the function name f is only used in error messages
|
||||||
|
let typs = concatMap collectOverloads cs
|
||||||
|
ttys <- mapM (inferLType gr g) ts
|
||||||
|
v <- matchOverload f typs ttys
|
||||||
|
return $ Just v
|
||||||
|
_ -> return Nothing
|
||||||
|
|
||||||
|
where
|
||||||
|
collectOverloads tr@(Q c) = case lookupOverload gr c of
|
||||||
|
Ok typs -> typs
|
||||||
|
_ -> case lookupResType gr c of
|
||||||
|
Ok ty -> let (args,val) = typeFormCnc ty in [(map (\(b,x,t) -> t) args,(val,tr))]
|
||||||
|
_ -> []
|
||||||
|
collectOverloads _ = [] --- constructors QC
|
||||||
|
|
||||||
|
matchOverload f typs ttys = do
|
||||||
|
let (tts,tys) = unzip ttys
|
||||||
|
let vfs = lookupOverloadInstance tys typs
|
||||||
|
let matches = [vf | vf@((_,v,_),_) <- vfs, matchVal mt v]
|
||||||
|
let showTypes ty = hsep (map ppType ty)
|
||||||
|
|
||||||
|
|
||||||
|
let (stys,styps) = (showTypes tys, [showTypes ty | (ty,_) <- typs])
|
||||||
|
|
||||||
|
-- to avoid strange error msg e.g. in case of unmatch record extension, show whole types if needed AR 28/1/2013
|
||||||
|
let (stysError,stypsError) = if elem (render stys) (map render styps)
|
||||||
|
then (hsep (map (ppTerm Unqualified 0) tys), [hsep (map (ppTerm Unqualified 0) ty) | (ty,_) <- typs])
|
||||||
|
else (stys,styps)
|
||||||
|
|
||||||
|
case ([vf | (vf,True) <- matches],[vf | (vf,False) <- matches]) of
|
||||||
|
([(_,val,fun)],_) -> return (mkApp fun tts, val)
|
||||||
|
([],[(pre,val,fun)]) -> do
|
||||||
|
checkWarn $ "ignoring lock fields in resolving" <+> ppTerm Unqualified 0 ot $$
|
||||||
|
"for" $$
|
||||||
|
nest 2 (showTypes tys) $$
|
||||||
|
"using" $$
|
||||||
|
nest 2 (showTypes pre)
|
||||||
|
return (mkApp fun tts, val)
|
||||||
|
([],[]) -> do
|
||||||
|
checkError $ "no overload instance of" <+> ppTerm Qualified 0 f $$
|
||||||
|
maybe empty (\x -> "with value type" <+> ppType x) mt $$
|
||||||
|
"for argument list" $$
|
||||||
|
nest 2 stysError $$
|
||||||
|
"among alternatives" $$
|
||||||
|
nest 2 (vcat stypsError)
|
||||||
|
|
||||||
|
|
||||||
|
(vfs1,vfs2) -> case (noProds vfs1,noProds vfs2) of
|
||||||
|
([(val,fun)],_) -> do
|
||||||
|
return (mkApp fun tts, val)
|
||||||
|
([],[(val,fun)]) -> do
|
||||||
|
checkWarn ("ignoring lock fields in resolving" <+> ppTerm Unqualified 0 ot)
|
||||||
|
return (mkApp fun tts, val)
|
||||||
|
|
||||||
|
----- unsafely exclude irritating warning AR 24/5/2008
|
||||||
|
----- checkWarn $ "overloading of" +++ prt f +++
|
||||||
|
----- "resolved by excluding partial applications:" ++++
|
||||||
|
----- unlines [prtType env ty | (ty,_) <- vfs', not (noProd ty)]
|
||||||
|
|
||||||
|
--- now forgiving ambiguity with a warning AR 1/2/2014
|
||||||
|
-- This gives ad hoc overloading the same behaviour as the choice of the first match in renaming did before.
|
||||||
|
-- But it also gives a chance to ambiguous overloadings that were banned before.
|
||||||
|
(nps1,nps2) -> do
|
||||||
|
checkWarn $ "ambiguous overloading of" <+> ppTerm Unqualified 0 f <+>
|
||||||
|
---- "with argument types" <+> hsep (map (ppTerm Qualified 0) tys) $$
|
||||||
|
"resolved by selecting the first of the alternatives" $$
|
||||||
|
nest 2 (vcat [ppTerm Qualified 0 fun | (_,ty,fun) <- vfs1 ++ if null vfs1 then vfs2 else []])
|
||||||
|
case [(mkApp fun tts,val) | (val,fun) <- nps1 ++ nps2] of
|
||||||
|
[] -> checkError $ "no alternatives left when resolving" <+> ppTerm Unqualified 0 f
|
||||||
|
h:_ -> return h
|
||||||
|
|
||||||
|
matchVal mt v = elem mt [Nothing,Just v,Just (unlocked v)]
|
||||||
|
|
||||||
|
unlocked v = case v of
|
||||||
|
RecType fs -> RecType $ filter (not . isLockLabel . fst) (sortRec fs)
|
||||||
|
_ -> v
|
||||||
|
---- TODO: accept subtypes
|
||||||
|
---- TODO: use a trie
|
||||||
|
lookupOverloadInstance tys typs =
|
||||||
|
[((pre,mkFunType rest val, t),isExact) |
|
||||||
|
let lt = length tys,
|
||||||
|
(ty,(val,t)) <- typs, length ty >= lt,
|
||||||
|
let (pre,rest) = splitAt lt ty,
|
||||||
|
let isExact = pre == tys,
|
||||||
|
isExact || map unlocked pre == map unlocked tys
|
||||||
|
]
|
||||||
|
|
||||||
|
noProds vfs = [(v,f) | (_,v,f) <- vfs, noProd v]
|
||||||
|
|
||||||
|
noProd ty = case ty of
|
||||||
|
Prod _ _ _ _ -> False
|
||||||
|
_ -> True
|
||||||
|
|
||||||
|
checkLType :: SourceGrammar -> Context -> Term -> Type -> Check (Term, Type)
|
||||||
|
checkLType gr g trm typ0 = do
|
||||||
|
typ <- computeLType gr g typ0
|
||||||
|
|
||||||
|
case trm of
|
||||||
|
|
||||||
|
Abs bt x c -> do
|
||||||
|
case typ of
|
||||||
|
Prod bt' z a b -> do
|
||||||
|
(c',b') <- if isWildIdent z
|
||||||
|
then checkLType gr ((bt,x,a):g) c b
|
||||||
|
else do b' <- checkIn (pp "abs") $ substituteLType [(bt',z,Vr x)] b
|
||||||
|
checkLType gr ((bt,x,a):g) c b'
|
||||||
|
return $ (Abs bt x c', Prod bt' z a b')
|
||||||
|
_ -> checkError $ "function type expected instead of" <+> ppType typ $$
|
||||||
|
"\n ** Double-check that the type signature of the operation" $$
|
||||||
|
"matches the number of arguments given to it.\n"
|
||||||
|
|
||||||
|
App f a -> do
|
||||||
|
over <- getOverload gr g (Just typ) trm
|
||||||
|
case over of
|
||||||
|
Just trty -> return trty
|
||||||
|
_ -> do
|
||||||
|
(trm',ty') <- inferLType gr g trm
|
||||||
|
termWith trm' $ checkEqLType gr g typ ty' trm'
|
||||||
|
|
||||||
|
AdHocOverload ts -> do
|
||||||
|
over <- getOverload gr g Nothing trm
|
||||||
|
case over of
|
||||||
|
Just trty -> return trty
|
||||||
|
_ -> checkError ("unresolved overloading of constants" <+> ppTerm Qualified 0 trm)
|
||||||
|
|
||||||
|
Q _ -> do
|
||||||
|
over <- getOverload gr g (Just typ) trm
|
||||||
|
case over of
|
||||||
|
Just trty -> return trty
|
||||||
|
_ -> do
|
||||||
|
(trm',ty') <- inferLType gr g trm
|
||||||
|
termWith trm' $ checkEqLType gr g typ ty' trm'
|
||||||
|
|
||||||
|
T _ [] ->
|
||||||
|
checkError ("found empty table in type" <+> ppTerm Unqualified 0 typ)
|
||||||
|
T _ cs -> case typ of
|
||||||
|
Table arg val -> do
|
||||||
|
case allParamValues gr arg of
|
||||||
|
Ok vs -> do
|
||||||
|
let ps0 = map fst cs
|
||||||
|
ps <- testOvershadow ps0 vs
|
||||||
|
if null ps
|
||||||
|
then return ()
|
||||||
|
else checkWarn ("patterns never reached:" $$
|
||||||
|
nest 2 (vcat (map (ppPatt Unqualified 0) ps)))
|
||||||
|
_ -> return () -- happens with variable types
|
||||||
|
cs' <- mapM (checkCase arg val) cs
|
||||||
|
return (T (TTyped arg) cs', typ)
|
||||||
|
_ -> checkError $ "table type expected for table instead of" $$ nest 2 (ppType typ)
|
||||||
|
V arg0 vs ->
|
||||||
|
case typ of
|
||||||
|
Table arg1 val ->
|
||||||
|
do arg' <- checkEqLType gr g arg0 arg1 trm
|
||||||
|
vs1 <- allParamValues gr arg1
|
||||||
|
if length vs1 == length vs
|
||||||
|
then return ()
|
||||||
|
else checkError $ "wrong number of values in table" <+> ppTerm Unqualified 0 trm
|
||||||
|
vs' <- map fst `fmap` sequence [checkLType gr g v val|v<-vs]
|
||||||
|
return (V arg' vs',typ)
|
||||||
|
|
||||||
|
R r -> case typ of --- why needed? because inference may be too difficult
|
||||||
|
RecType rr -> do
|
||||||
|
--let (ls,_) = unzip rr -- labels of expected type
|
||||||
|
fsts <- mapM (checkM r) rr -- check that they are found in the record
|
||||||
|
return $ (R fsts, typ) -- normalize record
|
||||||
|
|
||||||
|
_ -> checkError ("record type expected in type checking instead of" $$ nest 2 (ppTerm Unqualified 0 typ))
|
||||||
|
|
||||||
|
ExtR r s -> case typ of
|
||||||
|
_ | typ == typeType -> do
|
||||||
|
trm' <- computeLType gr g trm
|
||||||
|
case trm' of
|
||||||
|
RecType _ -> termWith trm' $ return typeType
|
||||||
|
ExtR (Vr _) (RecType _) -> termWith trm' $ return typeType
|
||||||
|
-- ext t = t ** ...
|
||||||
|
_ -> checkError ("invalid record type extension" <+> nest 2 (ppTerm Unqualified 0 trm))
|
||||||
|
|
||||||
|
RecType rr -> do
|
||||||
|
|
||||||
|
ll2 <- case s of
|
||||||
|
R ss -> return $ map fst ss
|
||||||
|
_ -> do
|
||||||
|
(s',typ2) <- inferLType gr g s
|
||||||
|
case typ2 of
|
||||||
|
RecType ss -> return $ map fst ss
|
||||||
|
_ -> checkError ("cannot get labels from" $$ nest 2 (ppTerm Unqualified 0 typ2))
|
||||||
|
let ll1 = [l | (l,_) <- rr, notElem l ll2]
|
||||||
|
|
||||||
|
--- over <- getOverload gr g Nothing r --- this would solve #66 but fail ParadigmsAra. AR 6/7/2020
|
||||||
|
--- let r1 = maybe r fst over
|
||||||
|
let r1 = r ---
|
||||||
|
|
||||||
|
(r',_) <- checkLType gr g r1 (RecType [field | field@(l,_) <- rr, elem l ll1])
|
||||||
|
(s',_) <- checkLType gr g s (RecType [field | field@(l,_) <- rr, elem l ll2])
|
||||||
|
|
||||||
|
let rec = R ([(l,(Nothing,P r' l)) | l <- ll1] ++ [(l,(Nothing,P s' l)) | l <- ll2])
|
||||||
|
return (rec, typ)
|
||||||
|
|
||||||
|
ExtR ty ex -> do
|
||||||
|
r' <- justCheck g r ty
|
||||||
|
s' <- justCheck g s ex
|
||||||
|
return $ (ExtR r' s', typ) --- is this all? it assumes the same division in trm and typ
|
||||||
|
|
||||||
|
_ -> checkError ("record extension not meaningful for" <+> ppTerm Unqualified 0 typ)
|
||||||
|
|
||||||
|
FV vs -> do
|
||||||
|
ttys <- mapM (flip (checkLType gr g) typ) vs
|
||||||
|
--- checkIfComplexVariantType trm typ
|
||||||
|
return (FV (map fst ttys), typ) --- typ' ?
|
||||||
|
|
||||||
|
S tab arg -> checks [ do
|
||||||
|
(tab',ty) <- inferLType gr g tab
|
||||||
|
ty' <- computeLType gr g ty
|
||||||
|
case ty' of
|
||||||
|
Table p t -> do
|
||||||
|
(arg',val) <- checkLType gr g arg p
|
||||||
|
checkEqLType gr g typ t trm
|
||||||
|
return (S tab' arg', t)
|
||||||
|
_ -> checkError ("table type expected for applied table instead of" <+> ppType ty')
|
||||||
|
, do
|
||||||
|
(arg',ty) <- inferLType gr g arg
|
||||||
|
ty' <- computeLType gr g ty
|
||||||
|
(tab',_) <- checkLType gr g tab (Table ty' typ)
|
||||||
|
return (S tab' arg', typ)
|
||||||
|
]
|
||||||
|
Let (x,(mty,def)) body -> case mty of
|
||||||
|
Just ty -> do
|
||||||
|
(ty0,_) <- checkLType gr g ty typeType
|
||||||
|
(def',ty') <- checkLType gr g def ty0
|
||||||
|
body' <- justCheck ((Explicit,x,ty'):g) body typ
|
||||||
|
return (Let (x,(Just ty',def')) body', typ)
|
||||||
|
_ -> do
|
||||||
|
(def',ty) <- inferLType gr g def -- tries to infer type of local constant
|
||||||
|
checkLType gr g (Let (x,(Just ty,def')) body) typ
|
||||||
|
|
||||||
|
ELin c tr -> do
|
||||||
|
tr1 <- unlockRecord c tr
|
||||||
|
checkLType gr g tr1 typ
|
||||||
|
|
||||||
|
_ -> do
|
||||||
|
(trm',ty') <- inferLType gr g trm
|
||||||
|
termWith trm' $ checkEqLType gr g typ ty' trm'
|
||||||
|
where
|
||||||
|
justCheck g ty te = checkLType gr g ty te >>= return . fst
|
||||||
|
{-
|
||||||
|
recParts rr t = (RecType rr1,RecType rr2) where
|
||||||
|
(rr1,rr2) = partition (flip elem (map fst t) . fst) rr
|
||||||
|
-}
|
||||||
|
checkM rms (l,ty) = case lookup l rms of
|
||||||
|
Just (Just ty0,t) -> do
|
||||||
|
checkEqLType gr g ty ty0 t
|
||||||
|
(t',ty') <- checkLType gr g t ty
|
||||||
|
return (l,(Just ty',t'))
|
||||||
|
Just (_,t) -> do
|
||||||
|
(t',ty') <- checkLType gr g t ty
|
||||||
|
return (l,(Just ty',t'))
|
||||||
|
_ -> checkError $
|
||||||
|
if isLockLabel l
|
||||||
|
then let cat = drop 5 (showIdent (label2ident l))
|
||||||
|
in ppTerm Unqualified 0 (R rms) <+> "is not in the lincat of" <+> cat <>
|
||||||
|
"; try wrapping it with lin" <+> cat
|
||||||
|
else "cannot find value for label" <+> l <+> "in" <+> ppTerm Unqualified 0 (R rms)
|
||||||
|
|
||||||
|
checkCase arg val (p,t) = do
|
||||||
|
cont <- pattContext gr g arg p
|
||||||
|
t' <- justCheck (reverse cont ++ g) t val
|
||||||
|
return (p,t')
|
||||||
|
|
||||||
|
pattContext :: SourceGrammar -> Context -> Type -> Patt -> Check Context
|
||||||
|
pattContext env g typ p = case p of
|
||||||
|
PV x -> return [(Explicit,x,typ)]
|
||||||
|
PP (q,c) ps | q /= cPredef -> do ---- why this /=? AR 6/1/2006
|
||||||
|
t <- lookupResType env (q,c)
|
||||||
|
let (cont,v) = typeFormCnc t
|
||||||
|
checkCond ("wrong number of arguments for constructor in" <+> ppPatt Unqualified 0 p)
|
||||||
|
(length cont == length ps)
|
||||||
|
checkEqLType env g typ v (patt2term p)
|
||||||
|
mapM (\((_,_,ty),p) -> pattContext env g ty p) (zip cont ps) >>= return . concat
|
||||||
|
PR r -> do
|
||||||
|
typ' <- computeLType env g typ
|
||||||
|
case typ' of
|
||||||
|
RecType t -> do
|
||||||
|
let pts = [(ty,tr) | (l,tr) <- r, Just ty <- [lookup l t]]
|
||||||
|
----- checkWarn $ prt p ++++ show pts ----- debug
|
||||||
|
mapM (uncurry (pattContext env g)) pts >>= return . concat
|
||||||
|
_ -> checkError ("record type expected for pattern instead of" <+> ppTerm Unqualified 0 typ')
|
||||||
|
PT t p' -> do
|
||||||
|
checkEqLType env g typ t (patt2term p')
|
||||||
|
pattContext env g typ p'
|
||||||
|
|
||||||
|
PAs x p -> do
|
||||||
|
g' <- pattContext env g typ p
|
||||||
|
return ((Explicit,x,typ):g')
|
||||||
|
|
||||||
|
PAlt p' q -> do
|
||||||
|
g1 <- pattContext env g typ p'
|
||||||
|
g2 <- pattContext env g typ q
|
||||||
|
let pts = nub ([x | pt@(_,x,_) <- g1, notElem pt g2] ++ [x | pt@(_,x,_) <- g2, notElem pt g1])
|
||||||
|
checkCond
|
||||||
|
("incompatible bindings of" <+>
|
||||||
|
fsep pts <+>
|
||||||
|
"in pattern alterantives" <+> ppPatt Unqualified 0 p) (null pts)
|
||||||
|
return g1 -- must be g1 == g2
|
||||||
|
PSeq p q -> do
|
||||||
|
g1 <- pattContext env g typ p
|
||||||
|
g2 <- pattContext env g typ q
|
||||||
|
return $ g1 ++ g2
|
||||||
|
PRep p' -> noBind typeStr p'
|
||||||
|
PNeg p' -> noBind typ p'
|
||||||
|
|
||||||
|
_ -> return [] ---- check types!
|
||||||
|
where
|
||||||
|
noBind typ p' = do
|
||||||
|
co <- pattContext env g typ p'
|
||||||
|
if not (null co)
|
||||||
|
then checkWarn ("no variable bound inside pattern" <+> ppPatt Unqualified 0 p)
|
||||||
|
>> return []
|
||||||
|
else return []
|
||||||
|
|
||||||
|
checkEqLType :: SourceGrammar -> Context -> Type -> Type -> Term -> Check Type
|
||||||
|
checkEqLType gr g t u trm = do
|
||||||
|
(b,t',u',s) <- checkIfEqLType gr g t u trm
|
||||||
|
case b of
|
||||||
|
True -> return t'
|
||||||
|
False ->
|
||||||
|
let inferredType = ppTerm Qualified 0 u
|
||||||
|
expectedType = ppTerm Qualified 0 t
|
||||||
|
term = ppTerm Unqualified 0 trm
|
||||||
|
funName = pp . head . words .render $ term
|
||||||
|
helpfulMsg =
|
||||||
|
case (arrows inferredType, arrows expectedType) of
|
||||||
|
(0,0) -> pp "" -- None of the types is a function
|
||||||
|
_ -> "\n **" <+>
|
||||||
|
if expectedType `isLessApplied` inferredType
|
||||||
|
then "Maybe you gave too few arguments to" <+> funName
|
||||||
|
else pp "Double-check that type signature and number of arguments match."
|
||||||
|
in checkError $ s <+> "type of" <+> term $$
|
||||||
|
"expected:" <+> expectedType $$ -- ppqType t u $$
|
||||||
|
"inferred:" <+> inferredType $$ -- ppqType u t
|
||||||
|
helpfulMsg
|
||||||
|
where
|
||||||
|
-- count the number of arrows in the prettyprinted term
|
||||||
|
arrows :: Doc -> Int
|
||||||
|
arrows = length . filter (=="->") . words . render
|
||||||
|
|
||||||
|
-- If prettyprinted type t has fewer arrows then prettyprinted type u,
|
||||||
|
-- then t is "less applied", and we can print out more helpful error msg.
|
||||||
|
isLessApplied :: Doc -> Doc -> Bool
|
||||||
|
isLessApplied t u = arrows t < arrows u
|
||||||
|
|
||||||
|
checkIfEqLType :: SourceGrammar -> Context -> Type -> Type -> Term -> Check (Bool,Type,Type,String)
|
||||||
|
checkIfEqLType gr g t u trm = do
|
||||||
|
t' <- computeLType gr g t
|
||||||
|
u' <- computeLType gr g u
|
||||||
|
case t' == u' || alpha [] t' u' of
|
||||||
|
True -> return (True,t',u',[])
|
||||||
|
-- forgive missing lock fields by only generating a warning.
|
||||||
|
--- better: use a flag to forgive? (AR 31/1/2006)
|
||||||
|
_ -> case missingLock [] t' u' of
|
||||||
|
Ok lo -> do
|
||||||
|
checkWarn $ "missing lock field" <+> fsep lo
|
||||||
|
return (True,t',u',[])
|
||||||
|
Bad s -> return (False,t',u',s)
|
||||||
|
|
||||||
|
where
|
||||||
|
|
||||||
|
-- check that u is a subtype of t
|
||||||
|
--- quick hack version of TC.eqVal
|
||||||
|
alpha g t u = case (t,u) of
|
||||||
|
|
||||||
|
-- error (the empty type!) is subtype of any other type
|
||||||
|
(_,u) | u == typeError -> True
|
||||||
|
|
||||||
|
-- contravariance
|
||||||
|
(Prod _ x a b, Prod _ y c d) -> alpha g c a && alpha ((x,y):g) b d
|
||||||
|
|
||||||
|
-- record subtyping
|
||||||
|
(RecType rs, RecType ts) -> all (\ (l,a) ->
|
||||||
|
any (\ (k,b) -> l == k && alpha g a b) ts) rs
|
||||||
|
(ExtR r s, ExtR r' s') -> alpha g r r' && alpha g s s'
|
||||||
|
(ExtR r s, t) -> alpha g r t || alpha g s t
|
||||||
|
|
||||||
|
-- the following say that Ints n is a subset of Int and of Ints m >= n
|
||||||
|
-- But why does it also allow Int as a subtype of Ints m? /TH 2014-04-04
|
||||||
|
(t,u) | Just m <- isTypeInts t, Just n <- isTypeInts u -> m >= n
|
||||||
|
| Just _ <- isTypeInts t, u == typeInt -> True ---- check size!
|
||||||
|
| t == typeInt, Just _ <- isTypeInts u -> True ---- why this ???? AR 11/12/2005
|
||||||
|
|
||||||
|
---- this should be made in Rename
|
||||||
|
(Q (m,a), Q (n,b)) | a == b -> elem m (allExtendsPlus gr n)
|
||||||
|
|| elem n (allExtendsPlus gr m)
|
||||||
|
|| m == n --- for Predef
|
||||||
|
(QC (m,a), QC (n,b)) | a == b -> elem m (allExtendsPlus gr n)
|
||||||
|
|| elem n (allExtendsPlus gr m)
|
||||||
|
(QC (m,a), Q (n,b)) | a == b -> elem m (allExtendsPlus gr n)
|
||||||
|
|| elem n (allExtendsPlus gr m)
|
||||||
|
(Q (m,a), QC (n,b)) | a == b -> elem m (allExtendsPlus gr n)
|
||||||
|
|| elem n (allExtendsPlus gr m)
|
||||||
|
|
||||||
|
-- contravariance
|
||||||
|
(Table a b, Table c d) -> alpha g c a && alpha g b d
|
||||||
|
(Vr x, Vr y) -> x == y || elem (x,y) g || elem (y,x) g
|
||||||
|
_ -> t == u
|
||||||
|
--- the following should be one-way coercions only. AR 4/1/2001
|
||||||
|
|| elem t sTypes && elem u sTypes
|
||||||
|
|| (t == typeType && u == typePType)
|
||||||
|
|| (u == typeType && t == typePType)
|
||||||
|
|
||||||
|
missingLock g t u = case (t,u) of
|
||||||
|
(RecType rs, RecType ts) ->
|
||||||
|
let
|
||||||
|
ls = [l | (l,a) <- rs,
|
||||||
|
not (any (\ (k,b) -> alpha g a b && l == k) ts)]
|
||||||
|
(locks,others) = partition isLockLabel ls
|
||||||
|
in case others of
|
||||||
|
_:_ -> Bad $ render ("missing record fields:" <+> fsep (punctuate ',' (others)))
|
||||||
|
_ -> return locks
|
||||||
|
-- contravariance
|
||||||
|
(Prod _ x a b, Prod _ y c d) -> do
|
||||||
|
ls1 <- missingLock g c a
|
||||||
|
ls2 <- missingLock g b d
|
||||||
|
return $ ls1 ++ ls2
|
||||||
|
|
||||||
|
_ -> Bad ""
|
||||||
|
|
||||||
|
sTypes = [typeStr, typeTok, typeString]
|
||||||
|
|
||||||
|
-- auxiliaries
|
||||||
|
|
||||||
|
-- | light-weight substitution for dep. types
|
||||||
|
substituteLType :: Context -> Type -> Check Type
|
||||||
|
substituteLType g t = case t of
|
||||||
|
Vr x -> return $ maybe t id $ lookup x [(x,t) | (_,x,t) <- g]
|
||||||
|
_ -> composOp (substituteLType g) t
|
||||||
|
|
||||||
|
termWith :: Term -> Check Type -> Check (Term, Type)
|
||||||
|
termWith t ct = do
|
||||||
|
ty <- ct
|
||||||
|
return (t,ty)
|
||||||
|
|
||||||
|
-- | compositional check\/infer of binary operations
|
||||||
|
check2 :: (Term -> Check Term) -> (Term -> Term -> Term) ->
|
||||||
|
Term -> Term -> Type -> Check (Term,Type)
|
||||||
|
check2 chk con a b t = do
|
||||||
|
a' <- chk a
|
||||||
|
b' <- chk b
|
||||||
|
return (con a' b', t)
|
||||||
|
|
||||||
|
-- printing a type with a lock field lock_C as C
|
||||||
|
ppType :: Type -> Doc
|
||||||
|
ppType ty =
|
||||||
|
case ty of
|
||||||
|
RecType fs -> case filter isLockLabel $ map fst fs of
|
||||||
|
[lock] -> pp (drop 5 (showIdent (label2ident lock)))
|
||||||
|
_ -> ppTerm Unqualified 0 ty
|
||||||
|
Prod _ x a b -> ppType a <+> "->" <+> ppType b
|
||||||
|
_ -> ppTerm Unqualified 0 ty
|
||||||
|
{-
|
||||||
|
ppqType :: Type -> Type -> Doc
|
||||||
|
ppqType t u = case (ppType t, ppType u) of
|
||||||
|
(pt,pu) | render pt == render pu -> ppTerm Qualified 0 t
|
||||||
|
(pt,_) -> pt
|
||||||
|
-}
|
||||||
|
checkLookup :: Ident -> Context -> Check Type
|
||||||
|
checkLookup x g =
|
||||||
|
case [ty | (b,y,ty) <- g, x == y] of
|
||||||
|
[] -> checkError ("unknown variable" <+> x)
|
||||||
|
(ty:_) -> return ty
|
||||||
@@ -5,22 +5,21 @@
|
|||||||
-- Stability : (stable)
|
-- Stability : (stable)
|
||||||
-- Portability : (portable)
|
-- Portability : (portable)
|
||||||
--
|
--
|
||||||
-- > CVS $Date: 2005/10/02 20:50:19 $
|
-- > CVS $Date: 2005/10/02 20:50:19 $
|
||||||
-- > CVS $Author: aarne $
|
-- > CVS $Author: aarne $
|
||||||
-- > CVS $Revision: 1.11 $
|
-- > CVS $Revision: 1.11 $
|
||||||
--
|
--
|
||||||
-- Thierry Coquand's type checking algorithm that creates a trace
|
-- Thierry Coquand's type checking algorithm that creates a trace
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
|
|
||||||
module GF.Compile.TypeCheck.TC (
|
module GF.Compile.TypeCheck.TC (AExp(..),
|
||||||
AExp(..),
|
Theory,
|
||||||
Theory,
|
checkExp,
|
||||||
checkExp,
|
inferExp,
|
||||||
inferExp,
|
checkBranch,
|
||||||
checkBranch,
|
eqVal,
|
||||||
eqVal,
|
whnf
|
||||||
whnf
|
) where
|
||||||
) where
|
|
||||||
|
|
||||||
import GF.Data.Operations
|
import GF.Data.Operations
|
||||||
import GF.Grammar
|
import GF.Grammar
|
||||||
@@ -32,17 +31,17 @@ import Data.Maybe
|
|||||||
import GF.Text.Pretty
|
import GF.Text.Pretty
|
||||||
|
|
||||||
data AExp =
|
data AExp =
|
||||||
AVr Ident Val
|
AVr Ident Val
|
||||||
| ACn QIdent Val
|
| ACn QIdent Val
|
||||||
| AType
|
| AType
|
||||||
| AInt Int
|
| AInt Int
|
||||||
| AFloat Double
|
| AFloat Double
|
||||||
| AStr String
|
| AStr String
|
||||||
| AMeta MetaId Val
|
| AMeta MetaId Val
|
||||||
| ALet (Ident,(Val,AExp)) AExp
|
| ALet (Ident,(Val,AExp)) AExp
|
||||||
| AApp AExp AExp Val
|
| AApp AExp AExp Val
|
||||||
| AAbs Ident Val AExp
|
| AAbs Ident Val AExp
|
||||||
| AProd Ident AExp AExp
|
| AProd Ident AExp AExp
|
||||||
-- -- | AEqs [([Exp],AExp)] --- not used
|
-- -- | AEqs [([Exp],AExp)] --- not used
|
||||||
| ARecType [ALabelling]
|
| ARecType [ALabelling]
|
||||||
| AR [AAssign]
|
| AR [AAssign]
|
||||||
@@ -51,7 +50,7 @@ data AExp =
|
|||||||
| AData Val
|
| AData Val
|
||||||
deriving (Eq,Show)
|
deriving (Eq,Show)
|
||||||
|
|
||||||
type ALabelling = (Label, AExp)
|
type ALabelling = (Label, AExp)
|
||||||
type AAssign = (Label, (Val, AExp))
|
type AAssign = (Label, (Val, AExp))
|
||||||
|
|
||||||
type Theory = QIdent -> Err Val
|
type Theory = QIdent -> Err Val
|
||||||
@@ -72,7 +71,7 @@ whnf :: Val -> Err Val
|
|||||||
whnf v = ---- errIn ("whnf" +++ prt v) $ ---- debug
|
whnf v = ---- errIn ("whnf" +++ prt v) $ ---- debug
|
||||||
case v of
|
case v of
|
||||||
VApp u w -> do
|
VApp u w -> do
|
||||||
u' <- whnf u
|
u' <- whnf u
|
||||||
w' <- whnf w
|
w' <- whnf w
|
||||||
app u' w'
|
app u' w'
|
||||||
VClos env e -> eval env e
|
VClos env e -> eval env e
|
||||||
@@ -82,9 +81,9 @@ app :: Val -> Val -> Err Val
|
|||||||
app u v = case u of
|
app u v = case u of
|
||||||
VClos env (Abs _ x e) -> eval ((x,v):env) e
|
VClos env (Abs _ x e) -> eval ((x,v):env) e
|
||||||
_ -> return $ VApp u v
|
_ -> return $ VApp u v
|
||||||
|
|
||||||
eval :: Env -> Term -> Err Val
|
eval :: Env -> Term -> Err Val
|
||||||
eval env e = ---- errIn ("eval" +++ prt e +++ "in" +++ prEnv env) $
|
eval env e = ---- errIn ("eval" +++ prt e +++ "in" +++ prEnv env) $
|
||||||
case e of
|
case e of
|
||||||
Vr x -> lookupVar env x
|
Vr x -> lookupVar env x
|
||||||
Q c -> return $ VCn c
|
Q c -> return $ VCn c
|
||||||
@@ -96,23 +95,23 @@ eval env e = ---- errIn ("eval" +++ prt e +++ "in" +++ prEnv env) $
|
|||||||
_ -> return $ VClos env e
|
_ -> return $ VClos env e
|
||||||
|
|
||||||
eqVal :: Int -> Val -> Val -> Err [(Val,Val)]
|
eqVal :: Int -> Val -> Val -> Err [(Val,Val)]
|
||||||
eqVal k u1 u2 = ---- errIn (prt u1 +++ "<>" +++ prBracket (show k) +++ prt u2) $
|
eqVal k u1 u2 = ---- errIn (prt u1 +++ "<>" +++ prBracket (show k) +++ prt u2) $
|
||||||
do
|
do
|
||||||
w1 <- whnf u1
|
w1 <- whnf u1
|
||||||
w2 <- whnf u2
|
w2 <- whnf u2
|
||||||
let v = VGen k
|
let v = VGen k
|
||||||
case (w1,w2) of
|
case (w1,w2) of
|
||||||
(VApp f1 a1, VApp f2 a2) -> liftM2 (++) (eqVal k f1 f2) (eqVal k a1 a2)
|
(VApp f1 a1, VApp f2 a2) -> liftM2 (++) (eqVal k f1 f2) (eqVal k a1 a2)
|
||||||
(VClos env1 (Abs _ x1 e1), VClos env2 (Abs _ x2 e2)) ->
|
(VClos env1 (Abs _ x1 e1), VClos env2 (Abs _ x2 e2)) ->
|
||||||
eqVal (k+1) (VClos ((x1,v x1):env1) e1) (VClos ((x2,v x1):env2) e2)
|
eqVal (k+1) (VClos ((x1,v x1):env1) e1) (VClos ((x2,v x1):env2) e2)
|
||||||
(VClos env1 (Prod _ x1 a1 e1), VClos env2 (Prod _ x2 a2 e2)) ->
|
(VClos env1 (Prod _ x1 a1 e1), VClos env2 (Prod _ x2 a2 e2)) ->
|
||||||
liftM2 (++)
|
liftM2 (++)
|
||||||
(eqVal k (VClos env1 a1) (VClos env2 a2))
|
(eqVal k (VClos env1 a1) (VClos env2 a2))
|
||||||
(eqVal (k+1) (VClos ((x1,v x1):env1) e1) (VClos ((x2,v x1):env2) e2))
|
(eqVal (k+1) (VClos ((x1,v x1):env1) e1) (VClos ((x2,v x1):env2) e2))
|
||||||
(VGen i _, VGen j _) -> return [(w1,w2) | i /= j]
|
(VGen i _, VGen j _) -> return [(w1,w2) | i /= j]
|
||||||
(VCn (_, i), VCn (_,j)) -> return [(w1,w2) | i /= j]
|
(VCn (_, i), VCn (_,j)) -> return [(w1,w2) | i /= j]
|
||||||
--- thus ignore qualifications; valid because inheritance cannot
|
--- thus ignore qualifications; valid because inheritance cannot
|
||||||
--- be qualified. Simplifies annotation. AR 17/3/2005
|
--- be qualified. Simplifies annotation. AR 17/3/2005
|
||||||
_ -> return [(w1,w2) | w1 /= w2]
|
_ -> return [(w1,w2) | w1 /= w2]
|
||||||
-- invariant: constraints are in whnf
|
-- invariant: constraints are in whnf
|
||||||
|
|
||||||
@@ -128,10 +127,10 @@ checkExp th tenv@(k,rho,gamma) e ty = do
|
|||||||
|
|
||||||
Abs _ x t -> case typ of
|
Abs _ x t -> case typ of
|
||||||
VClos env (Prod _ y a b) -> do
|
VClos env (Prod _ y a b) -> do
|
||||||
a' <- whnf $ VClos env a ---
|
a' <- whnf $ VClos env a ---
|
||||||
(t',cs) <- checkExp th
|
(t',cs) <- checkExp th
|
||||||
(k+1,(x,v x):rho, (x,a'):gamma) t (VClos ((y,v x):env) b)
|
(k+1,(x,v x):rho, (x,a'):gamma) t (VClos ((y,v x):env) b)
|
||||||
return (AAbs x a' t', cs)
|
return (AAbs x a' t', cs)
|
||||||
_ -> Bad (render ("function type expected for" <+> ppTerm Unqualified 0 e <+> "instead of" <+> ppValue Unqualified 0 typ))
|
_ -> Bad (render ("function type expected for" <+> ppTerm Unqualified 0 e <+> "instead of" <+> ppValue Unqualified 0 typ))
|
||||||
|
|
||||||
Let (x, (mb_typ, e1)) e2 -> do
|
Let (x, (mb_typ, e1)) e2 -> do
|
||||||
@@ -151,7 +150,7 @@ checkExp th tenv@(k,rho,gamma) e ty = do
|
|||||||
(b',csb) <- checkType th (k+1, (x,v x):rho, (x,VClos rho a):gamma) b
|
(b',csb) <- checkType th (k+1, (x,v x):rho, (x,VClos rho a):gamma) b
|
||||||
return (AProd x a' b', csa ++ csb)
|
return (AProd x a' b', csa ++ csb)
|
||||||
|
|
||||||
R xs ->
|
R xs ->
|
||||||
case typ of
|
case typ of
|
||||||
VRecType ys -> do case [l | (l,_) <- ys, isNothing (lookup l xs)] of
|
VRecType ys -> do case [l | (l,_) <- ys, isNothing (lookup l xs)] of
|
||||||
[] -> return ()
|
[] -> return ()
|
||||||
@@ -175,7 +174,7 @@ checkInferExp th tenv@(k,_,_) e typ = do
|
|||||||
(e',w,cs1) <- inferExp th tenv e
|
(e',w,cs1) <- inferExp th tenv e
|
||||||
cs2 <- eqVal k w typ
|
cs2 <- eqVal k w typ
|
||||||
return (e',cs1 ++ cs2)
|
return (e',cs1 ++ cs2)
|
||||||
|
|
||||||
inferExp :: Theory -> TCEnv -> Term -> Err (AExp, Val, [(Val,Val)])
|
inferExp :: Theory -> TCEnv -> Term -> Err (AExp, Val, [(Val,Val)])
|
||||||
inferExp th tenv@(k,rho,gamma) e = case e of
|
inferExp th tenv@(k,rho,gamma) e = case e of
|
||||||
Vr x -> mkAnnot (AVr x) $ noConstr $ lookupVar gamma x
|
Vr x -> mkAnnot (AVr x) $ noConstr $ lookupVar gamma x
|
||||||
@@ -201,13 +200,13 @@ inferExp th tenv@(k,rho,gamma) e = case e of
|
|||||||
(e2,val2,cs2) <- inferExp th (k,rho,(x,val1):gamma) e2
|
(e2,val2,cs2) <- inferExp th (k,rho,(x,val1):gamma) e2
|
||||||
return (ALet (x,(val1,e1)) e2, val2, cs1++cs2)
|
return (ALet (x,(val1,e1)) e2, val2, cs1++cs2)
|
||||||
App f t -> do
|
App f t -> do
|
||||||
(f',w,csf) <- inferExp th tenv f
|
(f',w,csf) <- inferExp th tenv f
|
||||||
typ <- whnf w
|
typ <- whnf w
|
||||||
case typ of
|
case typ of
|
||||||
VClos env (Prod _ x a b) -> do
|
VClos env (Prod _ x a b) -> do
|
||||||
(a',csa) <- checkExp th tenv t (VClos env a)
|
(a',csa) <- checkExp th tenv t (VClos env a)
|
||||||
b' <- whnf $ VClos ((x,VClos rho t):env) b
|
b' <- whnf $ VClos ((x,VClos rho t):env) b
|
||||||
return $ (AApp f' a' b', b', csf ++ csa)
|
return $ (AApp f' a' b', b', csf ++ csa)
|
||||||
_ -> Bad (render ("Prod expected for function" <+> ppTerm Unqualified 0 f <+> "instead of" <+> ppValue Unqualified 0 typ))
|
_ -> Bad (render ("Prod expected for function" <+> ppTerm Unqualified 0 f <+> "instead of" <+> ppValue Unqualified 0 typ))
|
||||||
_ -> Bad (render ("cannot infer type of expression" <+> ppTerm Unqualified 0 e))
|
_ -> Bad (render ("cannot infer type of expression" <+> ppTerm Unqualified 0 e))
|
||||||
|
|
||||||
@@ -233,9 +232,9 @@ checkAssign th tenv@(k,rho,gamma) typs (lbl,(Nothing,exp)) = do
|
|||||||
return ((lbl,(val,aexp)),cs)
|
return ((lbl,(val,aexp)),cs)
|
||||||
|
|
||||||
checkBranch :: Theory -> TCEnv -> Equation -> Val -> Err (([Term],AExp),[(Val,Val)])
|
checkBranch :: Theory -> TCEnv -> Equation -> Val -> Err (([Term],AExp),[(Val,Val)])
|
||||||
checkBranch th tenv b@(ps,t) ty = errIn ("branch" +++ show b) $
|
checkBranch th tenv b@(ps,t) ty = errIn ("branch" +++ show b) $
|
||||||
chB tenv' ps' ty
|
chB tenv' ps' ty
|
||||||
where
|
where
|
||||||
|
|
||||||
(ps',_,rho2,k') = ps2ts k ps
|
(ps',_,rho2,k') = ps2ts k ps
|
||||||
tenv' = (k, rho2++rho, gamma) ---- k' ?
|
tenv' = (k, rho2++rho, gamma) ---- k' ?
|
||||||
@@ -246,11 +245,11 @@ checkBranch th tenv b@(ps,t) ty = errIn ("branch" +++ show b) $
|
|||||||
typ <- whnf ty
|
typ <- whnf ty
|
||||||
case typ of
|
case typ of
|
||||||
VClos env (Prod _ y a b) -> do
|
VClos env (Prod _ y a b) -> do
|
||||||
a' <- whnf $ VClos env a
|
a' <- whnf $ VClos env a
|
||||||
(p', sigma, binds, cs1) <- checkP tenv p y a'
|
(p', sigma, binds, cs1) <- checkP tenv p y a'
|
||||||
let tenv' = (length binds, sigma ++ rho, binds ++ gamma)
|
let tenv' = (length binds, sigma ++ rho, binds ++ gamma)
|
||||||
((ps',exp),cs2) <- chB tenv' ps2 (VClos ((y,p'):env) b)
|
((ps',exp),cs2) <- chB tenv' ps2 (VClos ((y,p'):env) b)
|
||||||
return ((p:ps',exp), cs1 ++ cs2) -- don't change the patt
|
return ((p:ps',exp), cs1 ++ cs2) -- don't change the patt
|
||||||
_ -> Bad (render ("Product expected for definiens" <+> ppTerm Unqualified 0 t <+> "instead of" <+> ppValue Unqualified 0 typ))
|
_ -> Bad (render ("Product expected for definiens" <+> ppTerm Unqualified 0 t <+> "instead of" <+> ppValue Unqualified 0 typ))
|
||||||
[] -> do
|
[] -> do
|
||||||
(e,cs) <- checkExp th tenv t ty
|
(e,cs) <- checkExp th tenv t ty
|
||||||
@@ -260,15 +259,15 @@ checkBranch th tenv b@(ps,t) ty = errIn ("branch" +++ show b) $
|
|||||||
let sigma = [(x, VGen i x) | ((x,_),i) <- zip delta [k..]]
|
let sigma = [(x, VGen i x) | ((x,_),i) <- zip delta [k..]]
|
||||||
return (VClos sigma t, sigma, delta, cs)
|
return (VClos sigma t, sigma, delta, cs)
|
||||||
|
|
||||||
ps2ts k = foldr p2t ([],0,[],k)
|
ps2ts k = foldr p2t ([],0,[],k)
|
||||||
p2t p (ps,i,g,k) = case p of
|
p2t p (ps,i,g,k) = case p of
|
||||||
PW -> (Meta i : ps, i+1,g,k)
|
PW -> (Meta i : ps, i+1,g,k)
|
||||||
PV x -> (Vr x : ps, i, upd x k g,k+1)
|
PV x -> (Vr x : ps, i, upd x k g,k+1)
|
||||||
PAs x p -> p2t p (ps,i,g,k)
|
PAs x p -> p2t p (ps,i,g,k)
|
||||||
PString s -> (K s : ps, i, g, k)
|
PString s -> (K s : ps, i, g, k)
|
||||||
PInt n -> (EInt n : ps, i, g, k)
|
PInt n -> (EInt n : ps, i, g, k)
|
||||||
PFloat n -> (EFloat n : ps, i, g, k)
|
PFloat n -> (EFloat n : ps, i, g, k)
|
||||||
PP c xs -> (mkApp (Q c) xss : ps, j, g',k')
|
PP c xs -> (mkApp (Q c) xss : ps, j, g',k')
|
||||||
where (xss,j,g',k') = foldr p2t ([],i,g,k) xs
|
where (xss,j,g',k') = foldr p2t ([],i,g,k) xs
|
||||||
PImplArg p -> p2t p (ps,i,g,k)
|
PImplArg p -> p2t p (ps,i,g,k)
|
||||||
PTilde t -> (t : ps, i, g, k)
|
PTilde t -> (t : ps, i, g, k)
|
||||||
@@ -308,8 +307,8 @@ checkPatt th tenv exp val = do
|
|||||||
case typ of
|
case typ of
|
||||||
VClos env (Prod _ x a b) -> do
|
VClos env (Prod _ x a b) -> do
|
||||||
(a',_,csa) <- checkExpP tenv t (VClos env a)
|
(a',_,csa) <- checkExpP tenv t (VClos env a)
|
||||||
b' <- whnf $ VClos ((x,VClos rho t):env) b
|
b' <- whnf $ VClos ((x,VClos rho t):env) b
|
||||||
return $ (AApp f' a' b', b', csf ++ csa)
|
return $ (AApp f' a' b', b', csf ++ csa)
|
||||||
_ -> Bad (render ("Prod expected for function" <+> ppTerm Unqualified 0 f <+> "instead of" <+> ppValue Unqualified 0 typ))
|
_ -> Bad (render ("Prod expected for function" <+> ppTerm Unqualified 0 f <+> "instead of" <+> ppValue Unqualified 0 typ))
|
||||||
_ -> Bad (render ("cannot typecheck pattern" <+> ppTerm Unqualified 0 exp))
|
_ -> Bad (render ("cannot typecheck pattern" <+> ppTerm Unqualified 0 exp))
|
||||||
|
|
||||||
@@ -322,3 +321,4 @@ mkAnnot :: (Val -> AExp) -> Err (Val,[(Val,Val)]) -> Err (AExp,Val,[(Val,Val)])
|
|||||||
mkAnnot a ti = do
|
mkAnnot a ti = do
|
||||||
(v,cs) <- ti
|
(v,cs) <- ti
|
||||||
return (a v, v, cs)
|
return (a v, v, cs)
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
-- Stability : (stable)
|
-- Stability : (stable)
|
||||||
-- Portability : (portable)
|
-- Portability : (portable)
|
||||||
--
|
--
|
||||||
-- > CVS $Date: 2005/05/30 18:39:44 $
|
-- > CVS $Date: 2005/05/30 18:39:44 $
|
||||||
-- > CVS $Author: aarne $
|
-- > CVS $Author: aarne $
|
||||||
-- > CVS $Revision: 1.8 $
|
-- > CVS $Revision: 1.8 $
|
||||||
--
|
--
|
||||||
@@ -34,14 +34,14 @@ buildAnyTree :: Fail.MonadFail m => ModuleName -> [(Ident,Info)] -> m (Map.Map I
|
|||||||
buildAnyTree m = go Map.empty
|
buildAnyTree m = go Map.empty
|
||||||
where
|
where
|
||||||
go map [] = return map
|
go map [] = return map
|
||||||
go map ((c,j):is) =
|
go map ((c,j):is) = do
|
||||||
case Map.lookup c map of
|
case Map.lookup c map of
|
||||||
Just i -> case unifyAnyInfo m i j of
|
Just i -> case unifyAnyInfo m i j of
|
||||||
Ok k -> go (Map.insert c k map) is
|
Ok k -> go (Map.insert c k map) is
|
||||||
Bad _ -> fail $ render ("conflicting information in module"<+>m $$
|
Bad _ -> fail $ render ("conflicting information in module"<+>m $$
|
||||||
nest 4 (ppJudgement Qualified (c,i)) $$
|
nest 4 (ppJudgement Qualified (c,i)) $$
|
||||||
"and" $+$
|
"and" $+$
|
||||||
nest 4 (ppJudgement Qualified (c,j)))
|
nest 4 (ppJudgement Qualified (c,j)))
|
||||||
Nothing -> go (Map.insert c j map) is
|
Nothing -> go (Map.insert c j map) is
|
||||||
|
|
||||||
extendModule :: FilePath -> SourceGrammar -> SourceModule -> Check SourceModule
|
extendModule :: FilePath -> SourceGrammar -> SourceModule -> Check SourceModule
|
||||||
@@ -51,14 +51,14 @@ extendModule cwd gr (name,m)
|
|||||||
---- Should be replaced by real control. AR 4/2/2005
|
---- Should be replaced by real control. AR 4/2/2005
|
||||||
| mstatus m == MSIncomplete && isModCnc m = return (name,m)
|
| mstatus m == MSIncomplete && isModCnc m = return (name,m)
|
||||||
| otherwise = checkInModule cwd m NoLoc empty $ do
|
| otherwise = checkInModule cwd m NoLoc empty $ do
|
||||||
m' <- foldM extOne m (mextend m)
|
m' <- foldM extOne m (mextend m)
|
||||||
return (name,m')
|
return (name,m')
|
||||||
where
|
where
|
||||||
extOne mo (n,cond) = do
|
extOne mo (n,cond) = do
|
||||||
m0 <- lookupModule gr n
|
m0 <- lookupModule gr n
|
||||||
|
|
||||||
-- test that the module types match, and find out if the old is complete
|
-- test that the module types match, and find out if the old is complete
|
||||||
unless (sameMType (mtype m) (mtype mo))
|
unless (sameMType (mtype m) (mtype mo))
|
||||||
(checkError ("illegal extension type to module" <+> name))
|
(checkError ("illegal extension type to module" <+> name))
|
||||||
|
|
||||||
let isCompl = isCompleteModule m0
|
let isCompl = isCompleteModule m0
|
||||||
@@ -67,7 +67,7 @@ extendModule cwd gr (name,m)
|
|||||||
js1 <- extendMod gr isCompl ((n,m0), isInherited cond) name (jments mo)
|
js1 <- extendMod gr isCompl ((n,m0), isInherited cond) name (jments mo)
|
||||||
|
|
||||||
-- if incomplete, throw away extension information
|
-- if incomplete, throw away extension information
|
||||||
return $
|
return $
|
||||||
if isCompl
|
if isCompl
|
||||||
then mo {jments = js1}
|
then mo {jments = js1}
|
||||||
else mo {mextend= filter ((/=n) . fst) (mextend mo)
|
else mo {mextend= filter ((/=n) . fst) (mextend mo)
|
||||||
@@ -75,7 +75,7 @@ extendModule cwd gr (name,m)
|
|||||||
,jments = js1
|
,jments = js1
|
||||||
}
|
}
|
||||||
|
|
||||||
-- | rebuilding instance + interface, and "with" modules, prior to renaming.
|
-- | rebuilding instance + interface, and "with" modules, prior to renaming.
|
||||||
-- AR 24/10/2003
|
-- AR 24/10/2003
|
||||||
rebuildModule :: FilePath -> SourceGrammar -> SourceModule -> Check SourceModule
|
rebuildModule :: FilePath -> SourceGrammar -> SourceModule -> Check SourceModule
|
||||||
rebuildModule cwd gr mo@(i,mi@(ModInfo mt stat fs_ me mw ops_ med_ msrc_ env_ js_)) =
|
rebuildModule cwd gr mo@(i,mi@(ModInfo mt stat fs_ me mw ops_ med_ msrc_ env_ js_)) =
|
||||||
@@ -88,8 +88,8 @@ rebuildModule cwd gr mo@(i,mi@(ModInfo mt stat fs_ me mw ops_ med_ msrc_ env_ js
|
|||||||
|
|
||||||
-- add the information given in interface into an instance module
|
-- add the information given in interface into an instance module
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
unless (null is || mstatus mi == MSIncomplete)
|
unless (null is || mstatus mi == MSIncomplete)
|
||||||
(checkError ("module" <+> i <+>
|
(checkError ("module" <+> i <+>
|
||||||
"has open interfaces and must therefore be declared incomplete"))
|
"has open interfaces and must therefore be declared incomplete"))
|
||||||
case mt of
|
case mt of
|
||||||
MTInstance (i0,mincl) -> do
|
MTInstance (i0,mincl) -> do
|
||||||
@@ -113,7 +113,7 @@ rebuildModule cwd gr mo@(i,mi@(ModInfo mt stat fs_ me mw ops_ med_ msrc_ env_ js
|
|||||||
let stat' = if all (flip elem infs) is
|
let stat' = if all (flip elem infs) is
|
||||||
then MSComplete
|
then MSComplete
|
||||||
else MSIncomplete
|
else MSIncomplete
|
||||||
unless (stat' == MSComplete || stat == MSIncomplete)
|
unless (stat' == MSComplete || stat == MSIncomplete)
|
||||||
(checkError ("module" <+> i <+> "remains incomplete"))
|
(checkError ("module" <+> i <+> "remains incomplete"))
|
||||||
ModInfo mt0 _ fs me' _ ops0 _ fpath _ js <- lookupModule gr ext
|
ModInfo mt0 _ fs me' _ ops0 _ fpath _ js <- lookupModule gr ext
|
||||||
let ops1 = nub $
|
let ops1 = nub $
|
||||||
@@ -141,24 +141,24 @@ rebuildModule cwd gr mo@(i,mi@(ModInfo mt stat fs_ me mw ops_ med_ msrc_ env_ js
|
|||||||
extendMod :: Grammar ->
|
extendMod :: Grammar ->
|
||||||
Bool -> (Module,Ident -> Bool) -> ModuleName ->
|
Bool -> (Module,Ident -> Bool) -> ModuleName ->
|
||||||
Map.Map Ident Info -> Check (Map.Map Ident Info)
|
Map.Map Ident Info -> Check (Map.Map Ident Info)
|
||||||
extendMod gr isCompl ((name,mi),cond) base new = foldM try new $ Map.toList (jments mi)
|
extendMod gr isCompl ((name,mi),cond) base new = foldM try new $ Map.toList (jments mi)
|
||||||
where
|
where
|
||||||
try new (c,i0)
|
try new (c,i0)
|
||||||
| not (cond c) = return new
|
| not (cond c) = return new
|
||||||
| otherwise = case Map.lookup c new of
|
| otherwise = case Map.lookup c new of
|
||||||
Just j -> case unifyAnyInfo name i j of
|
Just j -> case unifyAnyInfo name i j of
|
||||||
Ok k -> return $ Map.insert c k new
|
Ok k -> return $ Map.insert c k new
|
||||||
Bad _ -> do (base,j) <- case j of
|
Bad _ -> do (base,j) <- case j of
|
||||||
AnyInd _ m -> lookupOrigInfo gr (m,c)
|
AnyInd _ m -> lookupOrigInfo gr (m,c)
|
||||||
_ -> return (base,j)
|
_ -> return (base,j)
|
||||||
(name,i) <- case i of
|
(name,i) <- case i of
|
||||||
AnyInd _ m -> lookupOrigInfo gr (m,c)
|
AnyInd _ m -> lookupOrigInfo gr (m,c)
|
||||||
_ -> return (name,i)
|
_ -> return (name,i)
|
||||||
checkError ("cannot unify the information" $$
|
checkError ("cannot unify the information" $$
|
||||||
nest 4 (ppJudgement Qualified (c,i)) $$
|
nest 4 (ppJudgement Qualified (c,i)) $$
|
||||||
"in module" <+> name <+> "with" $$
|
"in module" <+> name <+> "with" $$
|
||||||
nest 4 (ppJudgement Qualified (c,j)) $$
|
nest 4 (ppJudgement Qualified (c,j)) $$
|
||||||
"in module" <+> base)
|
"in module" <+> base)
|
||||||
Nothing-> if isCompl
|
Nothing-> if isCompl
|
||||||
then return $ Map.insert c (indirInfo name i) new
|
then return $ Map.insert c (indirInfo name i) new
|
||||||
else return $ Map.insert c i new
|
else return $ Map.insert c i new
|
||||||
@@ -166,11 +166,11 @@ extendMod gr isCompl ((name,mi),cond) base new = foldM try new $ Map.toList (jme
|
|||||||
i = globalizeLoc (msrc mi) i0
|
i = globalizeLoc (msrc mi) i0
|
||||||
|
|
||||||
indirInfo :: ModuleName -> Info -> Info
|
indirInfo :: ModuleName -> Info -> Info
|
||||||
indirInfo n info = AnyInd b n' where
|
indirInfo n info = AnyInd b n' where
|
||||||
(b,n') = case info of
|
(b,n') = case info of
|
||||||
ResValue _ -> (True,n)
|
ResValue _ -> (True,n)
|
||||||
ResParam _ _ -> (True,n)
|
ResParam _ _ -> (True,n)
|
||||||
AbsFun _ _ Nothing _ -> (True,n)
|
AbsFun _ _ Nothing _ -> (True,n)
|
||||||
AnyInd b k -> (b,k)
|
AnyInd b k -> (b,k)
|
||||||
_ -> (False,n) ---- canonical in Abs
|
_ -> (False,n) ---- canonical in Abs
|
||||||
|
|
||||||
@@ -194,24 +194,24 @@ globalizeLoc fpath i =
|
|||||||
|
|
||||||
unifyAnyInfo :: ModuleName -> Info -> Info -> Err Info
|
unifyAnyInfo :: ModuleName -> Info -> Info -> Err Info
|
||||||
unifyAnyInfo m i j = case (i,j) of
|
unifyAnyInfo m i j = case (i,j) of
|
||||||
(AbsCat mc1, AbsCat mc2) ->
|
(AbsCat mc1, AbsCat mc2) ->
|
||||||
liftM AbsCat (unifyMaybeL mc1 mc2)
|
liftM AbsCat (unifyMaybeL mc1 mc2)
|
||||||
(AbsFun mt1 ma1 md1 moper1, AbsFun mt2 ma2 md2 moper2) ->
|
(AbsFun mt1 ma1 md1 moper1, AbsFun mt2 ma2 md2 moper2) ->
|
||||||
liftM4 AbsFun (unifyMaybeL mt1 mt2) (unifAbsArrity ma1 ma2) (unifAbsDefs md1 md2) (unifyMaybe moper1 moper2) -- adding defs
|
liftM4 AbsFun (unifyMaybeL mt1 mt2) (unifAbsArrity ma1 ma2) (unifAbsDefs md1 md2) (unifyMaybe moper1 moper2) -- adding defs
|
||||||
|
|
||||||
(ResParam mt1 mv1, ResParam mt2 mv2) ->
|
(ResParam mt1 mv1, ResParam mt2 mv2) ->
|
||||||
liftM2 ResParam (unifyMaybeL mt1 mt2) (unifyMaybe mv1 mv2)
|
liftM2 ResParam (unifyMaybeL mt1 mt2) (unifyMaybe mv1 mv2)
|
||||||
(ResValue (L l1 t1), ResValue (L l2 t2))
|
(ResValue (L l1 t1), ResValue (L l2 t2))
|
||||||
| t1==t2 -> return (ResValue (L l1 t1))
|
| t1==t2 -> return (ResValue (L l1 t1))
|
||||||
| otherwise -> fail ""
|
| otherwise -> fail ""
|
||||||
(_, ResOverload ms t) | elem m ms ->
|
(_, ResOverload ms t) | elem m ms ->
|
||||||
return $ ResOverload ms t
|
return $ ResOverload ms t
|
||||||
(ResOper mt1 m1, ResOper mt2 m2) ->
|
(ResOper mt1 m1, ResOper mt2 m2) ->
|
||||||
liftM2 ResOper (unifyMaybeL mt1 mt2) (unifyMaybeL m1 m2)
|
liftM2 ResOper (unifyMaybeL mt1 mt2) (unifyMaybeL m1 m2)
|
||||||
|
|
||||||
(CncCat mc1 md1 mr1 mp1 mpmcfg1, CncCat mc2 md2 mr2 mp2 mpmcfg2) ->
|
(CncCat mc1 md1 mr1 mp1 mpmcfg1, CncCat mc2 md2 mr2 mp2 mpmcfg2) ->
|
||||||
liftM5 CncCat (unifyMaybeL mc1 mc2) (unifyMaybeL md1 md2) (unifyMaybeL mr1 mr2) (unifyMaybeL mp1 mp2) (unifyMaybe mpmcfg1 mpmcfg2)
|
liftM5 CncCat (unifyMaybeL mc1 mc2) (unifyMaybeL md1 md2) (unifyMaybeL mr1 mr2) (unifyMaybeL mp1 mp2) (unifyMaybe mpmcfg1 mpmcfg2)
|
||||||
(CncFun m mt1 md1 mpmcfg1, CncFun _ mt2 md2 mpmcfg2) ->
|
(CncFun m mt1 md1 mpmcfg1, CncFun _ mt2 md2 mpmcfg2) ->
|
||||||
liftM3 (CncFun m) (unifyMaybeL mt1 mt2) (unifyMaybeL md1 md2) (unifyMaybe mpmcfg1 mpmcfg2)
|
liftM3 (CncFun m) (unifyMaybeL mt1 mt2) (unifyMaybeL md1 md2) (unifyMaybe mpmcfg1 mpmcfg2)
|
||||||
|
|
||||||
(AnyInd b1 m1, AnyInd b2 m2) -> do
|
(AnyInd b1 m1, AnyInd b2 m2) -> do
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
-- | Parallel grammar compilation
|
-- | Parallel grammar compilation
|
||||||
module GF.CompileInParallel(parallelBatchCompile) where
|
module GF.CompileInParallel(parallelBatchCompile) where
|
||||||
import Prelude hiding (catch,(<>))
|
import Prelude hiding (catch,(<>)) -- GHC 8.4.1 clash with Text.PrettyPrint
|
||||||
import Control.Monad(join,ap,when,unless)
|
import Control.Monad(join,ap,when,unless)
|
||||||
import Control.Applicative
|
import Control.Applicative
|
||||||
import GF.Infra.Concurrency
|
import GF.Infra.Concurrency
|
||||||
@@ -36,8 +36,11 @@ import qualified Control.Monad.Fail as Fail
|
|||||||
parallelBatchCompile jobs opts rootfiles0 =
|
parallelBatchCompile jobs opts rootfiles0 =
|
||||||
do setJobs jobs
|
do setJobs jobs
|
||||||
rootfiles <- mapM canonical rootfiles0
|
rootfiles <- mapM canonical rootfiles0
|
||||||
lib_dir <- canonical =<< getLibraryDirectory opts
|
lib_dirs1 <- getLibraryDirectory opts
|
||||||
filepaths <- mapM (getPathFromFile lib_dir opts) rootfiles
|
lib_dirs2 <- mapM canonical lib_dirs1
|
||||||
|
let lib_dir = head lib_dirs2
|
||||||
|
when (length lib_dirs2 >1) $ ePutStrLn ("GF_LIB_PATH defines more than one directory; using the first, " ++ show lib_dir)
|
||||||
|
filepaths <- mapM (getPathFromFile [lib_dir] opts) rootfiles
|
||||||
let groups = groupFiles lib_dir filepaths
|
let groups = groupFiles lib_dir filepaths
|
||||||
n = length groups
|
n = length groups
|
||||||
when (n>1) $ ePutStrLn "Grammar mixes present and alltenses, dividing modules into two groups"
|
when (n>1) $ ePutStrLn "Grammar mixes present and alltenses, dividing modules into two groups"
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
module GF.Compiler (mainGFC, linkGrammars, writeGrammar, writeOutputs) where
|
module GF.Compiler (mainGFC, linkGrammars, writePGF, writeLPGF, writeOutputs) where
|
||||||
|
|
||||||
import PGF2
|
import PGF
|
||||||
import PGF2.Internal(unionPGF,writePGF,writeConcr)
|
import PGF.Internal(concretes,optimizePGF,unionPGF)
|
||||||
import GF.Compile as S(batchCompile,link,srcAbsName)
|
import PGF.Internal(putSplitAbs,encodeFile,runPut)
|
||||||
|
import LPGF(LPGF)
|
||||||
|
import qualified LPGF
|
||||||
|
import GF.Compile as S(batchCompile,link,linkl,srcAbsName)
|
||||||
import GF.CompileInParallel as P(parallelBatchCompile)
|
import GF.CompileInParallel as P(parallelBatchCompile)
|
||||||
import GF.Compile.Export
|
import GF.Compile.Export
|
||||||
import GF.Compile.ConcreteToHaskell(concretes2haskell)
|
import GF.Compile.ConcreteToHaskell(concretes2haskell)
|
||||||
@@ -10,7 +13,8 @@ import GF.Compile.GrammarToCanonical--(concretes2canonical)
|
|||||||
import GF.Compile.CFGtoPGF
|
import GF.Compile.CFGtoPGF
|
||||||
import GF.Compile.GetGrammar
|
import GF.Compile.GetGrammar
|
||||||
import GF.Grammar.BNFC
|
import GF.Grammar.BNFC
|
||||||
import GF.Grammar.CFG
|
import GF.Grammar.CFG hiding (Grammar)
|
||||||
|
import GF.Grammar.Grammar (Grammar, ModuleName)
|
||||||
|
|
||||||
--import GF.Infra.Ident(showIdent)
|
--import GF.Infra.Ident(showIdent)
|
||||||
import GF.Infra.UseIO
|
import GF.Infra.UseIO
|
||||||
@@ -22,10 +26,11 @@ import GF.Text.Pretty(render,render80)
|
|||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
import qualified Data.Set as Set
|
import qualified Data.Set as Set
|
||||||
|
import Data.Time(UTCTime)
|
||||||
import qualified Data.ByteString.Lazy as BSL
|
import qualified Data.ByteString.Lazy as BSL
|
||||||
import GF.Grammar.CanonicalJSON (encodeJSON)
|
import GF.Grammar.CanonicalJSON (encodeJSON)
|
||||||
import System.FilePath
|
import System.FilePath
|
||||||
import Control.Monad(when,unless,forM_)
|
import Control.Monad(when,unless,forM,void)
|
||||||
|
|
||||||
-- | Compile the given GF grammar files. The result is a number of @.gfo@ files
|
-- | Compile the given GF grammar files. The result is a number of @.gfo@ files
|
||||||
-- and, depending on the options, a @.pgf@ file. (@gf -batch@, @gf -make@)
|
-- and, depending on the options, a @.pgf@ file. (@gf -batch@, @gf -make@)
|
||||||
@@ -46,7 +51,7 @@ mainGFC opts fs = do
|
|||||||
extensionIs ext = (== ext) . takeExtension
|
extensionIs ext = (== ext) . takeExtension
|
||||||
|
|
||||||
compileSourceFiles :: Options -> [FilePath] -> IOE ()
|
compileSourceFiles :: Options -> [FilePath] -> IOE ()
|
||||||
compileSourceFiles opts fs =
|
compileSourceFiles opts fs =
|
||||||
do output <- batchCompile opts fs
|
do output <- batchCompile opts fs
|
||||||
exportCanonical output
|
exportCanonical output
|
||||||
unless (flag optStopAfterPhase opts == Compile) $
|
unless (flag optStopAfterPhase opts == Compile) $
|
||||||
@@ -91,7 +96,11 @@ compileSourceFiles opts fs =
|
|||||||
-- in the 'Options') from the output of 'parallelBatchCompile'.
|
-- in the 'Options') from the output of 'parallelBatchCompile'.
|
||||||
-- If a @.pgf@ file by the same name already exists and it is newer than the
|
-- If a @.pgf@ file by the same name already exists and it is newer than the
|
||||||
-- source grammar files (as indicated by the 'UTCTime' argument), it is not
|
-- source grammar files (as indicated by the 'UTCTime' argument), it is not
|
||||||
-- recreated. Calls 'writeGrammar' and 'writeOutputs'.
|
-- recreated. Calls 'writePGF' and 'writeOutputs'.
|
||||||
|
linkGrammars :: Options -> (UTCTime,[(ModuleName, Grammar)]) -> IOE ()
|
||||||
|
linkGrammars opts (_,cnc_grs) | FmtLPGF `elem` flag optOutputFormats opts = do
|
||||||
|
lpgf <- linkl opts (head cnc_grs)
|
||||||
|
void $ writeLPGF opts lpgf
|
||||||
linkGrammars opts (t_src,~cnc_grs@(~(cnc,gr):_)) =
|
linkGrammars opts (t_src,~cnc_grs@(~(cnc,gr):_)) =
|
||||||
do let abs = render (srcAbsName gr cnc)
|
do let abs = render (srcAbsName gr cnc)
|
||||||
pgfFile = outputPath opts (grammarName' opts abs<.>"pgf")
|
pgfFile = outputPath opts (grammarName' opts abs<.>"pgf")
|
||||||
@@ -101,8 +110,10 @@ linkGrammars opts (t_src,~cnc_grs@(~(cnc,gr):_)) =
|
|||||||
if t_pgf >= Just t_src
|
if t_pgf >= Just t_src
|
||||||
then putIfVerb opts $ pgfFile ++ " is up-to-date."
|
then putIfVerb opts $ pgfFile ++ " is up-to-date."
|
||||||
else do pgfs <- mapM (link opts) cnc_grs
|
else do pgfs <- mapM (link opts) cnc_grs
|
||||||
let pgf = foldl1 (\one two -> fromMaybe two (unionPGF one two)) pgfs
|
let pgf0 = foldl1 unionPGF pgfs
|
||||||
writeGrammar opts pgf
|
probs <- maybe (return . defaultProbabilities) readProbabilitiesFromFile (flag optProbsFile opts) pgf0
|
||||||
|
let pgf = setProbabilities probs pgf0
|
||||||
|
writePGF opts pgf
|
||||||
writeOutputs opts pgf
|
writeOutputs opts pgf
|
||||||
|
|
||||||
compileCFFiles :: Options -> [FilePath] -> IOE ()
|
compileCFFiles :: Options -> [FilePath] -> IOE ()
|
||||||
@@ -112,11 +123,12 @@ compileCFFiles opts fs = do
|
|||||||
startCat <- case rules of
|
startCat <- case rules of
|
||||||
(Rule cat _ _ : _) -> return cat
|
(Rule cat _ _ : _) -> return cat
|
||||||
_ -> fail "empty CFG"
|
_ -> fail "empty CFG"
|
||||||
probs <- liftIO (maybe (return Map.empty) readProbabilitiesFromFile (flag optProbsFile opts))
|
let pgf = cf2pgf (last fs) (mkCFG startCat Set.empty rules)
|
||||||
let pgf = cf2pgf opts (last fs) (mkCFG startCat Set.empty rules) probs
|
|
||||||
unless (flag optStopAfterPhase opts == Compile) $
|
unless (flag optStopAfterPhase opts == Compile) $
|
||||||
do writeGrammar opts pgf
|
do probs <- liftIO (maybe (return . defaultProbabilities) readProbabilitiesFromFile (flag optProbsFile opts) pgf)
|
||||||
writeOutputs opts pgf
|
let pgf' = setProbabilities probs $ if flag optOptimizePGF opts then optimizePGF pgf else pgf
|
||||||
|
writePGF opts pgf'
|
||||||
|
writeOutputs opts pgf'
|
||||||
|
|
||||||
unionPGFFiles :: Options -> [FilePath] -> IOE ()
|
unionPGFFiles :: Options -> [FilePath] -> IOE ()
|
||||||
unionPGFFiles opts fs =
|
unionPGFFiles opts fs =
|
||||||
@@ -134,11 +146,14 @@ unionPGFFiles opts fs =
|
|||||||
|
|
||||||
doIt =
|
doIt =
|
||||||
do pgfs <- mapM readPGFVerbose fs
|
do pgfs <- mapM readPGFVerbose fs
|
||||||
let pgf = foldl1 (\one two -> fromMaybe two (unionPGF one two)) pgfs
|
let pgf0 = foldl1 unionPGF pgfs
|
||||||
let pgfFile = outputPath opts (grammarName opts pgf <.> "pgf")
|
pgf1 = if flag optOptimizePGF opts then optimizePGF pgf0 else pgf0
|
||||||
|
probs <- liftIO (maybe (return . defaultProbabilities) readProbabilitiesFromFile (flag optProbsFile opts) pgf1)
|
||||||
|
let pgf = setProbabilities probs pgf1
|
||||||
|
pgfFile = outputPath opts (grammarName opts pgf <.> "pgf")
|
||||||
if pgfFile `elem` fs
|
if pgfFile `elem` fs
|
||||||
then putStrLnE $ "Refusing to overwrite " ++ pgfFile
|
then putStrLnE $ "Refusing to overwrite " ++ pgfFile
|
||||||
else writeGrammar opts pgf
|
else void $ writePGF opts pgf
|
||||||
writeOutputs opts pgf
|
writeOutputs opts pgf
|
||||||
|
|
||||||
readPGFVerbose f =
|
readPGFVerbose f =
|
||||||
@@ -148,37 +163,51 @@ unionPGFFiles opts fs =
|
|||||||
-- Calls 'exportPGF'.
|
-- Calls 'exportPGF'.
|
||||||
writeOutputs :: Options -> PGF -> IOE ()
|
writeOutputs :: Options -> PGF -> IOE ()
|
||||||
writeOutputs opts pgf = do
|
writeOutputs opts pgf = do
|
||||||
sequence_ [writeOutput opts name str
|
sequence_ [writeOutput opts name str
|
||||||
| fmt <- flag optOutputFormats opts,
|
| fmt <- flag optOutputFormats opts,
|
||||||
(name,str) <- exportPGF opts fmt pgf]
|
(name,str) <- exportPGF opts fmt pgf]
|
||||||
|
|
||||||
-- | Write the result of compiling a grammar (e.g. with 'compileToPGF' or
|
-- | Write the result of compiling a grammar (e.g. with 'compileToPGF' or
|
||||||
-- 'link') to a @.pgf@ file.
|
-- 'link') to a @.pgf@ file.
|
||||||
-- A split PGF file is output if the @-split-pgf@ option is used.
|
-- A split PGF file is output if the @-split-pgf@ option is used.
|
||||||
writeGrammar :: Options -> PGF -> IOE ()
|
writePGF :: Options -> PGF -> IOE [FilePath]
|
||||||
writeGrammar opts pgf =
|
writePGF opts pgf =
|
||||||
if flag optSplitPGF opts then writeSplitPGF else writeNormalPGF
|
if flag optSplitPGF opts then writeSplitPGF else writeNormalPGF
|
||||||
where
|
where
|
||||||
writeNormalPGF =
|
writeNormalPGF =
|
||||||
do let outfile = outputPath opts (grammarName opts pgf <.> "pgf")
|
do let outfile = outputPath opts (grammarName opts pgf <.> "pgf")
|
||||||
writing opts outfile (writePGF outfile pgf)
|
writing opts outfile $ encodeFile outfile pgf
|
||||||
|
return [outfile]
|
||||||
|
|
||||||
writeSplitPGF =
|
writeSplitPGF =
|
||||||
do let outfile = outputPath opts (grammarName opts pgf <.> "pgf")
|
do let outfile = outputPath opts (grammarName opts pgf <.> "pgf")
|
||||||
writing opts outfile $ writePGF outfile pgf
|
writing opts outfile $ BSL.writeFile outfile (runPut (putSplitAbs pgf))
|
||||||
forM_ (Map.toList (languages pgf)) $ \(concrname,concr) -> do
|
--encodeFile_ outfile (putSplitAbs pgf)
|
||||||
let outfile = outputPath opts (concrname <.> "pgf_c")
|
outfiles <- forM (Map.toList (concretes pgf)) $ \cnc -> do
|
||||||
writing opts outfile (writeConcr outfile concr)
|
let outfile = outputPath opts (showCId (fst cnc) <.> "pgf_c")
|
||||||
|
writing opts outfile $ encodeFile outfile cnc
|
||||||
|
return outfile
|
||||||
|
|
||||||
|
return (outfile:outfiles)
|
||||||
|
|
||||||
writeOutput :: Options -> FilePath-> String -> IOE ()
|
writeLPGF :: Options -> LPGF -> IOE FilePath
|
||||||
writeOutput opts file str = writing opts path $ writeUTF8File path str
|
writeLPGF opts lpgf = do
|
||||||
where path = outputPath opts file
|
let
|
||||||
|
grammarName = fromMaybe (showCId (LPGF.abstractName lpgf)) (flag optName opts)
|
||||||
|
outfile = outputPath opts (grammarName <.> "lpgf")
|
||||||
|
writing opts outfile $ liftIO $ LPGF.encodeFile outfile lpgf
|
||||||
|
return outfile
|
||||||
|
|
||||||
|
writeOutput :: Options -> FilePath-> String -> IOE FilePath
|
||||||
|
writeOutput opts file str = do
|
||||||
|
let outfile = outputPath opts file
|
||||||
|
writing opts outfile $ writeUTF8File outfile str
|
||||||
|
return outfile
|
||||||
|
|
||||||
-- * Useful helper functions
|
-- * Useful helper functions
|
||||||
|
|
||||||
grammarName :: Options -> PGF -> String
|
grammarName :: Options -> PGF -> String
|
||||||
grammarName opts pgf = grammarName' opts (abstractName pgf)
|
grammarName opts pgf = grammarName' opts (showCId (abstractName pgf))
|
||||||
grammarName' opts abs = fromMaybe abs (flag optName opts)
|
grammarName' opts abs = fromMaybe abs (flag optName opts)
|
||||||
|
|
||||||
outputJustPGF opts = null (flag optOutputFormats opts) && not (flag optSplitPGF opts)
|
outputJustPGF opts = null (flag optOutputFormats opts) && not (flag optSplitPGF opts)
|
||||||
|
|||||||
@@ -16,18 +16,18 @@
|
|||||||
{-# LANGUAGE CPP #-}
|
{-# LANGUAGE CPP #-}
|
||||||
module GF.Data.BacktrackM (
|
module GF.Data.BacktrackM (
|
||||||
-- * the backtracking state monad
|
-- * the backtracking state monad
|
||||||
BacktrackM,
|
BacktrackM,
|
||||||
-- * monad specific utilities
|
-- * monad specific utilities
|
||||||
member,
|
member,
|
||||||
cut,
|
cut,
|
||||||
-- * running the monad
|
-- * running the monad
|
||||||
foldBM, runBM,
|
foldBM, runBM,
|
||||||
foldSolutions, solutions,
|
foldSolutions, solutions,
|
||||||
foldFinalStates, finalStates,
|
foldFinalStates, finalStates,
|
||||||
|
|
||||||
-- * reexport the 'MonadState' class
|
-- * reexport the 'MonadState' class
|
||||||
module Control.Monad.State.Class,
|
module Control.Monad.State.Class,
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Data.List
|
import Data.List
|
||||||
import Control.Applicative
|
import Control.Applicative
|
||||||
@@ -70,7 +70,7 @@ instance Applicative (BacktrackM s) where
|
|||||||
instance Monad (BacktrackM s) where
|
instance Monad (BacktrackM s) where
|
||||||
return a = BM (\c s b -> c a s b)
|
return a = BM (\c s b -> c a s b)
|
||||||
BM m >>= k = BM (\c s b -> m (\a s b -> unBM (k a) c s b) s b)
|
BM m >>= k = BM (\c s b -> m (\a s b -> unBM (k a) c s b) s b)
|
||||||
where unBM (BM m) = m
|
where unBM (BM m) = m
|
||||||
|
|
||||||
#if !(MIN_VERSION_base(4,13,0))
|
#if !(MIN_VERSION_base(4,13,0))
|
||||||
fail = Fail.fail
|
fail = Fail.fail
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
-- Stability : (stable)
|
-- Stability : (stable)
|
||||||
-- Portability : (portable)
|
-- Portability : (portable)
|
||||||
--
|
--
|
||||||
-- > CVS $Date: 2005/11/10 16:43:44 $
|
-- > CVS $Date: 2005/11/10 16:43:44 $
|
||||||
-- > CVS $Author: bringert $
|
-- > CVS $Author: bringert $
|
||||||
-- > CVS $Revision: 1.2 $
|
-- > CVS $Revision: 1.2 $
|
||||||
--
|
--
|
||||||
@@ -34,7 +34,7 @@ import Data.Set (Set)
|
|||||||
import qualified Data.Set as Set
|
import qualified Data.Set as Set
|
||||||
|
|
||||||
data Graph n a b = Graph [n] ![Node n a] ![Edge n b]
|
data Graph n a b = Graph [n] ![Node n a] ![Edge n b]
|
||||||
deriving (Eq,Show)
|
deriving (Eq,Show)
|
||||||
|
|
||||||
type Node n a = (n,a)
|
type Node n a = (n,a)
|
||||||
type Edge n b = (n,n,b)
|
type Edge n b = (n,n,b)
|
||||||
@@ -63,7 +63,7 @@ emap f (Graph c ns es) = Graph c ns [(x,y,f l) | (x,y,l) <- es]
|
|||||||
|
|
||||||
-- | Add a node to the graph.
|
-- | Add a node to the graph.
|
||||||
newNode :: a -- ^ Node label
|
newNode :: a -- ^ Node label
|
||||||
-> Graph n a b
|
-> Graph n a b
|
||||||
-> (Graph n a b,n) -- ^ Node graph and name of new node
|
-> (Graph n a b,n) -- ^ Node graph and name of new node
|
||||||
newNode l (Graph (c:cs) ns es) = (Graph cs ((c,l):ns) es, c)
|
newNode l (Graph (c:cs) ns es) = (Graph cs ((c,l):ns) es, c)
|
||||||
|
|
||||||
@@ -83,7 +83,7 @@ newEdges es g = foldl' (flip newEdge) g es
|
|||||||
-- lazy version:
|
-- lazy version:
|
||||||
-- newEdges es' (Graph c ns es) = Graph c ns (es'++es)
|
-- newEdges es' (Graph c ns es) = Graph c ns (es'++es)
|
||||||
|
|
||||||
insertEdgeWith :: Eq n =>
|
insertEdgeWith :: Eq n =>
|
||||||
(b -> b -> b) -> Edge n b -> Graph n a b -> Graph n a b
|
(b -> b -> b) -> Edge n b -> Graph n a b -> Graph n a b
|
||||||
insertEdgeWith f e@(x,y,l) (Graph c ns es) = Graph c ns (h es)
|
insertEdgeWith f e@(x,y,l) (Graph c ns es) = Graph c ns (h es)
|
||||||
where h [] = [e]
|
where h [] = [e]
|
||||||
@@ -97,7 +97,7 @@ removeNode n = removeNodes (Set.singleton n)
|
|||||||
-- | Remove a set of nodes and all edges to and from those nodes.
|
-- | Remove a set of nodes and all edges to and from those nodes.
|
||||||
removeNodes :: Ord n => Set n -> Graph n a b -> Graph n a b
|
removeNodes :: Ord n => Set n -> Graph n a b -> Graph n a b
|
||||||
removeNodes xs (Graph c ns es) = Graph c ns' es'
|
removeNodes xs (Graph c ns es) = Graph c ns' es'
|
||||||
where
|
where
|
||||||
keepNode n = not (Set.member n xs)
|
keepNode n = not (Set.member n xs)
|
||||||
ns' = [ x | x@(n,_) <- ns, keepNode n ]
|
ns' = [ x | x@(n,_) <- ns, keepNode n ]
|
||||||
es' = [ e | e@(f,t,_) <- es, keepNode f && keepNode t ]
|
es' = [ e | e@(f,t,_) <- es, keepNode f && keepNode t ]
|
||||||
@@ -105,7 +105,7 @@ removeNodes xs (Graph c ns es) = Graph c ns' es'
|
|||||||
-- | Get a map of node names to info about each node.
|
-- | Get a map of node names to info about each node.
|
||||||
nodeInfo :: Ord n => Graph n a b -> NodeInfo n a b
|
nodeInfo :: Ord n => Graph n a b -> NodeInfo n a b
|
||||||
nodeInfo g = Map.fromList [ (n, (x, fn inc n, fn out n)) | (n,x) <- nodes g ]
|
nodeInfo g = Map.fromList [ (n, (x, fn inc n, fn out n)) | (n,x) <- nodes g ]
|
||||||
where
|
where
|
||||||
inc = groupEdgesBy edgeTo g
|
inc = groupEdgesBy edgeTo g
|
||||||
out = groupEdgesBy edgeFrom g
|
out = groupEdgesBy edgeFrom g
|
||||||
fn m n = fromMaybe [] (Map.lookup n m)
|
fn m n = fromMaybe [] (Map.lookup n m)
|
||||||
@@ -148,16 +148,16 @@ reverseGraph :: Graph n a b -> Graph n a b
|
|||||||
reverseGraph (Graph c ns es) = Graph c ns [ (t,f,l) | (f,t,l) <- es ]
|
reverseGraph (Graph c ns es) = Graph c ns [ (t,f,l) | (f,t,l) <- es ]
|
||||||
|
|
||||||
-- | Add the nodes from the second graph to the first graph.
|
-- | Add the nodes from the second graph to the first graph.
|
||||||
-- The nodes in the second graph will be renamed using the name
|
-- The nodes in the second graph will be renamed using the name
|
||||||
-- supply in the first graph.
|
-- supply in the first graph.
|
||||||
-- This function is more efficient when the second graph
|
-- This function is more efficient when the second graph
|
||||||
-- is smaller than the first.
|
-- is smaller than the first.
|
||||||
mergeGraphs :: Ord m => Graph n a b -> Graph m a b
|
mergeGraphs :: Ord m => Graph n a b -> Graph m a b
|
||||||
-> (Graph n a b, m -> n) -- ^ The new graph and a function translating
|
-> (Graph n a b, m -> n) -- ^ The new graph and a function translating
|
||||||
-- the old names of nodes in the second graph
|
-- the old names of nodes in the second graph
|
||||||
-- to names in the new graph.
|
-- to names in the new graph.
|
||||||
mergeGraphs (Graph c ns1 es1) g2 = (Graph c' (ns2++ns1) (es2++es1), newName)
|
mergeGraphs (Graph c ns1 es1) g2 = (Graph c' (ns2++ns1) (es2++es1), newName)
|
||||||
where
|
where
|
||||||
(xs,c') = splitAt (length (nodes g2)) c
|
(xs,c') = splitAt (length (nodes g2)) c
|
||||||
newNames = Map.fromList (zip (map fst (nodes g2)) xs)
|
newNames = Map.fromList (zip (map fst (nodes g2)) xs)
|
||||||
newName n = fromJust $ Map.lookup n newNames
|
newName n = fromJust $ Map.lookup n newNames
|
||||||
@@ -170,7 +170,7 @@ renameNodes :: (n -> m) -- ^ renaming function
|
|||||||
-> Graph n a b -> Graph m a b
|
-> Graph n a b -> Graph m a b
|
||||||
renameNodes newName c (Graph _ ns es) = Graph c ns' es'
|
renameNodes newName c (Graph _ ns es) = Graph c ns' es'
|
||||||
where ns' = map' (\ (n,x) -> (newName n,x)) ns
|
where ns' = map' (\ (n,x) -> (newName n,x)) ns
|
||||||
es' = map' (\ (f,t,l) -> (newName f, newName t, l)) es
|
es' = map' (\ (f,t,l) -> (newName f, newName t, l)) es
|
||||||
|
|
||||||
-- | A strict 'map'
|
-- | A strict 'map'
|
||||||
map' :: (a -> b) -> [a] -> [b]
|
map' :: (a -> b) -> [a] -> [b]
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
-- Stability : (stable)
|
-- Stability : (stable)
|
||||||
-- Portability : (portable)
|
-- Portability : (portable)
|
||||||
--
|
--
|
||||||
-- > CVS $Date: 2005/09/15 18:10:44 $
|
-- > CVS $Date: 2005/09/15 18:10:44 $
|
||||||
-- > CVS $Author: bringert $
|
-- > CVS $Author: bringert $
|
||||||
-- > CVS $Revision: 1.2 $
|
-- > CVS $Revision: 1.2 $
|
||||||
--
|
--
|
||||||
@@ -13,14 +13,14 @@
|
|||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
|
|
||||||
module GF.Data.Graphviz (
|
module GF.Data.Graphviz (
|
||||||
Graph(..), GraphType(..),
|
Graph(..), GraphType(..),
|
||||||
Node(..), Edge(..),
|
Node(..), Edge(..),
|
||||||
Attr,
|
Attr,
|
||||||
addSubGraphs,
|
addSubGraphs,
|
||||||
setName,
|
setName,
|
||||||
setAttr,
|
setAttr,
|
||||||
prGraphviz
|
prGraphviz
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Data.Char
|
import Data.Char
|
||||||
|
|
||||||
@@ -70,14 +70,14 @@ prGraphviz g@(Graph t i _ _ _ _) =
|
|||||||
graphtype t ++ " " ++ maybe "" esc i ++ " {\n" ++ prGraph g ++ "}\n"
|
graphtype t ++ " " ++ maybe "" esc i ++ " {\n" ++ prGraph g ++ "}\n"
|
||||||
|
|
||||||
prSubGraph :: Graph -> String
|
prSubGraph :: Graph -> String
|
||||||
prSubGraph g@(Graph _ i _ _ _ _) =
|
prSubGraph g@(Graph _ i _ _ _ _) =
|
||||||
"subgraph" ++ " " ++ maybe "" esc i ++ " {\n" ++ prGraph g ++ "}"
|
"subgraph" ++ " " ++ maybe "" esc i ++ " {\n" ++ prGraph g ++ "}"
|
||||||
|
|
||||||
prGraph :: Graph -> String
|
prGraph :: Graph -> String
|
||||||
prGraph (Graph t id at ns es ss) =
|
prGraph (Graph t id at ns es ss) =
|
||||||
unlines $ map (++";") (map prAttr at
|
unlines $ map (++";") (map prAttr at
|
||||||
++ map prNode ns
|
++ map prNode ns
|
||||||
++ map (prEdge t) es
|
++ map (prEdge t) es
|
||||||
++ map prSubGraph ss)
|
++ map prSubGraph ss)
|
||||||
|
|
||||||
graphtype :: GraphType -> String
|
graphtype :: GraphType -> String
|
||||||
@@ -96,7 +96,7 @@ edgeop Undirected = "--"
|
|||||||
|
|
||||||
prAttrList :: [Attr] -> String
|
prAttrList :: [Attr] -> String
|
||||||
prAttrList [] = ""
|
prAttrList [] = ""
|
||||||
prAttrList at = "[" ++ join "," (map prAttr at) ++ "]"
|
prAttrList at = "[" ++ join "," (map prAttr at) ++ "]"
|
||||||
|
|
||||||
prAttr :: Attr -> String
|
prAttr :: Attr -> String
|
||||||
prAttr (n,v) = esc n ++ " = " ++ esc v
|
prAttr (n,v) = esc n ++ " = " ++ esc v
|
||||||
|
|||||||
57
src/compiler/GF/Data/IntMapBuilder.hs
Normal file
57
src/compiler/GF/Data/IntMapBuilder.hs
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
-- | In order to build an IntMap in one pass, we need a map data structure with
|
||||||
|
-- fast lookup in both keys and values.
|
||||||
|
-- This is achieved by keeping a separate reversed map of values to keys during building.
|
||||||
|
module GF.Data.IntMapBuilder where
|
||||||
|
|
||||||
|
import Data.IntMap (IntMap)
|
||||||
|
import qualified Data.IntMap as IntMap
|
||||||
|
import Data.Hashable (Hashable)
|
||||||
|
import Data.HashMap.Strict (HashMap)
|
||||||
|
import qualified Data.HashMap.Strict as HashMap
|
||||||
|
import Data.Tuple (swap)
|
||||||
|
import Prelude hiding (lookup)
|
||||||
|
|
||||||
|
data IMB a = IMB {
|
||||||
|
intMap :: IntMap a,
|
||||||
|
valMap :: HashMap a Int
|
||||||
|
}
|
||||||
|
|
||||||
|
-- | An empty IMB
|
||||||
|
empty :: (Eq a, Hashable a) => IMB a
|
||||||
|
empty = IMB {
|
||||||
|
intMap = IntMap.empty,
|
||||||
|
valMap = HashMap.empty
|
||||||
|
}
|
||||||
|
|
||||||
|
-- | Lookup a value
|
||||||
|
lookup :: (Eq a, Hashable a) => a -> IMB a -> Maybe Int
|
||||||
|
lookup a IMB { valMap = vm } = HashMap.lookup a vm
|
||||||
|
|
||||||
|
-- | Insert without any lookup
|
||||||
|
insert :: (Eq a, Hashable a) => a -> IMB a -> (Int, IMB a)
|
||||||
|
insert a IMB { intMap = im, valMap = vm } =
|
||||||
|
let
|
||||||
|
ix = IntMap.size im
|
||||||
|
im' = IntMap.insert ix a im
|
||||||
|
vm' = HashMap.insert a ix vm
|
||||||
|
imb' = IMB { intMap = im', valMap = vm' }
|
||||||
|
in
|
||||||
|
(ix, imb')
|
||||||
|
|
||||||
|
-- | Insert only when lookup fails
|
||||||
|
insert' :: (Eq a, Hashable a) => a -> IMB a -> (Int, IMB a)
|
||||||
|
insert' a imb =
|
||||||
|
case lookup a imb of
|
||||||
|
Just ix -> (ix, imb)
|
||||||
|
Nothing -> insert a imb
|
||||||
|
|
||||||
|
-- | Build IMB from existing IntMap
|
||||||
|
fromIntMap :: (Eq a, Hashable a) => IntMap a -> IMB a
|
||||||
|
fromIntMap im = IMB {
|
||||||
|
intMap = im,
|
||||||
|
valMap = HashMap.fromList (map swap (IntMap.toList im))
|
||||||
|
}
|
||||||
|
|
||||||
|
-- | Get IntMap from IMB
|
||||||
|
toIntMap :: (Eq a, Hashable a) => IMB a -> IntMap a
|
||||||
|
toIntMap = intMap
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
-- Stability : (stable)
|
-- Stability : (stable)
|
||||||
-- Portability : (portable)
|
-- Portability : (portable)
|
||||||
--
|
--
|
||||||
-- > CVS $Date: 2005/11/11 16:12:41 $
|
-- > CVS $Date: 2005/11/11 16:12:41 $
|
||||||
-- > CVS $Author: bringert $
|
-- > CVS $Author: bringert $
|
||||||
-- > CVS $Revision: 1.22 $
|
-- > CVS $Revision: 1.22 $
|
||||||
--
|
--
|
||||||
@@ -15,34 +15,34 @@
|
|||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
|
|
||||||
module GF.Data.Operations (
|
module GF.Data.Operations (
|
||||||
-- ** The Error monad
|
-- ** The Error monad
|
||||||
Err(..), err, maybeErr, testErr, fromErr, errIn,
|
Err(..), err, maybeErr, testErr, fromErr, errIn,
|
||||||
lookupErr,
|
lookupErr,
|
||||||
|
|
||||||
-- ** Error monad class
|
-- ** Error monad class
|
||||||
ErrorMonad(..), checks, --doUntil, allChecks, checkAgain,
|
ErrorMonad(..), checks, --doUntil, allChecks, checkAgain,
|
||||||
liftErr,
|
liftErr,
|
||||||
|
|
||||||
|
-- ** Checking
|
||||||
|
checkUnique, unifyMaybeBy, unifyMaybe,
|
||||||
|
|
||||||
-- ** Checking
|
-- ** Monadic operations on lists and pairs
|
||||||
checkUnique, unifyMaybeBy, unifyMaybe,
|
mapPairsM, pairM,
|
||||||
|
|
||||||
|
-- ** Printing
|
||||||
|
indent, (+++), (++-), (++++), (+++-), (+++++),
|
||||||
|
prUpper, prReplicate, prTList, prQuotedString, prParenth, prCurly,
|
||||||
|
prBracket, prArgList, prSemicList, prCurlyList, restoreEscapes,
|
||||||
|
numberedParagraphs, prConjList, prIfEmpty, wrapLines,
|
||||||
|
|
||||||
-- ** Monadic operations on lists and pairs
|
-- ** Topological sorting
|
||||||
mapPairsM, pairM,
|
topoTest, topoTest2,
|
||||||
|
|
||||||
-- ** Printing
|
-- ** Misc
|
||||||
indent, (+++), (++-), (++++), (+++-), (+++++),
|
readIntArg,
|
||||||
prUpper, prReplicate, prTList, prQuotedString, prParenth, prCurly,
|
iterFix, chunks,
|
||||||
prBracket, prArgList, prSemicList, prCurlyList, restoreEscapes,
|
|
||||||
numberedParagraphs, prConjList, prIfEmpty, wrapLines,
|
) where
|
||||||
|
|
||||||
-- ** Topological sorting
|
|
||||||
topoTest, topoTest2,
|
|
||||||
|
|
||||||
-- ** Misc
|
|
||||||
readIntArg,
|
|
||||||
iterFix, chunks,
|
|
||||||
|
|
||||||
) where
|
|
||||||
|
|
||||||
import Data.Char (isSpace, toUpper, isSpace, isDigit)
|
import Data.Char (isSpace, toUpper, isSpace, isDigit)
|
||||||
import Data.List (nub, partition, (\\))
|
import Data.List (nub, partition, (\\))
|
||||||
@@ -107,7 +107,7 @@ indent i s = replicate i ' ' ++ s
|
|||||||
(+++), (++-), (++++), (+++-), (+++++) :: String -> String -> String
|
(+++), (++-), (++++), (+++-), (+++++) :: String -> String -> String
|
||||||
a +++ b = a ++ " " ++ b
|
a +++ b = a ++ " " ++ b
|
||||||
|
|
||||||
a ++- "" = a
|
a ++- "" = a
|
||||||
a ++- b = a +++ b
|
a ++- b = a +++ b
|
||||||
|
|
||||||
a ++++ b = a ++ "\n" ++ b
|
a ++++ b = a ++ "\n" ++ b
|
||||||
@@ -145,20 +145,20 @@ prCurly s = "{" ++ s ++ "}"
|
|||||||
prBracket s = "[" ++ s ++ "]"
|
prBracket s = "[" ++ s ++ "]"
|
||||||
|
|
||||||
prArgList, prSemicList, prCurlyList :: [String] -> String
|
prArgList, prSemicList, prCurlyList :: [String] -> String
|
||||||
prArgList = prParenth . prTList ","
|
prArgList = prParenth . prTList ","
|
||||||
prSemicList = prTList " ; "
|
prSemicList = prTList " ; "
|
||||||
prCurlyList = prCurly . prSemicList
|
prCurlyList = prCurly . prSemicList
|
||||||
|
|
||||||
restoreEscapes :: String -> String
|
restoreEscapes :: String -> String
|
||||||
restoreEscapes s =
|
restoreEscapes s =
|
||||||
case s of
|
case s of
|
||||||
[] -> []
|
[] -> []
|
||||||
'"' : t -> '\\' : '"' : restoreEscapes t
|
'"' : t -> '\\' : '"' : restoreEscapes t
|
||||||
'\\': t -> '\\' : '\\' : restoreEscapes t
|
'\\': t -> '\\' : '\\' : restoreEscapes t
|
||||||
c : t -> c : restoreEscapes t
|
c : t -> c : restoreEscapes t
|
||||||
|
|
||||||
numberedParagraphs :: [[String]] -> [String]
|
numberedParagraphs :: [[String]] -> [String]
|
||||||
numberedParagraphs t = case t of
|
numberedParagraphs t = case t of
|
||||||
[] -> []
|
[] -> []
|
||||||
p:[] -> p
|
p:[] -> p
|
||||||
_ -> concat [(show n ++ ".") : s | (n,s) <- zip [1..] t]
|
_ -> concat [(show n ++ ".") : s | (n,s) <- zip [1..] t]
|
||||||
@@ -204,12 +204,12 @@ topoTest2 g0 = maybe (Right cycles) Left (tsort g)
|
|||||||
([],[]) -> Just []
|
([],[]) -> Just []
|
||||||
([],_) -> Nothing
|
([],_) -> Nothing
|
||||||
(ns,rest) -> (leaves:) `fmap` tsort [(n,es \\ leaves) | (n,es)<-rest]
|
(ns,rest) -> (leaves:) `fmap` tsort [(n,es \\ leaves) | (n,es)<-rest]
|
||||||
where leaves = map fst ns
|
where leaves = map fst ns
|
||||||
|
|
||||||
|
|
||||||
-- | Fix point iterator (for computing e.g. transitive closures or reachability)
|
-- | Fix point iterator (for computing e.g. transitive closures or reachability)
|
||||||
iterFix :: Eq a => ([a] -> [a]) -> [a] -> [a]
|
iterFix :: Eq a => ([a] -> [a]) -> [a] -> [a]
|
||||||
iterFix more start = iter start start
|
iterFix more start = iter start start
|
||||||
where
|
where
|
||||||
iter old new = if (null new')
|
iter old new = if (null new')
|
||||||
then old
|
then old
|
||||||
@@ -241,7 +241,7 @@ liftErr e = err raise return e
|
|||||||
{-
|
{-
|
||||||
instance ErrorMonad (STM s) where
|
instance ErrorMonad (STM s) where
|
||||||
raise msg = STM (\s -> raise msg)
|
raise msg = STM (\s -> raise msg)
|
||||||
handle (STM f) g = STM (\s -> (f s)
|
handle (STM f) g = STM (\s -> (f s)
|
||||||
`handle` (\e -> let STM g' = (g e) in
|
`handle` (\e -> let STM g' = (g e) in
|
||||||
g' s))
|
g' s))
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
-- Stability : (stable)
|
-- Stability : (stable)
|
||||||
-- Portability : (portable)
|
-- Portability : (portable)
|
||||||
--
|
--
|
||||||
-- > CVS $Date: 2005/10/26 17:13:13 $
|
-- > CVS $Date: 2005/10/26 17:13:13 $
|
||||||
-- > CVS $Author: bringert $
|
-- > CVS $Author: bringert $
|
||||||
-- > CVS $Revision: 1.1 $
|
-- > CVS $Revision: 1.1 $
|
||||||
--
|
--
|
||||||
@@ -83,7 +83,7 @@ transitiveClosure r = fix (Map.map growSet) r
|
|||||||
where growSet ys = foldl Set.union ys (map (allRelated r) $ Set.toList ys)
|
where growSet ys = foldl Set.union ys (map (allRelated r) $ Set.toList ys)
|
||||||
|
|
||||||
reflexiveClosure_ :: Ord a => [a] -- ^ The set over which the relation is defined.
|
reflexiveClosure_ :: Ord a => [a] -- ^ The set over which the relation is defined.
|
||||||
-> Rel a -> Rel a
|
-> Rel a -> Rel a
|
||||||
reflexiveClosure_ u r = relates [(x,x) | x <- u] r
|
reflexiveClosure_ u r = relates [(x,x) | x <- u] r
|
||||||
|
|
||||||
-- | Uses 'domain'
|
-- | Uses 'domain'
|
||||||
@@ -104,7 +104,7 @@ reflexiveElements :: Ord a => Rel a -> Set a
|
|||||||
reflexiveElements r = Set.fromList [ x | (x,ys) <- Map.toList r, x `Set.member` ys ]
|
reflexiveElements r = Set.fromList [ x | (x,ys) <- Map.toList r, x `Set.member` ys ]
|
||||||
|
|
||||||
-- | Keep the related pairs for which the predicate is true.
|
-- | Keep the related pairs for which the predicate is true.
|
||||||
filterRel :: Ord a => (a -> a -> Bool) -> Rel a -> Rel a
|
filterRel :: Ord a => (a -> a -> Bool) -> Rel a -> Rel a
|
||||||
filterRel p = fst . purgeEmpty . Map.mapWithKey (Set.filter . p)
|
filterRel p = fst . purgeEmpty . Map.mapWithKey (Set.filter . p)
|
||||||
|
|
||||||
-- | Remove keys that map to no elements.
|
-- | Remove keys that map to no elements.
|
||||||
@@ -112,16 +112,16 @@ purgeEmpty :: Ord a => Rel a -> (Rel a, Set a)
|
|||||||
purgeEmpty r = let (r',r'') = Map.partition (not . Set.null) r
|
purgeEmpty r = let (r',r'') = Map.partition (not . Set.null) r
|
||||||
in (r', Map.keysSet r'')
|
in (r', Map.keysSet r'')
|
||||||
|
|
||||||
-- | Get the equivalence classes from an equivalence relation.
|
-- | Get the equivalence classes from an equivalence relation.
|
||||||
equivalenceClasses :: Ord a => Rel a -> [Set a]
|
equivalenceClasses :: Ord a => Rel a -> [Set a]
|
||||||
equivalenceClasses r = equivalenceClasses_ (Map.keys r) r
|
equivalenceClasses r = equivalenceClasses_ (Map.keys r) r
|
||||||
where equivalenceClasses_ [] _ = []
|
where equivalenceClasses_ [] _ = []
|
||||||
equivalenceClasses_ (x:xs) r = ys:equivalenceClasses_ zs r
|
equivalenceClasses_ (x:xs) r = ys:equivalenceClasses_ zs r
|
||||||
where ys = allRelated r x
|
where ys = allRelated r x
|
||||||
zs = [x' | x' <- xs, not (x' `Set.member` ys)]
|
zs = [x' | x' <- xs, not (x' `Set.member` ys)]
|
||||||
|
|
||||||
isTransitive :: Ord a => Rel a -> Bool
|
isTransitive :: Ord a => Rel a -> Bool
|
||||||
isTransitive r = and [z `Set.member` ys | (x,ys) <- Map.toList r,
|
isTransitive r = and [z `Set.member` ys | (x,ys) <- Map.toList r,
|
||||||
y <- Set.toList ys, z <- Set.toList (allRelated r y)]
|
y <- Set.toList ys, z <- Set.toList (allRelated r y)]
|
||||||
|
|
||||||
isReflexive :: Ord a => Rel a -> Bool
|
isReflexive :: Ord a => Rel a -> Bool
|
||||||
@@ -181,7 +181,7 @@ remove x r = let (mss,r') = Map.updateLookupWithKey (\_ _ -> Nothing) x r
|
|||||||
Nothing -> (r', Set.empty, Set.empty)
|
Nothing -> (r', Set.empty, Set.empty)
|
||||||
-- remove element from all incoming and outgoing sets
|
-- remove element from all incoming and outgoing sets
|
||||||
-- of other elements
|
-- of other elements
|
||||||
Just (is,os) ->
|
Just (is,os) ->
|
||||||
let r'' = foldr (\i -> Map.adjust (\ (is',os') -> (is', Set.delete x os')) i) r' $ Set.toList is
|
let r'' = foldr (\i -> Map.adjust (\ (is',os') -> (is', Set.delete x os')) i) r' $ Set.toList is
|
||||||
r''' = foldr (\o -> Map.adjust (\ (is',os') -> (Set.delete x is', os')) o) r'' $ Set.toList os
|
r''' = foldr (\o -> Map.adjust (\ (is',os') -> (Set.delete x is', os')) o) r'' $ Set.toList os
|
||||||
in (r''', is, os)
|
in (r''', is, os)
|
||||||
@@ -190,4 +190,4 @@ incoming :: Ord a => a -> Rel' a -> Set a
|
|||||||
incoming x r = maybe Set.empty fst $ Map.lookup x r
|
incoming x r = maybe Set.empty fst $ Map.lookup x r
|
||||||
|
|
||||||
--outgoing :: Ord a => a -> Rel' a -> Set a
|
--outgoing :: Ord a => a -> Rel' a -> Set a
|
||||||
--outgoing x r = maybe Set.empty snd $ Map.lookup x r
|
--outgoing x r = maybe Set.empty snd $ Map.lookup x r
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
-- Stability : (stable)
|
-- Stability : (stable)
|
||||||
-- Portability : (portable)
|
-- Portability : (portable)
|
||||||
--
|
--
|
||||||
-- > CVS $Date: 2005/10/26 18:47:16 $
|
-- > CVS $Date: 2005/10/26 18:47:16 $
|
||||||
-- > CVS $Author: bringert $
|
-- > CVS $Author: bringert $
|
||||||
-- > CVS $Revision: 1.6 $
|
-- > CVS $Revision: 1.6 $
|
||||||
--
|
--
|
||||||
@@ -33,7 +33,7 @@ longerThan n = not . notLongerThan n
|
|||||||
lookupList :: Eq a => a -> [(a, b)] -> [b]
|
lookupList :: Eq a => a -> [(a, b)] -> [b]
|
||||||
lookupList a [] = []
|
lookupList a [] = []
|
||||||
lookupList a (p:ps) | a == fst p = snd p : lookupList a ps
|
lookupList a (p:ps) | a == fst p = snd p : lookupList a ps
|
||||||
| otherwise = lookupList a ps
|
| otherwise = lookupList a ps
|
||||||
|
|
||||||
split :: [a] -> ([a], [a])
|
split :: [a] -> ([a], [a])
|
||||||
split (x : y : as) = (x:xs, y:ys)
|
split (x : y : as) = (x:xs, y:ys)
|
||||||
@@ -48,8 +48,8 @@ splitBy p (a : as) = if p a then (a:xs, ys) else (xs, a:ys)
|
|||||||
foldMerge :: (a -> a -> a) -> a -> [a] -> a
|
foldMerge :: (a -> a -> a) -> a -> [a] -> a
|
||||||
foldMerge merge zero = fm
|
foldMerge merge zero = fm
|
||||||
where fm [] = zero
|
where fm [] = zero
|
||||||
fm [a] = a
|
fm [a] = a
|
||||||
fm abs = let (as, bs) = split abs in fm as `merge` fm bs
|
fm abs = let (as, bs) = split abs in fm as `merge` fm bs
|
||||||
|
|
||||||
select :: [a] -> [(a, [a])]
|
select :: [a] -> [(a, [a])]
|
||||||
select [] = []
|
select [] = []
|
||||||
@@ -68,7 +68,7 @@ safeInit :: [a] -> [a]
|
|||||||
safeInit [] = []
|
safeInit [] = []
|
||||||
safeInit xs = init xs
|
safeInit xs = init xs
|
||||||
|
|
||||||
-- | Sorts and then groups elements given an ordering of the
|
-- | Sorts and then groups elements given an ordering of the
|
||||||
-- elements.
|
-- elements.
|
||||||
sortGroupBy :: (a -> a -> Ordering) -> [a] -> [[a]]
|
sortGroupBy :: (a -> a -> Ordering) -> [a] -> [[a]]
|
||||||
sortGroupBy f = groupBy (compareEq f) . sortBy f
|
sortGroupBy f = groupBy (compareEq f) . sortBy f
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
module GF.Grammar.BNFC(BNFCRule(..), BNFCSymbol, Symbol(..), CFTerm(..), bnfc2cf) where
|
module GF.Grammar.BNFC(BNFCRule(..), BNFCSymbol, Symbol(..), CFTerm(..), bnfc2cf) where
|
||||||
|
|
||||||
import GF.Grammar.CFG
|
import GF.Grammar.CFG
|
||||||
|
import PGF (Token, mkCId)
|
||||||
import Data.List (partition)
|
import Data.List (partition)
|
||||||
|
|
||||||
type IsList = Bool
|
type IsList = Bool
|
||||||
@@ -63,12 +64,12 @@ transformRules sepMap (BNFCCoercions c num) = rules ++ [lastRule]
|
|||||||
lastRule = Rule (c',[0]) ss rn
|
lastRule = Rule (c',[0]) ss rn
|
||||||
where c' = c ++ show num
|
where c' = c ++ show num
|
||||||
ss = [Terminal "(", NonTerminal (c,[0]), Terminal ")"]
|
ss = [Terminal "(", NonTerminal (c,[0]), Terminal ")"]
|
||||||
rn = CFObj ("coercion_" ++ c) []
|
rn = CFObj (mkCId $ "coercion_" ++ c) []
|
||||||
|
|
||||||
fRules c n = Rule (c',[0]) ss rn
|
fRules c n = Rule (c',[0]) ss rn
|
||||||
where c' = if n == 0 then c else c ++ show n
|
where c' = if n == 0 then c else c ++ show n
|
||||||
ss = [NonTerminal (c ++ show (n+1),[0])]
|
ss = [NonTerminal (c ++ show (n+1),[0])]
|
||||||
rn = CFObj ("coercion_" ++ c') []
|
rn = CFObj (mkCId $ "coercion_" ++ c') []
|
||||||
|
|
||||||
transformSymb :: SepMap -> BNFCSymbol -> (String, ParamCFSymbol)
|
transformSymb :: SepMap -> BNFCSymbol -> (String, ParamCFSymbol)
|
||||||
transformSymb sepMap s = case s of
|
transformSymb sepMap s = case s of
|
||||||
@@ -93,7 +94,7 @@ createListRules' ne isSep symb c = ruleBase : ruleCons
|
|||||||
then [NonTerminal (c,[0]) | ne]
|
then [NonTerminal (c,[0]) | ne]
|
||||||
else [NonTerminal (c,[0]) | ne] ++
|
else [NonTerminal (c,[0]) | ne] ++
|
||||||
[Terminal symb | symb /= "" && ne]
|
[Terminal symb | symb /= "" && ne]
|
||||||
rn = CFObj ("Base" ++ c) []
|
rn = CFObj (mkCId $ "Base" ++ c) []
|
||||||
ruleCons
|
ruleCons
|
||||||
| isSep && symb /= "" && not ne = [Rule ("List" ++ c,[1]) smbs0 rn
|
| isSep && symb /= "" && not ne = [Rule ("List" ++ c,[1]) smbs0 rn
|
||||||
,Rule ("List" ++ c,[1]) smbs1 rn]
|
,Rule ("List" ++ c,[1]) smbs1 rn]
|
||||||
@@ -106,4 +107,4 @@ createListRules' ne isSep symb c = ruleBase : ruleCons
|
|||||||
smbs = [NonTerminal (c,[0])] ++
|
smbs = [NonTerminal (c,[0])] ++
|
||||||
[Terminal symb | symb /= ""] ++
|
[Terminal symb | symb /= ""] ++
|
||||||
[NonTerminal ("List" ++ c,[0])]
|
[NonTerminal ("List" ++ c,[0])]
|
||||||
rn = CFObj ("Cons" ++ c) []
|
rn = CFObj (mkCId $ "Cons" ++ c) []
|
||||||
|
|||||||
@@ -10,9 +10,9 @@
|
|||||||
module GF.Grammar.Binary(VersionTagged(..),decodeModuleHeader,decodeModule,encodeModule) where
|
module GF.Grammar.Binary(VersionTagged(..),decodeModuleHeader,decodeModule,encodeModule) where
|
||||||
|
|
||||||
import Prelude hiding (catch)
|
import Prelude hiding (catch)
|
||||||
import Control.Monad
|
|
||||||
import Control.Exception(catch,ErrorCall(..),throwIO)
|
import Control.Exception(catch,ErrorCall(..),throwIO)
|
||||||
import Data.Binary
|
|
||||||
|
import PGF.Internal(Binary(..),Word8,putWord8,getWord8,encodeFile,decodeFile)
|
||||||
import qualified Data.Map as Map(empty)
|
import qualified Data.Map as Map(empty)
|
||||||
import qualified Data.ByteString.Char8 as BS
|
import qualified Data.ByteString.Char8 as BS
|
||||||
|
|
||||||
@@ -22,7 +22,8 @@ import GF.Infra.Option
|
|||||||
import GF.Infra.UseIO(MonadIO(..))
|
import GF.Infra.UseIO(MonadIO(..))
|
||||||
import GF.Grammar.Grammar
|
import GF.Grammar.Grammar
|
||||||
|
|
||||||
import PGF2.Internal(Literal(..),Symbol(..))
|
import PGF() -- Binary instances
|
||||||
|
import PGF.Internal(Literal(..))
|
||||||
|
|
||||||
-- Please change this every time when the GFO format is changed
|
-- Please change this every time when the GFO format is changed
|
||||||
gfoVersion = "GF04"
|
gfoVersion = "GF04"
|
||||||
@@ -297,53 +298,6 @@ instance Binary Label where
|
|||||||
1 -> fmap LVar get
|
1 -> fmap LVar get
|
||||||
_ -> decodingError
|
_ -> decodingError
|
||||||
|
|
||||||
instance Binary BindType where
|
|
||||||
put Explicit = putWord8 0
|
|
||||||
put Implicit = putWord8 1
|
|
||||||
get = do tag <- getWord8
|
|
||||||
case tag of
|
|
||||||
0 -> return Explicit
|
|
||||||
1 -> return Implicit
|
|
||||||
_ -> decodingError
|
|
||||||
|
|
||||||
instance Binary Literal where
|
|
||||||
put (LStr s) = putWord8 0 >> put s
|
|
||||||
put (LInt i) = putWord8 1 >> put i
|
|
||||||
put (LFlt d) = putWord8 2 >> put d
|
|
||||||
get = do tag <- getWord8
|
|
||||||
case tag of
|
|
||||||
0 -> liftM LStr get
|
|
||||||
1 -> liftM LInt get
|
|
||||||
2 -> liftM LFlt get
|
|
||||||
_ -> decodingError
|
|
||||||
|
|
||||||
instance Binary Symbol where
|
|
||||||
put (SymCat n l) = putWord8 0 >> put (n,l)
|
|
||||||
put (SymLit n l) = putWord8 1 >> put (n,l)
|
|
||||||
put (SymVar n l) = putWord8 2 >> put (n,l)
|
|
||||||
put (SymKS ts) = putWord8 3 >> put ts
|
|
||||||
put (SymKP d vs) = putWord8 4 >> put (d,vs)
|
|
||||||
put SymBIND = putWord8 5
|
|
||||||
put SymSOFT_BIND = putWord8 6
|
|
||||||
put SymNE = putWord8 7
|
|
||||||
put SymSOFT_SPACE = putWord8 8
|
|
||||||
put SymCAPIT = putWord8 9
|
|
||||||
put SymALL_CAPIT = putWord8 10
|
|
||||||
get = do tag <- getWord8
|
|
||||||
case tag of
|
|
||||||
0 -> liftM2 SymCat get get
|
|
||||||
1 -> liftM2 SymLit get get
|
|
||||||
2 -> liftM2 SymVar get get
|
|
||||||
3 -> liftM SymKS get
|
|
||||||
4 -> liftM2 (\d vs -> SymKP d vs) get get
|
|
||||||
5 -> return SymBIND
|
|
||||||
6 -> return SymSOFT_BIND
|
|
||||||
7 -> return SymNE
|
|
||||||
8 -> return SymSOFT_SPACE
|
|
||||||
9 -> return SymCAPIT
|
|
||||||
10-> return SymALL_CAPIT
|
|
||||||
_ -> decodingError
|
|
||||||
|
|
||||||
--putGFOVersion = mapM_ (putWord8 . fromIntegral . ord) gfoVersion
|
--putGFOVersion = mapM_ (putWord8 . fromIntegral . ord) gfoVersion
|
||||||
--getGFOVersion = replicateM (length gfoVersion) (fmap (chr . fromIntegral) getWord8)
|
--getGFOVersion = replicateM (length gfoVersion) (fmap (chr . fromIntegral) getWord8)
|
||||||
--putGFOVersion = put gfoVersion
|
--putGFOVersion = put gfoVersion
|
||||||
|
|||||||
@@ -4,11 +4,10 @@
|
|||||||
--
|
--
|
||||||
-- Context-free grammar representation and manipulation.
|
-- Context-free grammar representation and manipulation.
|
||||||
----------------------------------------------------------------------
|
----------------------------------------------------------------------
|
||||||
module GF.Grammar.CFG(Cat,Token, module GF.Grammar.CFG) where
|
module GF.Grammar.CFG where
|
||||||
|
|
||||||
import GF.Data.Utilities
|
import GF.Data.Utilities
|
||||||
import PGF2(Fun,Cat)
|
import PGF
|
||||||
import PGF2.Internal(Token)
|
|
||||||
import GF.Data.Relation
|
import GF.Data.Relation
|
||||||
|
|
||||||
import Data.Map (Map)
|
import Data.Map (Map)
|
||||||
@@ -21,6 +20,8 @@ import qualified Data.Set as Set
|
|||||||
-- * Types
|
-- * Types
|
||||||
--
|
--
|
||||||
|
|
||||||
|
type Cat = String
|
||||||
|
|
||||||
data Symbol c t = NonTerminal c | Terminal t
|
data Symbol c t = NonTerminal c | Terminal t
|
||||||
deriving (Eq, Ord, Show)
|
deriving (Eq, Ord, Show)
|
||||||
|
|
||||||
@@ -38,12 +39,12 @@ data Grammar c t = Grammar {
|
|||||||
deriving (Eq, Ord, Show)
|
deriving (Eq, Ord, Show)
|
||||||
|
|
||||||
data CFTerm
|
data CFTerm
|
||||||
= CFObj Fun [CFTerm] -- ^ an abstract syntax function with arguments
|
= CFObj CId [CFTerm] -- ^ an abstract syntax function with arguments
|
||||||
| CFAbs Int CFTerm -- ^ A lambda abstraction. The Int is the variable id.
|
| CFAbs Int CFTerm -- ^ A lambda abstraction. The Int is the variable id.
|
||||||
| CFApp CFTerm CFTerm -- ^ Application
|
| CFApp CFTerm CFTerm -- ^ Application
|
||||||
| CFRes Int -- ^ The result of the n:th (0-based) non-terminal
|
| CFRes Int -- ^ The result of the n:th (0-based) non-terminal
|
||||||
| CFVar Int -- ^ A lambda-bound variable
|
| CFVar Int -- ^ A lambda-bound variable
|
||||||
| CFMeta Fun -- ^ A metavariable
|
| CFMeta CId -- ^ A metavariable
|
||||||
deriving (Eq, Ord, Show)
|
deriving (Eq, Ord, Show)
|
||||||
|
|
||||||
type CFSymbol = Symbol Cat Token
|
type CFSymbol = Symbol Cat Token
|
||||||
@@ -231,7 +232,7 @@ uniqueFuns = snd . mapAccumL uniqueFun Set.empty
|
|||||||
uniqueFun funs (Rule cat items (CFObj fun args)) = (Set.insert fun' funs,Rule cat items (CFObj fun' args))
|
uniqueFun funs (Rule cat items (CFObj fun args)) = (Set.insert fun' funs,Rule cat items (CFObj fun' args))
|
||||||
where
|
where
|
||||||
fun' = head [fun'|suffix<-"":map show ([2..]::[Int]),
|
fun' = head [fun'|suffix<-"":map show ([2..]::[Int]),
|
||||||
let fun'=fun++suffix,
|
let fun'=mkCId (showCId fun++suffix),
|
||||||
not (fun' `Set.member` funs)]
|
not (fun' `Set.member` funs)]
|
||||||
|
|
||||||
-- | Gets all rules in a CFG.
|
-- | Gets all rules in a CFG.
|
||||||
@@ -309,12 +310,12 @@ prProductions prods =
|
|||||||
prCFTerm :: CFTerm -> String
|
prCFTerm :: CFTerm -> String
|
||||||
prCFTerm = pr 0
|
prCFTerm = pr 0
|
||||||
where
|
where
|
||||||
pr p (CFObj f args) = paren p (f ++ " (" ++ concat (intersperse "," (map (pr 0) args)) ++ ")")
|
pr p (CFObj f args) = paren p (showCId f ++ " (" ++ concat (intersperse "," (map (pr 0) args)) ++ ")")
|
||||||
pr p (CFAbs i t) = paren p ("\\x" ++ show i ++ ". " ++ pr 0 t)
|
pr p (CFAbs i t) = paren p ("\\x" ++ show i ++ ". " ++ pr 0 t)
|
||||||
pr p (CFApp t1 t2) = paren p (pr 1 t1 ++ "(" ++ pr 0 t2 ++ ")")
|
pr p (CFApp t1 t2) = paren p (pr 1 t1 ++ "(" ++ pr 0 t2 ++ ")")
|
||||||
pr _ (CFRes i) = "$" ++ show i
|
pr _ (CFRes i) = "$" ++ show i
|
||||||
pr _ (CFVar i) = "x" ++ show i
|
pr _ (CFVar i) = "x" ++ show i
|
||||||
pr _ (CFMeta c) = "?" ++ c
|
pr _ (CFMeta c) = "?" ++ showCId c
|
||||||
paren 0 x = x
|
paren 0 x = x
|
||||||
paren 1 x = "(" ++ x ++ ")"
|
paren 1 x = "(" ++ x ++ ")"
|
||||||
|
|
||||||
@@ -322,12 +323,12 @@ prCFTerm = pr 0
|
|||||||
-- * CFRule Utilities
|
-- * CFRule Utilities
|
||||||
--
|
--
|
||||||
|
|
||||||
ruleFun :: Rule c t -> Fun
|
ruleFun :: Rule c t -> CId
|
||||||
ruleFun (Rule _ _ t) = f t
|
ruleFun (Rule _ _ t) = f t
|
||||||
where f (CFObj n _) = n
|
where f (CFObj n _) = n
|
||||||
f (CFApp _ x) = f x
|
f (CFApp _ x) = f x
|
||||||
f (CFAbs _ x) = f x
|
f (CFAbs _ x) = f x
|
||||||
f _ = ""
|
f _ = mkCId ""
|
||||||
|
|
||||||
-- | Check if any of the categories used on the right-hand side
|
-- | Check if any of the categories used on the right-hand side
|
||||||
-- are in the given list of categories.
|
-- are in the given list of categories.
|
||||||
@@ -335,7 +336,7 @@ anyUsedBy :: Eq c => [c] -> Rule c t -> Bool
|
|||||||
anyUsedBy cs (Rule _ ss _) = any (`elem` cs) (filterCats ss)
|
anyUsedBy cs (Rule _ ss _) = any (`elem` cs) (filterCats ss)
|
||||||
|
|
||||||
mkCFTerm :: String -> CFTerm
|
mkCFTerm :: String -> CFTerm
|
||||||
mkCFTerm n = CFObj n []
|
mkCFTerm n = CFObj (mkCId n) []
|
||||||
|
|
||||||
ruleIsNonRecursive :: Ord c => Set c -> Rule c t -> Bool
|
ruleIsNonRecursive :: Ord c => Set c -> Rule c t -> Bool
|
||||||
ruleIsNonRecursive cs = noCatsInSet cs . ruleRhs
|
ruleIsNonRecursive cs = noCatsInSet cs . ruleRhs
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
module GF.Grammar.Canonical where
|
module GF.Grammar.Canonical where
|
||||||
import Prelude hiding ((<>))
|
import Prelude hiding ((<>))
|
||||||
import GF.Text.Pretty
|
import GF.Text.Pretty
|
||||||
import GF.Infra.Ident (RawIdent)
|
|
||||||
|
|
||||||
-- | A Complete grammar
|
-- | A Complete grammar
|
||||||
data Grammar = Grammar Abstract [Concrete] deriving Show
|
data Grammar = Grammar Abstract [Concrete] deriving Show
|
||||||
@@ -31,7 +30,7 @@ data TypeApp = TypeApp CatId [Type] deriving Show
|
|||||||
data TypeBinding = TypeBinding VarId Type deriving Show
|
data TypeBinding = TypeBinding VarId Type deriving Show
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
-- ** Concreate syntax
|
-- ** Concrete syntax
|
||||||
|
|
||||||
-- | Concrete Syntax
|
-- | Concrete Syntax
|
||||||
data Concrete = Concrete ModId ModId Flags [ParamDef] [LincatDef] [LinDef]
|
data Concrete = Concrete ModId ModId Flags [ParamDef] [LincatDef] [LinDef]
|
||||||
@@ -103,9 +102,9 @@ data TableRow rhs = TableRow LinPattern rhs
|
|||||||
|
|
||||||
-- *** Identifiers in Concrete Syntax
|
-- *** Identifiers in Concrete Syntax
|
||||||
|
|
||||||
newtype PredefId = PredefId Id deriving (Eq,Ord,Show)
|
newtype PredefId = PredefId Id deriving (Eq,Ord,Show)
|
||||||
newtype LabelId = LabelId Id deriving (Eq,Ord,Show)
|
newtype LabelId = LabelId Id deriving (Eq,Ord,Show)
|
||||||
data VarValueId = VarValueId QualId deriving (Eq,Ord,Show)
|
newtype VarValueId = VarValueId QualId deriving (Eq,Ord,Show)
|
||||||
|
|
||||||
-- | Name of param type or param value
|
-- | Name of param type or param value
|
||||||
newtype ParamId = ParamId QualId deriving (Eq,Ord,Show)
|
newtype ParamId = ParamId QualId deriving (Eq,Ord,Show)
|
||||||
@@ -116,9 +115,9 @@ newtype ParamId = ParamId QualId deriving (Eq,Ord,Show)
|
|||||||
newtype ModId = ModId Id deriving (Eq,Ord,Show)
|
newtype ModId = ModId Id deriving (Eq,Ord,Show)
|
||||||
|
|
||||||
newtype CatId = CatId Id deriving (Eq,Ord,Show)
|
newtype CatId = CatId Id deriving (Eq,Ord,Show)
|
||||||
newtype FunId = FunId Id deriving (Eq,Show)
|
newtype FunId = FunId Id deriving (Eq,Ord,Show)
|
||||||
|
|
||||||
data VarId = Anonymous | VarId Id deriving Show
|
data VarId = Anonymous | VarId Id deriving (Eq,Show)
|
||||||
|
|
||||||
newtype Flags = Flags [(FlagName,FlagValue)] deriving Show
|
newtype Flags = Flags [(FlagName,FlagValue)] deriving Show
|
||||||
type FlagName = Id
|
type FlagName = Id
|
||||||
@@ -127,7 +126,7 @@ data FlagValue = Str String | Int Int | Flt Double deriving Show
|
|||||||
|
|
||||||
-- *** Identifiers
|
-- *** Identifiers
|
||||||
|
|
||||||
type Id = RawIdent
|
type Id = String
|
||||||
data QualId = Qual ModId Id | Unqual Id deriving (Eq,Ord,Show)
|
data QualId = Qual ModId Id | Unqual Id deriving (Eq,Ord,Show)
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
@@ -266,6 +265,7 @@ instance PPA LinPattern where
|
|||||||
RecordPattern r -> block r
|
RecordPattern r -> block r
|
||||||
TuplePattern ps -> "<"<>punctuate "," ps<>">"
|
TuplePattern ps -> "<"<>punctuate "," ps<>">"
|
||||||
WildPattern -> pp "_"
|
WildPattern -> pp "_"
|
||||||
|
_ -> parens p
|
||||||
|
|
||||||
instance RhsSeparator LinPattern where rhsSep _ = pp "="
|
instance RhsSeparator LinPattern where rhsSep _ = pp "="
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import Control.Applicative ((<|>))
|
|||||||
import Data.Ratio (denominator, numerator)
|
import Data.Ratio (denominator, numerator)
|
||||||
import GF.Grammar.Canonical
|
import GF.Grammar.Canonical
|
||||||
import Control.Monad (guard)
|
import Control.Monad (guard)
|
||||||
import GF.Infra.Ident (RawIdent,showRawIdent,rawIdentS)
|
|
||||||
|
|
||||||
|
|
||||||
encodeJSON :: FilePath -> Grammar -> IO ()
|
encodeJSON :: FilePath -> Grammar -> IO ()
|
||||||
@@ -30,7 +29,7 @@ instance JSON Grammar where
|
|||||||
-- ** Abstract Syntax
|
-- ** Abstract Syntax
|
||||||
|
|
||||||
instance JSON Abstract where
|
instance JSON Abstract where
|
||||||
showJSON (Abstract absid flags cats funs)
|
showJSON (Abstract absid flags cats funs)
|
||||||
= makeObj [("abs", showJSON absid),
|
= makeObj [("abs", showJSON absid),
|
||||||
("flags", showJSON flags),
|
("flags", showJSON flags),
|
||||||
("cats", showJSON cats),
|
("cats", showJSON cats),
|
||||||
@@ -82,7 +81,7 @@ instance JSON TypeBinding where
|
|||||||
-- ** Concrete syntax
|
-- ** Concrete syntax
|
||||||
|
|
||||||
instance JSON Concrete where
|
instance JSON Concrete where
|
||||||
showJSON (Concrete cncid absid flags params lincats lins)
|
showJSON (Concrete cncid absid flags params lincats lins)
|
||||||
= makeObj [("cnc", showJSON cncid),
|
= makeObj [("cnc", showJSON cncid),
|
||||||
("abs", showJSON absid),
|
("abs", showJSON absid),
|
||||||
("flags", showJSON flags),
|
("flags", showJSON flags),
|
||||||
@@ -205,12 +204,12 @@ instance JSON a => JSON (RecordRow a) where
|
|||||||
-- record rows and lists of record rows are both encoded as JSON records (i.e., objects)
|
-- record rows and lists of record rows are both encoded as JSON records (i.e., objects)
|
||||||
showJSON row = showJSONs [row]
|
showJSON row = showJSONs [row]
|
||||||
showJSONs rows = makeObj (map toRow rows)
|
showJSONs rows = makeObj (map toRow rows)
|
||||||
where toRow (RecordRow (LabelId lbl) val) = (showRawIdent lbl, showJSON val)
|
where toRow (RecordRow (LabelId lbl) val) = (lbl, showJSON val)
|
||||||
|
|
||||||
readJSON obj = head <$> readJSONs obj
|
readJSON obj = head <$> readJSONs obj
|
||||||
readJSONs obj = mapM fromRow (assocsJSObject obj)
|
readJSONs obj = mapM fromRow (assocsJSObject obj)
|
||||||
where fromRow (lbl, jsvalue) = do value <- readJSON jsvalue
|
where fromRow (lbl, jsvalue) = do value <- readJSON jsvalue
|
||||||
return (RecordRow (LabelId (rawIdentS lbl)) value)
|
return (RecordRow (LabelId lbl) value)
|
||||||
|
|
||||||
instance JSON rhs => JSON (TableRow rhs) where
|
instance JSON rhs => JSON (TableRow rhs) where
|
||||||
showJSON (TableRow l v) = makeObj [(".pattern", showJSON l), (".value", showJSON v)]
|
showJSON (TableRow l v) = makeObj [(".pattern", showJSON l), (".value", showJSON v)]
|
||||||
@@ -220,19 +219,19 @@ instance JSON rhs => JSON (TableRow rhs) where
|
|||||||
|
|
||||||
-- *** Identifiers in Concrete Syntax
|
-- *** Identifiers in Concrete Syntax
|
||||||
|
|
||||||
instance JSON PredefId where showJSON (PredefId s) = showJSON s ; readJSON = fmap PredefId . readJSON
|
instance JSON PredefId where showJSON (PredefId s) = showJSON s ; readJSON = fmap PredefId . readJSON
|
||||||
instance JSON LabelId where showJSON (LabelId s) = showJSON s ; readJSON = fmap LabelId . readJSON
|
instance JSON LabelId where showJSON (LabelId s) = showJSON s ; readJSON = fmap LabelId . readJSON
|
||||||
instance JSON VarValueId where showJSON (VarValueId s) = showJSON s ; readJSON = fmap VarValueId . readJSON
|
instance JSON VarValueId where showJSON (VarValueId s) = showJSON s ; readJSON = fmap VarValueId . readJSON
|
||||||
instance JSON ParamId where showJSON (ParamId s) = showJSON s ; readJSON = fmap ParamId . readJSON
|
instance JSON ParamId where showJSON (ParamId s) = showJSON s ; readJSON = fmap ParamId . readJSON
|
||||||
instance JSON ParamType where showJSON (ParamTypeId s) = showJSON s ; readJSON = fmap ParamTypeId . readJSON
|
instance JSON ParamType where showJSON (ParamTypeId s) = showJSON s ; readJSON = fmap ParamTypeId . readJSON
|
||||||
|
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
-- ** Used in both Abstract and Concrete Syntax
|
-- ** Used in both Abstract and Concrete Syntax
|
||||||
|
|
||||||
instance JSON ModId where showJSON (ModId s) = showJSON s ; readJSON = fmap ModId . readJSON
|
instance JSON ModId where showJSON (ModId s) = showJSON s ; readJSON = fmap ModId . readJSON
|
||||||
instance JSON CatId where showJSON (CatId s) = showJSON s ; readJSON = fmap CatId . readJSON
|
instance JSON CatId where showJSON (CatId s) = showJSON s ; readJSON = fmap CatId . readJSON
|
||||||
instance JSON FunId where showJSON (FunId s) = showJSON s ; readJSON = fmap FunId . readJSON
|
instance JSON FunId where showJSON (FunId s) = showJSON s ; readJSON = fmap FunId . readJSON
|
||||||
|
|
||||||
instance JSON VarId where
|
instance JSON VarId where
|
||||||
-- the anonymous variable is the underscore:
|
-- the anonymous variable is the underscore:
|
||||||
@@ -243,24 +242,20 @@ instance JSON VarId where
|
|||||||
<|> VarId <$> readJSON o
|
<|> VarId <$> readJSON o
|
||||||
|
|
||||||
instance JSON QualId where
|
instance JSON QualId where
|
||||||
showJSON (Qual (ModId m) n) = showJSON (showRawIdent m++"."++showRawIdent n)
|
showJSON (Qual (ModId m) n) = showJSON (m++"."++n)
|
||||||
showJSON (Unqual n) = showJSON n
|
showJSON (Unqual n) = showJSON n
|
||||||
|
|
||||||
readJSON o = do qualid <- readJSON o
|
readJSON o = do qualid <- readJSON o
|
||||||
let (mod, id) = span (/= '.') qualid
|
let (mod, id) = span (/= '.') qualid
|
||||||
return $ if null mod then Unqual (rawIdentS id) else Qual (ModId (rawIdentS mod)) (rawIdentS id)
|
return $ if null mod then Unqual id else Qual (ModId mod) id
|
||||||
|
|
||||||
instance JSON RawIdent where
|
|
||||||
showJSON i = showJSON $ showRawIdent i
|
|
||||||
readJSON o = rawIdentS <$> readJSON o
|
|
||||||
|
|
||||||
instance JSON Flags where
|
instance JSON Flags where
|
||||||
-- flags are encoded directly as JSON records (i.e., objects):
|
-- flags are encoded directly as JSON records (i.e., objects):
|
||||||
showJSON (Flags fs) = makeObj [(showRawIdent f, showJSON v) | (f, v) <- fs]
|
showJSON (Flags fs) = makeObj [(f, showJSON v) | (f, v) <- fs]
|
||||||
|
|
||||||
readJSON obj = Flags <$> mapM fromRow (assocsJSObject obj)
|
readJSON obj = Flags <$> mapM fromRow (assocsJSObject obj)
|
||||||
where fromRow (lbl, jsvalue) = do value <- readJSON jsvalue
|
where fromRow (lbl, jsvalue) = do value <- readJSON jsvalue
|
||||||
return (rawIdentS lbl, value)
|
return (lbl, value)
|
||||||
|
|
||||||
instance JSON FlagValue where
|
instance JSON FlagValue where
|
||||||
-- flag values are encoded as basic JSON types:
|
-- flag values are encoded as basic JSON types:
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ module GF.Grammar.EBNF (EBNF, ERule, ERHS(..), ebnf2cf) where
|
|||||||
|
|
||||||
import GF.Data.Operations
|
import GF.Data.Operations
|
||||||
import GF.Grammar.CFG
|
import GF.Grammar.CFG
|
||||||
|
import PGF (mkCId)
|
||||||
|
|
||||||
type EBNF = [ERule]
|
type EBNF = [ERule]
|
||||||
type ERule = (ECat, ERHS)
|
type ERule = (ECat, ERHS)
|
||||||
@@ -39,7 +40,7 @@ ebnf2cf :: EBNF -> [ParamCFRule]
|
|||||||
ebnf2cf ebnf =
|
ebnf2cf ebnf =
|
||||||
[Rule cat items (mkCFF i cat) | (i,(cat,items)) <- zip [0..] (normEBNF ebnf)]
|
[Rule cat items (mkCFF i cat) | (i,(cat,items)) <- zip [0..] (normEBNF ebnf)]
|
||||||
where
|
where
|
||||||
mkCFF i (c,_) = CFObj ("Mk" ++ c ++ "_" ++ show i) []
|
mkCFF i (c,_) = CFObj (mkCId ("Mk" ++ c ++ "_" ++ show i)) []
|
||||||
|
|
||||||
normEBNF :: EBNF -> [CFJustRule]
|
normEBNF :: EBNF -> [CFJustRule]
|
||||||
normEBNF erules = let
|
normEBNF erules = let
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ module GF.Grammar.Grammar (
|
|||||||
Location(..), L(..), unLoc, noLoc, ppLocation, ppL,
|
Location(..), L(..), unLoc, noLoc, ppLocation, ppL,
|
||||||
|
|
||||||
-- ** PMCFG
|
-- ** PMCFG
|
||||||
PMCFG(..), Production(..), FId, FunId, SeqId, LIndex
|
PMCFG(..), Production(..), FId, FunId, SeqId, LIndex, Sequence
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import GF.Infra.Ident
|
import GF.Infra.Ident
|
||||||
@@ -73,8 +73,7 @@ import GF.Infra.Location
|
|||||||
|
|
||||||
import GF.Data.Operations
|
import GF.Data.Operations
|
||||||
|
|
||||||
import PGF2(BindType(..))
|
import PGF.Internal (FId, FunId, SeqId, LIndex, Sequence, BindType(..))
|
||||||
import PGF2.Internal(FId, FunId, SeqId, LIndex, Symbol)
|
|
||||||
|
|
||||||
import Data.Array.IArray(Array)
|
import Data.Array.IArray(Array)
|
||||||
import Data.Array.Unboxed(UArray)
|
import Data.Array.Unboxed(UArray)
|
||||||
@@ -100,7 +99,7 @@ data ModuleInfo = ModInfo {
|
|||||||
mopens :: [OpenSpec],
|
mopens :: [OpenSpec],
|
||||||
mexdeps :: [ModuleName],
|
mexdeps :: [ModuleName],
|
||||||
msrc :: FilePath,
|
msrc :: FilePath,
|
||||||
mseqs :: Maybe (Array SeqId [Symbol]),
|
mseqs :: Maybe (Array SeqId Sequence),
|
||||||
jments :: Map.Map Ident Info
|
jments :: Map.Map Ident Info
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -267,7 +267,7 @@ type AlexInput2 = (AlexInput,AlexInput)
|
|||||||
|
|
||||||
data ParseResult a
|
data ParseResult a
|
||||||
= POk AlexInput2 a
|
= POk AlexInput2 a
|
||||||
| PFailed Posn -- The position of the error
|
| PFailed Posn -- The position of the error
|
||||||
String -- The error message
|
String -- The error message
|
||||||
|
|
||||||
newtype P a = P { unP :: AlexInput2 -> ParseResult a }
|
newtype P a = P { unP :: AlexInput2 -> ParseResult a }
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
-- Stability : (stable)
|
-- Stability : (stable)
|
||||||
-- Portability : (portable)
|
-- Portability : (portable)
|
||||||
--
|
--
|
||||||
-- > CVS $Date: 2005/10/27 13:21:53 $
|
-- > CVS $Date: 2005/10/27 13:21:53 $
|
||||||
-- > CVS $Author: aarne $
|
-- > CVS $Author: aarne $
|
||||||
-- > CVS $Revision: 1.15 $
|
-- > CVS $Revision: 1.15 $
|
||||||
--
|
--
|
||||||
@@ -20,17 +20,17 @@ module GF.Grammar.Lookup (
|
|||||||
lookupOrigInfo,
|
lookupOrigInfo,
|
||||||
allOrigInfos,
|
allOrigInfos,
|
||||||
lookupResDef, lookupResDefLoc,
|
lookupResDef, lookupResDefLoc,
|
||||||
lookupResType,
|
lookupResType,
|
||||||
lookupOverload,
|
lookupOverload,
|
||||||
lookupOverloadTypes,
|
lookupOverloadTypes,
|
||||||
lookupParamValues,
|
lookupParamValues,
|
||||||
allParamValues,
|
allParamValues,
|
||||||
lookupAbsDef,
|
lookupAbsDef,
|
||||||
lookupLincat,
|
lookupLincat,
|
||||||
lookupFunType,
|
lookupFunType,
|
||||||
lookupCatContext,
|
lookupCatContext,
|
||||||
allOpers, allOpersTo
|
allOpers, allOpersTo
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import GF.Data.Operations
|
import GF.Data.Operations
|
||||||
import GF.Infra.Ident
|
import GF.Infra.Ident
|
||||||
@@ -69,7 +69,7 @@ lookupResDef gr x = fmap unLoc (lookupResDefLoc gr x)
|
|||||||
lookupResDefLoc gr (m,c)
|
lookupResDefLoc gr (m,c)
|
||||||
| isPredefCat c = fmap noLoc (lock c defLinType)
|
| isPredefCat c = fmap noLoc (lock c defLinType)
|
||||||
| otherwise = look m c
|
| otherwise = look m c
|
||||||
where
|
where
|
||||||
look m c = do
|
look m c = do
|
||||||
info <- lookupQIdentInfo gr (m,c)
|
info <- lookupQIdentInfo gr (m,c)
|
||||||
case info of
|
case info of
|
||||||
@@ -77,7 +77,7 @@ lookupResDefLoc gr (m,c)
|
|||||||
ResOper _ Nothing -> return (noLoc (Q (m,c)))
|
ResOper _ Nothing -> return (noLoc (Q (m,c)))
|
||||||
CncCat (Just (L l ty)) _ _ _ _ -> fmap (L l) (lock c ty)
|
CncCat (Just (L l ty)) _ _ _ _ -> fmap (L l) (lock c ty)
|
||||||
CncCat _ _ _ _ _ -> fmap noLoc (lock c defLinType)
|
CncCat _ _ _ _ _ -> fmap noLoc (lock c defLinType)
|
||||||
|
|
||||||
CncFun (Just (cat,_,_)) (Just (L l tr)) _ _ -> fmap (L l) (unlock cat tr)
|
CncFun (Just (cat,_,_)) (Just (L l tr)) _ _ -> fmap (L l) (unlock cat tr)
|
||||||
CncFun _ (Just ltr) _ _ -> return ltr
|
CncFun _ (Just ltr) _ _ -> return ltr
|
||||||
|
|
||||||
@@ -95,7 +95,7 @@ lookupResType gr (m,c) = do
|
|||||||
-- used in reused concrete
|
-- used in reused concrete
|
||||||
CncCat _ _ _ _ _ -> return typeType
|
CncCat _ _ _ _ _ -> return typeType
|
||||||
CncFun (Just (cat,cont,val)) _ _ _ -> do
|
CncFun (Just (cat,cont,val)) _ _ _ -> do
|
||||||
val' <- lock cat val
|
val' <- lock cat val
|
||||||
return $ mkProd cont val' []
|
return $ mkProd cont val' []
|
||||||
AnyInd _ n -> lookupResType gr (n,c)
|
AnyInd _ n -> lookupResType gr (n,c)
|
||||||
ResParam _ _ -> return typePType
|
ResParam _ _ -> return typePType
|
||||||
@@ -111,7 +111,7 @@ lookupOverloadTypes gr id@(m,c) = do
|
|||||||
-- used in reused concrete
|
-- used in reused concrete
|
||||||
CncCat _ _ _ _ _ -> ret typeType
|
CncCat _ _ _ _ _ -> ret typeType
|
||||||
CncFun (Just (cat,cont,val)) _ _ _ -> do
|
CncFun (Just (cat,cont,val)) _ _ _ -> do
|
||||||
val' <- lock cat val
|
val' <- lock cat val
|
||||||
ret $ mkProd cont val' []
|
ret $ mkProd cont val' []
|
||||||
ResParam _ _ -> ret typePType
|
ResParam _ _ -> ret typePType
|
||||||
ResValue (L _ t) -> ret t
|
ResValue (L _ t) -> ret t
|
||||||
@@ -130,8 +130,8 @@ lookupOverload gr (m,c) = do
|
|||||||
case info of
|
case info of
|
||||||
ResOverload os tysts -> do
|
ResOverload os tysts -> do
|
||||||
tss <- mapM (\x -> lookupOverload gr (x,c)) os
|
tss <- mapM (\x -> lookupOverload gr (x,c)) os
|
||||||
return $ [let (args,val) = typeFormCnc ty in (map (\(b,x,t) -> t) args,(val,tr)) |
|
return $ [let (args,val) = typeFormCnc ty in (map (\(b,x,t) -> t) args,(val,tr)) |
|
||||||
(L _ ty,L _ tr) <- tysts] ++
|
(L _ ty,L _ tr) <- tysts] ++
|
||||||
concat tss
|
concat tss
|
||||||
|
|
||||||
AnyInd _ n -> lookupOverload gr (n,c)
|
AnyInd _ n -> lookupOverload gr (n,c)
|
||||||
@@ -216,7 +216,7 @@ lookupCatContext gr m c = do
|
|||||||
-- notice that it only gives the modules that are reachable and the opers that are included
|
-- notice that it only gives the modules that are reachable and the opers that are included
|
||||||
|
|
||||||
allOpers :: Grammar -> [(QIdent,Type,Location)]
|
allOpers :: Grammar -> [(QIdent,Type,Location)]
|
||||||
allOpers gr =
|
allOpers gr =
|
||||||
[((m,op),typ,loc) |
|
[((m,op),typ,loc) |
|
||||||
(m,mi) <- maybe [] (allExtends gr) (greatestResource gr),
|
(m,mi) <- maybe [] (allExtends gr) (greatestResource gr),
|
||||||
(op,info) <- Map.toList (jments mi),
|
(op,info) <- Map.toList (jments mi),
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
-- Stability : (stable)
|
-- Stability : (stable)
|
||||||
-- Portability : (portable)
|
-- Portability : (portable)
|
||||||
--
|
--
|
||||||
-- > CVS $Date: 2005/11/11 16:38:00 $
|
-- > CVS $Date: 2005/11/11 16:38:00 $
|
||||||
-- > CVS $Author: bringert $
|
-- > CVS $Author: bringert $
|
||||||
-- > CVS $Revision: 1.24 $
|
-- > CVS $Revision: 1.24 $
|
||||||
--
|
--
|
||||||
@@ -51,14 +51,14 @@ typeForm t =
|
|||||||
_ -> error (render ("no normal form of type" <+> ppTerm Unqualified 0 t))
|
_ -> error (render ("no normal form of type" <+> ppTerm Unqualified 0 t))
|
||||||
|
|
||||||
typeFormCnc :: Type -> (Context, Type)
|
typeFormCnc :: Type -> (Context, Type)
|
||||||
typeFormCnc t =
|
typeFormCnc t =
|
||||||
case t of
|
case t of
|
||||||
Prod b x a t -> let (x', v) = typeFormCnc t
|
Prod b x a t -> let (x', v) = typeFormCnc t
|
||||||
in ((b,x,a):x',v)
|
in ((b,x,a):x',v)
|
||||||
_ -> ([],t)
|
_ -> ([],t)
|
||||||
|
|
||||||
valCat :: Type -> Cat
|
valCat :: Type -> Cat
|
||||||
valCat typ =
|
valCat typ =
|
||||||
let (_,cat,_) = typeForm typ
|
let (_,cat,_) = typeForm typ
|
||||||
in cat
|
in cat
|
||||||
|
|
||||||
@@ -99,7 +99,7 @@ isHigherOrderType t = fromErr True $ do -- pessimistic choice
|
|||||||
contextOfType :: Monad m => Type -> m Context
|
contextOfType :: Monad m => Type -> m Context
|
||||||
contextOfType typ = case typ of
|
contextOfType typ = case typ of
|
||||||
Prod b x a t -> liftM ((b,x,a):) $ contextOfType t
|
Prod b x a t -> liftM ((b,x,a):) $ contextOfType t
|
||||||
_ -> return []
|
_ -> return []
|
||||||
|
|
||||||
termForm :: Monad m => Term -> m ([(BindType,Ident)], Term, [Term])
|
termForm :: Monad m => Term -> m ([(BindType,Ident)], Term, [Term])
|
||||||
termForm t = case t of
|
termForm t = case t of
|
||||||
@@ -108,8 +108,8 @@ termForm t = case t of
|
|||||||
return ((b,x):x', fun, args)
|
return ((b,x):x', fun, args)
|
||||||
App c a ->
|
App c a ->
|
||||||
do (_,fun, args) <- termForm c
|
do (_,fun, args) <- termForm c
|
||||||
return ([],fun,args ++ [a])
|
return ([],fun,args ++ [a])
|
||||||
_ ->
|
_ ->
|
||||||
return ([],t,[])
|
return ([],t,[])
|
||||||
|
|
||||||
termFormCnc :: Term -> ([(BindType,Ident)], Term)
|
termFormCnc :: Term -> ([(BindType,Ident)], Term)
|
||||||
@@ -254,7 +254,7 @@ mkTable :: [Term] -> Term -> Term
|
|||||||
mkTable tt t = foldr Table t tt
|
mkTable tt t = foldr Table t tt
|
||||||
|
|
||||||
mkCTable :: [(BindType,Ident)] -> Term -> Term
|
mkCTable :: [(BindType,Ident)] -> Term -> Term
|
||||||
mkCTable ids v = foldr ccase v ids where
|
mkCTable ids v = foldr ccase v ids where
|
||||||
ccase (_,x) t = T TRaw [(PV x,t)]
|
ccase (_,x) t = T TRaw [(PV x,t)]
|
||||||
|
|
||||||
mkHypo :: Term -> Hypo
|
mkHypo :: Term -> Hypo
|
||||||
@@ -287,7 +287,7 @@ plusRecType t1 t2 = case (t1, t2) of
|
|||||||
filter (`elem` (map fst r1)) (map fst r2) of
|
filter (`elem` (map fst r1)) (map fst r2) of
|
||||||
[] -> return (RecType (r1 ++ r2))
|
[] -> return (RecType (r1 ++ r2))
|
||||||
ls -> raise $ render ("clashing labels" <+> hsep ls)
|
ls -> raise $ render ("clashing labels" <+> hsep ls)
|
||||||
_ -> raise $ render ("cannot add record types" <+> ppTerm Unqualified 0 t1 <+> "and" <+> ppTerm Unqualified 0 t2)
|
_ -> raise $ render ("cannot add record types" <+> ppTerm Unqualified 0 t1 <+> "and" <+> ppTerm Unqualified 0 t2)
|
||||||
|
|
||||||
--plusRecord :: Term -> Term -> Err Term
|
--plusRecord :: Term -> Term -> Err Term
|
||||||
plusRecord t1 t2 =
|
plusRecord t1 t2 =
|
||||||
@@ -304,7 +304,7 @@ defLinType = RecType [(theLinLabel, typeStr)]
|
|||||||
|
|
||||||
-- | refreshing variables
|
-- | refreshing variables
|
||||||
mkFreshVar :: [Ident] -> Ident
|
mkFreshVar :: [Ident] -> Ident
|
||||||
mkFreshVar olds = varX (maxVarIndex olds + 1)
|
mkFreshVar olds = varX (maxVarIndex olds + 1)
|
||||||
|
|
||||||
-- | trying to preserve a given symbol
|
-- | trying to preserve a given symbol
|
||||||
mkFreshVarX :: [Ident] -> Ident -> Ident
|
mkFreshVarX :: [Ident] -> Ident -> Ident
|
||||||
@@ -313,7 +313,7 @@ mkFreshVarX olds x = if (elem x olds) then (varX (maxVarIndex olds + 1)) else x
|
|||||||
maxVarIndex :: [Ident] -> Int
|
maxVarIndex :: [Ident] -> Int
|
||||||
maxVarIndex = maximum . ((-1):) . map varIndex
|
maxVarIndex = maximum . ((-1):) . map varIndex
|
||||||
|
|
||||||
mkFreshVars :: Int -> [Ident] -> [Ident]
|
mkFreshVars :: Int -> [Ident] -> [Ident]
|
||||||
mkFreshVars n olds = [varX (maxVarIndex olds + i) | i <- [1..n]]
|
mkFreshVars n olds = [varX (maxVarIndex olds + i) | i <- [1..n]]
|
||||||
|
|
||||||
-- | quick hack for refining with var in editor
|
-- | quick hack for refining with var in editor
|
||||||
@@ -413,11 +413,11 @@ patt2term pt = case pt of
|
|||||||
PC c pp -> mkApp (Con c) (map patt2term pp)
|
PC c pp -> mkApp (Con c) (map patt2term pp)
|
||||||
PP c pp -> mkApp (QC c) (map patt2term pp)
|
PP c pp -> mkApp (QC c) (map patt2term pp)
|
||||||
|
|
||||||
PR r -> R [assign l (patt2term p) | (l,p) <- r]
|
PR r -> R [assign l (patt2term p) | (l,p) <- r]
|
||||||
PT _ p -> patt2term p
|
PT _ p -> patt2term p
|
||||||
PInt i -> EInt i
|
PInt i -> EInt i
|
||||||
PFloat i -> EFloat i
|
PFloat i -> EFloat i
|
||||||
PString s -> K s
|
PString s -> K s
|
||||||
|
|
||||||
PAs x p -> appCons cAs [Vr x, patt2term p] --- an encoding
|
PAs x p -> appCons cAs [Vr x, patt2term p] --- an encoding
|
||||||
PChar -> appCons cChar [] --- an encoding
|
PChar -> appCons cChar [] --- an encoding
|
||||||
@@ -436,7 +436,7 @@ composSafeOp op = runIdentity . composOp (return . op)
|
|||||||
|
|
||||||
-- | to define compositional term functions
|
-- | to define compositional term functions
|
||||||
composOp :: Monad m => (Term -> m Term) -> Term -> m Term
|
composOp :: Monad m => (Term -> m Term) -> Term -> m Term
|
||||||
composOp co trm =
|
composOp co trm =
|
||||||
case trm of
|
case trm of
|
||||||
App c a -> liftM2 App (co c) (co a)
|
App c a -> liftM2 App (co c) (co a)
|
||||||
Abs b x t -> liftM (Abs b x) (co t)
|
Abs b x t -> liftM (Abs b x) (co t)
|
||||||
@@ -552,13 +552,13 @@ strsFromTerm t = case t of
|
|||||||
v0 <- mapM (strsFromTerm . fst) vs
|
v0 <- mapM (strsFromTerm . fst) vs
|
||||||
c0 <- mapM (strsFromTerm . snd) vs
|
c0 <- mapM (strsFromTerm . snd) vs
|
||||||
--let vs' = zip v0 c0
|
--let vs' = zip v0 c0
|
||||||
return [strTok (str2strings def) vars |
|
return [strTok (str2strings def) vars |
|
||||||
def <- d0,
|
def <- d0,
|
||||||
vars <- [[(str2strings v, map sstr c) | (v,c) <- zip vv c0] |
|
vars <- [[(str2strings v, map sstr c) | (v,c) <- zip vv c0] |
|
||||||
vv <- sequence v0]
|
vv <- sequence v0]
|
||||||
]
|
]
|
||||||
FV ts -> mapM strsFromTerm ts >>= return . concat
|
FV ts -> mapM strsFromTerm ts >>= return . concat
|
||||||
Strs ts -> mapM strsFromTerm ts >>= return . concat
|
Strs ts -> mapM strsFromTerm ts >>= return . concat
|
||||||
_ -> raise (render ("cannot get Str from term" <+> ppTerm Unqualified 0 t))
|
_ -> raise (render ("cannot get Str from term" <+> ppTerm Unqualified 0 t))
|
||||||
|
|
||||||
getTableType :: TInfo -> Err Type
|
getTableType :: TInfo -> Err Type
|
||||||
@@ -590,11 +590,11 @@ noExist = FV []
|
|||||||
defaultLinType :: Type
|
defaultLinType :: Type
|
||||||
defaultLinType = mkRecType linLabel [typeStr]
|
defaultLinType = mkRecType linLabel [typeStr]
|
||||||
|
|
||||||
-- | normalize records and record types; put s first
|
-- normalize records and record types; put s first
|
||||||
|
|
||||||
sortRec :: [(Label,a)] -> [(Label,a)]
|
sortRec :: [(Label,a)] -> [(Label,a)]
|
||||||
sortRec = sortBy ordLabel where
|
sortRec = sortBy ordLabel where
|
||||||
ordLabel (r1,_) (r2,_) =
|
ordLabel (r1,_) (r2,_) =
|
||||||
case (showIdent (label2ident r1), showIdent (label2ident r2)) of
|
case (showIdent (label2ident r1), showIdent (label2ident r2)) of
|
||||||
("s",_) -> LT
|
("s",_) -> LT
|
||||||
(_,"s") -> GT
|
(_,"s") -> GT
|
||||||
@@ -605,7 +605,7 @@ sortRec = sortBy ordLabel where
|
|||||||
-- | dependency check, detecting circularities and returning topo-sorted list
|
-- | dependency check, detecting circularities and returning topo-sorted list
|
||||||
|
|
||||||
allDependencies :: (ModuleName -> Bool) -> Map.Map Ident Info -> [(Ident,[Ident])]
|
allDependencies :: (ModuleName -> Bool) -> Map.Map Ident Info -> [(Ident,[Ident])]
|
||||||
allDependencies ism b =
|
allDependencies ism b =
|
||||||
[(f, nub (concatMap opty (pts i))) | (f,i) <- Map.toList b]
|
[(f, nub (concatMap opty (pts i))) | (f,i) <- Map.toList b]
|
||||||
where
|
where
|
||||||
opersIn t = case t of
|
opersIn t = case t of
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import GF.Compile.Update (buildAnyTree)
|
|||||||
import Data.List(intersperse)
|
import Data.List(intersperse)
|
||||||
import Data.Char(isAlphaNum)
|
import Data.Char(isAlphaNum)
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
|
import PGF(mkCId)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -624,7 +625,7 @@ ListCFRule
|
|||||||
|
|
||||||
CFRule :: { [BNFCRule] }
|
CFRule :: { [BNFCRule] }
|
||||||
CFRule
|
CFRule
|
||||||
: Ident '.' Ident '::=' ListCFSymbol ';' { [BNFCRule (showIdent $3) $5 (CFObj (showIdent $1) [])]
|
: Ident '.' Ident '::=' ListCFSymbol ';' { [BNFCRule (showIdent $3) $5 (CFObj (mkCId (showIdent $1)) [])]
|
||||||
}
|
}
|
||||||
| Ident '::=' ListCFRHS ';' { let { cat = showIdent $1;
|
| Ident '::=' ListCFRHS ';' { let { cat = showIdent $1;
|
||||||
mkFun cat its =
|
mkFun cat its =
|
||||||
@@ -637,7 +638,7 @@ CFRule
|
|||||||
Terminal c -> filter isAlphaNum c;
|
Terminal c -> filter isAlphaNum c;
|
||||||
NonTerminal (t,_) -> t
|
NonTerminal (t,_) -> t
|
||||||
}
|
}
|
||||||
} in map (\rhs -> BNFCRule cat rhs (CFObj (mkFun cat rhs) [])) $3
|
} in map (\rhs -> BNFCRule cat rhs (CFObj (mkCId (mkFun cat rhs)) [])) $3
|
||||||
}
|
}
|
||||||
| 'coercions' Ident Integer ';' { [BNFCCoercions (showIdent $2) $3]}
|
| 'coercions' Ident Integer ';' { [BNFCCoercions (showIdent $2) $3]}
|
||||||
| 'terminator' NonEmpty Ident String ';' { [BNFCTerminator $2 (showIdent $3) $4] }
|
| 'terminator' NonEmpty Ident String ';' { [BNFCTerminator $2 (showIdent $3) $4] }
|
||||||
|
|||||||
@@ -5,19 +5,18 @@
|
|||||||
-- Stability : (stable)
|
-- Stability : (stable)
|
||||||
-- Portability : (portable)
|
-- Portability : (portable)
|
||||||
--
|
--
|
||||||
-- > CVS $Date: 2005/10/12 12:38:29 $
|
-- > CVS $Date: 2005/10/12 12:38:29 $
|
||||||
-- > CVS $Author: aarne $
|
-- > CVS $Author: aarne $
|
||||||
-- > CVS $Revision: 1.7 $
|
-- > CVS $Revision: 1.7 $
|
||||||
--
|
--
|
||||||
-- pattern matching for both concrete and abstract syntax. AR -- 16\/6\/2003
|
-- pattern matching for both concrete and abstract syntax. AR -- 16\/6\/2003
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
|
|
||||||
module GF.Grammar.PatternMatch (
|
module GF.Grammar.PatternMatch (matchPattern,
|
||||||
matchPattern,
|
testOvershadow,
|
||||||
testOvershadow,
|
findMatch,
|
||||||
findMatch,
|
measurePatt
|
||||||
measurePatt
|
) where
|
||||||
) where
|
|
||||||
|
|
||||||
import GF.Data.Operations
|
import GF.Data.Operations
|
||||||
import GF.Grammar.Grammar
|
import GF.Grammar.Grammar
|
||||||
@@ -31,7 +30,7 @@ import GF.Text.Pretty
|
|||||||
--import Debug.Trace
|
--import Debug.Trace
|
||||||
|
|
||||||
matchPattern :: ErrorMonad m => [(Patt,rhs)] -> Term -> m (rhs, Substitution)
|
matchPattern :: ErrorMonad m => [(Patt,rhs)] -> Term -> m (rhs, Substitution)
|
||||||
matchPattern pts term =
|
matchPattern pts term =
|
||||||
if not (isInConstantForm term)
|
if not (isInConstantForm term)
|
||||||
then raise (render ("variables occur in" <+> pp term))
|
then raise (render ("variables occur in" <+> pp term))
|
||||||
else do
|
else do
|
||||||
@@ -62,15 +61,15 @@ testOvershadow pts vs = do
|
|||||||
findMatch :: ErrorMonad m => [([Patt],rhs)] -> [Term] -> m (rhs, Substitution)
|
findMatch :: ErrorMonad m => [([Patt],rhs)] -> [Term] -> m (rhs, Substitution)
|
||||||
findMatch cases terms = case cases of
|
findMatch cases terms = case cases of
|
||||||
[] -> raise (render ("no applicable case for" <+> hsep (punctuate ',' terms)))
|
[] -> raise (render ("no applicable case for" <+> hsep (punctuate ',' terms)))
|
||||||
(patts,_):_ | length patts /= length terms ->
|
(patts,_):_ | length patts /= length terms ->
|
||||||
raise (render ("wrong number of args for patterns :" <+> hsep patts <+>
|
raise (render ("wrong number of args for patterns :" <+> hsep patts <+>
|
||||||
"cannot take" <+> hsep terms))
|
"cannot take" <+> hsep terms))
|
||||||
(patts,val):cc -> case mapM tryMatch (zip patts terms) of
|
(patts,val):cc -> case mapM tryMatch (zip patts terms) of
|
||||||
Ok substs -> return (val, concat substs)
|
Ok substs -> return (val, concat substs)
|
||||||
_ -> findMatch cc terms
|
_ -> findMatch cc terms
|
||||||
|
|
||||||
tryMatch :: (Patt, Term) -> Err [(Ident, Term)]
|
tryMatch :: (Patt, Term) -> Err [(Ident, Term)]
|
||||||
tryMatch (p,t) = do
|
tryMatch (p,t) = do
|
||||||
t' <- termForm t
|
t' <- termForm t
|
||||||
trym p t'
|
trym p t'
|
||||||
where
|
where
|
||||||
@@ -84,26 +83,26 @@ tryMatch (p,t) = do
|
|||||||
(PString s, ([],K i,[])) | s==i -> return []
|
(PString s, ([],K i,[])) | s==i -> return []
|
||||||
(PInt s, ([],EInt i,[])) | s==i -> return []
|
(PInt s, ([],EInt i,[])) | s==i -> return []
|
||||||
(PFloat s,([],EFloat i,[])) | s==i -> return [] --- rounding?
|
(PFloat s,([],EFloat i,[])) | s==i -> return [] --- rounding?
|
||||||
(PC p pp, ([], Con f, tt)) |
|
(PC p pp, ([], Con f, tt)) |
|
||||||
p `eqStrIdent` f && length pp == length tt ->
|
p `eqStrIdent` f && length pp == length tt ->
|
||||||
do matches <- mapM tryMatch (zip pp tt)
|
do matches <- mapM tryMatch (zip pp tt)
|
||||||
return (concat matches)
|
return (concat matches)
|
||||||
|
|
||||||
(PP (q,p) pp, ([], QC (r,f), tt)) |
|
(PP (q,p) pp, ([], QC (r,f), tt)) |
|
||||||
-- q `eqStrIdent` r && --- not for inherited AR 10/10/2005
|
-- q `eqStrIdent` r && --- not for inherited AR 10/10/2005
|
||||||
p `eqStrIdent` f && length pp == length tt ->
|
p `eqStrIdent` f && length pp == length tt ->
|
||||||
do matches <- mapM tryMatch (zip pp tt)
|
do matches <- mapM tryMatch (zip pp tt)
|
||||||
return (concat matches)
|
return (concat matches)
|
||||||
---- hack for AppPredef bug
|
---- hack for AppPredef bug
|
||||||
(PP (q,p) pp, ([], Q (r,f), tt)) |
|
(PP (q,p) pp, ([], Q (r,f), tt)) |
|
||||||
-- q `eqStrIdent` r && ---
|
-- q `eqStrIdent` r && ---
|
||||||
p `eqStrIdent` f && length pp == length tt ->
|
p `eqStrIdent` f && length pp == length tt ->
|
||||||
do matches <- mapM tryMatch (zip pp tt)
|
do matches <- mapM tryMatch (zip pp tt)
|
||||||
return (concat matches)
|
return (concat matches)
|
||||||
|
|
||||||
(PR r, ([],R r',[])) |
|
(PR r, ([],R r',[])) |
|
||||||
all (`elem` map fst r') (map fst r) ->
|
all (`elem` map fst r') (map fst r) ->
|
||||||
do matches <- mapM tryMatch
|
do matches <- mapM tryMatch
|
||||||
[(p,snd a) | (l,p) <- r, let Just a = lookup l r']
|
[(p,snd a) | (l,p) <- r, let Just a = lookup l r']
|
||||||
return (concat matches)
|
return (concat matches)
|
||||||
(PT _ p',_) -> trym p' t'
|
(PT _ p',_) -> trym p' t'
|
||||||
@@ -126,7 +125,7 @@ tryMatch (p,t) = do
|
|||||||
(PMSeq mp1 mp2, ([],K s, [])) -> matchPMSeq mp1 mp2 s
|
(PMSeq mp1 mp2, ([],K s, [])) -> matchPMSeq mp1 mp2 s
|
||||||
|
|
||||||
(PRep p1, ([],K s, [])) -> checks [
|
(PRep p1, ([],K s, [])) -> checks [
|
||||||
trym (foldr (const (PSeq p1)) (PString "")
|
trym (foldr (const (PSeq p1)) (PString "")
|
||||||
[1..n]) t' | n <- [0 .. length s]
|
[1..n]) t' | n <- [0 .. length s]
|
||||||
] >>
|
] >>
|
||||||
return []
|
return []
|
||||||
|
|||||||
@@ -1,401 +1,365 @@
|
|||||||
----------------------------------------------------------------------
|
----------------------------------------------------------------------
|
||||||
-- |
|
-- |
|
||||||
-- Module : GF.Grammar.Printer
|
-- Module : GF.Grammar.Printer
|
||||||
-- Maintainer : Krasimir Angelov
|
-- Maintainer : Krasimir Angelov
|
||||||
-- Stability : (stable)
|
-- Stability : (stable)
|
||||||
-- Portability : (portable)
|
-- Portability : (portable)
|
||||||
--
|
--
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
|
|
||||||
{-# LANGUAGE FlexibleContexts #-}
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
module GF.Grammar.Printer
|
module GF.Grammar.Printer
|
||||||
( -- ** Pretty printing
|
( -- ** Pretty printing
|
||||||
TermPrintQual(..)
|
TermPrintQual(..)
|
||||||
, ppModule
|
, ppModule
|
||||||
, ppJudgement
|
, ppJudgement
|
||||||
, ppParams
|
, ppParams
|
||||||
, ppTerm
|
, ppTerm
|
||||||
, ppPatt
|
, ppPatt
|
||||||
, ppValue
|
, ppValue
|
||||||
, ppConstrs
|
, ppConstrs
|
||||||
, ppQIdent
|
, ppQIdent
|
||||||
, ppMeta
|
, ppMeta
|
||||||
, getAbs
|
, getAbs
|
||||||
) where
|
) where
|
||||||
import Prelude hiding ((<>)) -- GHC 8.4.1 clash with Text.PrettyPrint
|
import Prelude hiding ((<>)) -- GHC 8.4.1 clash with Text.PrettyPrint
|
||||||
|
|
||||||
import PGF2 as PGF2
|
import GF.Infra.Ident
|
||||||
import PGF2.Internal as PGF2
|
import GF.Infra.Option
|
||||||
import GF.Infra.Ident
|
import GF.Grammar.Values
|
||||||
import GF.Infra.Option
|
import GF.Grammar.Grammar
|
||||||
import GF.Grammar.Values
|
|
||||||
import GF.Grammar.Grammar
|
import PGF.Internal (ppMeta, ppLit, ppFId, ppFunId, ppSeqId, ppSeq)
|
||||||
|
|
||||||
import GF.Text.Pretty
|
import GF.Text.Pretty
|
||||||
import Data.Maybe (isNothing)
|
import Data.Maybe (isNothing)
|
||||||
import Data.List (intersperse)
|
import Data.List (intersperse)
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
--import qualified Data.IntMap as IntMap
|
--import qualified Data.IntMap as IntMap
|
||||||
--import qualified Data.Set as Set
|
--import qualified Data.Set as Set
|
||||||
import qualified Data.Array.IArray as Array
|
import qualified Data.Array.IArray as Array
|
||||||
|
|
||||||
data TermPrintQual
|
data TermPrintQual
|
||||||
= Terse | Unqualified | Qualified | Internal
|
= Terse | Unqualified | Qualified | Internal
|
||||||
deriving Eq
|
deriving Eq
|
||||||
|
|
||||||
instance Pretty Grammar where
|
instance Pretty Grammar where
|
||||||
pp = vcat . map (ppModule Qualified) . modules
|
pp = vcat . map (ppModule Qualified) . modules
|
||||||
|
|
||||||
ppModule :: TermPrintQual -> SourceModule -> Doc
|
ppModule :: TermPrintQual -> SourceModule -> Doc
|
||||||
ppModule q (mn, ModInfo mtype mstat opts exts with opens _ _ mseqs jments) =
|
ppModule q (mn, ModInfo mtype mstat opts exts with opens _ _ mseqs jments) =
|
||||||
hdr $$
|
hdr $$
|
||||||
nest 2 (ppOptions opts $$
|
nest 2 (ppOptions opts $$
|
||||||
vcat (map (ppJudgement q) (Map.toList jments)) $$
|
vcat (map (ppJudgement q) (Map.toList jments)) $$
|
||||||
maybe empty (ppSequences q) mseqs) $$
|
maybe empty (ppSequences q) mseqs) $$
|
||||||
ftr
|
ftr
|
||||||
where
|
where
|
||||||
hdr = complModDoc <+> modTypeDoc <+> '=' <+>
|
hdr = complModDoc <+> modTypeDoc <+> '=' <+>
|
||||||
hsep (intersperse (pp "**") $
|
hsep (intersperse (pp "**") $
|
||||||
filter (not . isEmpty) $ [ commaPunct ppExtends exts
|
filter (not . isEmpty) $ [ commaPunct ppExtends exts
|
||||||
, maybe empty ppWith with
|
, maybe empty ppWith with
|
||||||
, if null opens
|
, if null opens
|
||||||
then pp '{'
|
then pp '{'
|
||||||
else "open" <+> commaPunct ppOpenSpec opens <+> "in" <+> '{'
|
else "open" <+> commaPunct ppOpenSpec opens <+> "in" <+> '{'
|
||||||
])
|
])
|
||||||
|
|
||||||
ftr = '}'
|
ftr = '}'
|
||||||
|
|
||||||
complModDoc =
|
complModDoc =
|
||||||
case mstat of
|
case mstat of
|
||||||
MSComplete -> empty
|
MSComplete -> empty
|
||||||
MSIncomplete -> pp "incomplete"
|
MSIncomplete -> pp "incomplete"
|
||||||
|
|
||||||
modTypeDoc =
|
modTypeDoc =
|
||||||
case mtype of
|
case mtype of
|
||||||
MTAbstract -> "abstract" <+> mn
|
MTAbstract -> "abstract" <+> mn
|
||||||
MTResource -> "resource" <+> mn
|
MTResource -> "resource" <+> mn
|
||||||
MTConcrete abs -> "concrete" <+> mn <+> "of" <+> abs
|
MTConcrete abs -> "concrete" <+> mn <+> "of" <+> abs
|
||||||
MTInterface -> "interface" <+> mn
|
MTInterface -> "interface" <+> mn
|
||||||
MTInstance ie -> "instance" <+> mn <+> "of" <+> ppExtends ie
|
MTInstance ie -> "instance" <+> mn <+> "of" <+> ppExtends ie
|
||||||
|
|
||||||
ppExtends (id,MIAll ) = pp id
|
ppExtends (id,MIAll ) = pp id
|
||||||
ppExtends (id,MIOnly incs) = id <+> brackets (commaPunct pp incs)
|
ppExtends (id,MIOnly incs) = id <+> brackets (commaPunct pp incs)
|
||||||
ppExtends (id,MIExcept incs) = id <+> '-' <+> brackets (commaPunct pp incs)
|
ppExtends (id,MIExcept incs) = id <+> '-' <+> brackets (commaPunct pp incs)
|
||||||
|
|
||||||
ppWith (id,ext,opens) = ppExtends (id,ext) <+> "with" <+> commaPunct ppInstSpec opens
|
ppWith (id,ext,opens) = ppExtends (id,ext) <+> "with" <+> commaPunct ppInstSpec opens
|
||||||
|
|
||||||
ppOptions opts =
|
ppOptions opts =
|
||||||
"flags" $$
|
"flags" $$
|
||||||
nest 2 (vcat [option <+> '=' <+> ppLit value <+> ';' | (option,value) <- optionsGFO opts])
|
nest 2 (vcat [option <+> '=' <+> ppLit value <+> ';' | (option,value) <- optionsGFO opts])
|
||||||
|
|
||||||
ppJudgement q (id, AbsCat pcont ) =
|
ppJudgement q (id, AbsCat pcont ) =
|
||||||
"cat" <+> id <+>
|
"cat" <+> id <+>
|
||||||
(case pcont of
|
(case pcont of
|
||||||
Just (L _ cont) -> hsep (map (ppDecl q) cont)
|
Just (L _ cont) -> hsep (map (ppDecl q) cont)
|
||||||
Nothing -> empty) <+> ';'
|
Nothing -> empty) <+> ';'
|
||||||
ppJudgement q (id, AbsFun ptype _ pexp poper) =
|
ppJudgement q (id, AbsFun ptype _ pexp poper) =
|
||||||
let kind | isNothing pexp = "data"
|
let kind | isNothing pexp = "data"
|
||||||
| poper == Just False = "oper"
|
| poper == Just False = "oper"
|
||||||
| otherwise = "fun"
|
| otherwise = "fun"
|
||||||
in
|
in
|
||||||
(case ptype of
|
(case ptype of
|
||||||
Just (L _ typ) -> kind <+> id <+> ':' <+> ppTerm q 0 typ <+> ';'
|
Just (L _ typ) -> kind <+> id <+> ':' <+> ppTerm q 0 typ <+> ';'
|
||||||
Nothing -> empty) $$
|
Nothing -> empty) $$
|
||||||
(case pexp of
|
(case pexp of
|
||||||
Just [] -> empty
|
Just [] -> empty
|
||||||
Just eqs -> "def" <+> vcat [id <+> hsep (map (ppPatt q 2) ps) <+> '=' <+> ppTerm q 0 e <+> ';' | L _ (ps,e) <- eqs]
|
Just eqs -> "def" <+> vcat [id <+> hsep (map (ppPatt q 2) ps) <+> '=' <+> ppTerm q 0 e <+> ';' | L _ (ps,e) <- eqs]
|
||||||
Nothing -> empty)
|
Nothing -> empty)
|
||||||
ppJudgement q (id, ResParam pparams _) =
|
ppJudgement q (id, ResParam pparams _) =
|
||||||
"param" <+> id <+>
|
"param" <+> id <+>
|
||||||
(case pparams of
|
(case pparams of
|
||||||
Just (L _ ps) -> '=' <+> ppParams q ps
|
Just (L _ ps) -> '=' <+> ppParams q ps
|
||||||
_ -> empty) <+> ';'
|
_ -> empty) <+> ';'
|
||||||
ppJudgement q (id, ResValue pvalue) =
|
ppJudgement q (id, ResValue pvalue) =
|
||||||
"-- param constructor" <+> id <+> ':' <+>
|
"-- param constructor" <+> id <+> ':' <+>
|
||||||
(case pvalue of
|
(case pvalue of
|
||||||
(L _ ty) -> ppTerm q 0 ty) <+> ';'
|
(L _ ty) -> ppTerm q 0 ty) <+> ';'
|
||||||
ppJudgement q (id, ResOper ptype pexp) =
|
ppJudgement q (id, ResOper ptype pexp) =
|
||||||
"oper" <+> id <+>
|
"oper" <+> id <+>
|
||||||
(case ptype of {Just (L _ t) -> ':' <+> ppTerm q 0 t; Nothing -> empty} $$
|
(case ptype of {Just (L _ t) -> ':' <+> ppTerm q 0 t; Nothing -> empty} $$
|
||||||
case pexp of {Just (L _ e) -> '=' <+> ppTerm q 0 e; Nothing -> empty}) <+> ';'
|
case pexp of {Just (L _ e) -> '=' <+> ppTerm q 0 e; Nothing -> empty}) <+> ';'
|
||||||
ppJudgement q (id, ResOverload ids defs) =
|
ppJudgement q (id, ResOverload ids defs) =
|
||||||
"oper" <+> id <+> '=' <+>
|
"oper" <+> id <+> '=' <+>
|
||||||
("overload" <+> '{' $$
|
("overload" <+> '{' $$
|
||||||
nest 2 (vcat [id <+> (':' <+> ppTerm q 0 ty $$ '=' <+> ppTerm q 0 e <+> ';') | (L _ ty,L _ e) <- defs]) $$
|
nest 2 (vcat [id <+> (':' <+> ppTerm q 0 ty $$ '=' <+> ppTerm q 0 e <+> ';') | (L _ ty,L _ e) <- defs]) $$
|
||||||
'}') <+> ';'
|
'}') <+> ';'
|
||||||
ppJudgement q (id, CncCat pcat pdef pref pprn mpmcfg) =
|
ppJudgement q (id, CncCat pcat pdef pref pprn mpmcfg) =
|
||||||
(case pcat of
|
(case pcat of
|
||||||
Just (L _ typ) -> "lincat" <+> id <+> '=' <+> ppTerm q 0 typ <+> ';'
|
Just (L _ typ) -> "lincat" <+> id <+> '=' <+> ppTerm q 0 typ <+> ';'
|
||||||
Nothing -> empty) $$
|
Nothing -> empty) $$
|
||||||
(case pdef of
|
(case pdef of
|
||||||
Just (L _ exp) -> "lindef" <+> id <+> '=' <+> ppTerm q 0 exp <+> ';'
|
Just (L _ exp) -> "lindef" <+> id <+> '=' <+> ppTerm q 0 exp <+> ';'
|
||||||
Nothing -> empty) $$
|
Nothing -> empty) $$
|
||||||
(case pref of
|
(case pref of
|
||||||
Just (L _ exp) -> "linref" <+> id <+> '=' <+> ppTerm q 0 exp <+> ';'
|
Just (L _ exp) -> "linref" <+> id <+> '=' <+> ppTerm q 0 exp <+> ';'
|
||||||
Nothing -> empty) $$
|
Nothing -> empty) $$
|
||||||
(case pprn of
|
(case pprn of
|
||||||
Just (L _ prn) -> "printname" <+> id <+> '=' <+> ppTerm q 0 prn <+> ';'
|
Just (L _ prn) -> "printname" <+> id <+> '=' <+> ppTerm q 0 prn <+> ';'
|
||||||
Nothing -> empty) $$
|
Nothing -> empty) $$
|
||||||
(case (mpmcfg,q) of
|
(case (mpmcfg,q) of
|
||||||
(Just (PMCFG prods funs),Internal)
|
(Just (PMCFG prods funs),Internal)
|
||||||
-> "pmcfg" <+> id <+> '=' <+> '{' $$
|
-> "pmcfg" <+> id <+> '=' <+> '{' $$
|
||||||
nest 2 (vcat (map ppProduction prods) $$
|
nest 2 (vcat (map ppProduction prods) $$
|
||||||
' ' $$
|
' ' $$
|
||||||
vcat (map (\(funid,arr) -> ppFunId funid <+> ":=" <+>
|
vcat (map (\(funid,arr) -> ppFunId funid <+> ":=" <+>
|
||||||
parens (hcat (punctuate ',' (map ppSeqId (Array.elems arr)))))
|
parens (hcat (punctuate ',' (map ppSeqId (Array.elems arr)))))
|
||||||
(Array.assocs funs))) $$
|
(Array.assocs funs))) $$
|
||||||
'}'
|
'}'
|
||||||
_ -> empty)
|
_ -> empty)
|
||||||
ppJudgement q (id, CncFun ptype pdef pprn mpmcfg) =
|
ppJudgement q (id, CncFun ptype pdef pprn mpmcfg) =
|
||||||
(case pdef of
|
(case pdef of
|
||||||
Just (L _ e) -> let (xs,e') = getAbs e
|
Just (L _ e) -> let (xs,e') = getAbs e
|
||||||
in "lin" <+> id <+> hsep (map ppBind xs) <+> '=' <+> ppTerm q 0 e' <+> ';'
|
in "lin" <+> id <+> hsep (map ppBind xs) <+> '=' <+> ppTerm q 0 e' <+> ';'
|
||||||
Nothing -> empty) $$
|
Nothing -> empty) $$
|
||||||
(case pprn of
|
(case pprn of
|
||||||
Just (L _ prn) -> "printname" <+> id <+> '=' <+> ppTerm q 0 prn <+> ';'
|
Just (L _ prn) -> "printname" <+> id <+> '=' <+> ppTerm q 0 prn <+> ';'
|
||||||
Nothing -> empty) $$
|
Nothing -> empty) $$
|
||||||
(case (mpmcfg,q) of
|
(case (mpmcfg,q) of
|
||||||
(Just (PMCFG prods funs),Internal)
|
(Just (PMCFG prods funs),Internal)
|
||||||
-> "pmcfg" <+> id <+> '=' <+> '{' $$
|
-> "pmcfg" <+> id <+> '=' <+> '{' $$
|
||||||
nest 2 (vcat (map ppProduction prods) $$
|
nest 2 (vcat (map ppProduction prods) $$
|
||||||
' ' $$
|
' ' $$
|
||||||
vcat (map (\(funid,arr) -> ppFunId funid <+> ":=" <+>
|
vcat (map (\(funid,arr) -> ppFunId funid <+> ":=" <+>
|
||||||
parens (hcat (punctuate ',' (map ppSeqId (Array.elems arr)))))
|
parens (hcat (punctuate ',' (map ppSeqId (Array.elems arr)))))
|
||||||
(Array.assocs funs))) $$
|
(Array.assocs funs))) $$
|
||||||
'}'
|
'}'
|
||||||
_ -> empty)
|
_ -> empty)
|
||||||
ppJudgement q (id, AnyInd cann mid) =
|
ppJudgement q (id, AnyInd cann mid) =
|
||||||
case q of
|
case q of
|
||||||
Internal -> "ind" <+> id <+> '=' <+> (if cann then pp "canonical" else empty) <+> mid <+> ';'
|
Internal -> "ind" <+> id <+> '=' <+> (if cann then pp "canonical" else empty) <+> mid <+> ';'
|
||||||
_ -> empty
|
_ -> empty
|
||||||
|
|
||||||
instance Pretty Term where pp = ppTerm Unqualified 0
|
instance Pretty Term where pp = ppTerm Unqualified 0
|
||||||
|
|
||||||
ppTerm q d (Abs b v e) = let (xs,e') = getAbs (Abs b v e)
|
ppTerm q d (Abs b v e) = let (xs,e') = getAbs (Abs b v e)
|
||||||
in prec d 0 ('\\' <> commaPunct ppBind xs <+> "->" <+> ppTerm q 0 e')
|
in prec d 0 ('\\' <> commaPunct ppBind xs <+> "->" <+> ppTerm q 0 e')
|
||||||
ppTerm q d (T TRaw xs) = case getCTable (T TRaw xs) of
|
ppTerm q d (T TRaw xs) = case getCTable (T TRaw xs) of
|
||||||
([],_) -> "table" <+> '{' $$
|
([],_) -> "table" <+> '{' $$
|
||||||
nest 2 (vcat (punctuate ';' (map (ppCase q) xs))) $$
|
nest 2 (vcat (punctuate ';' (map (ppCase q) xs))) $$
|
||||||
'}'
|
'}'
|
||||||
(vs,e) -> prec d 0 ("\\\\" <> commaPunct pp vs <+> "=>" <+> ppTerm q 0 e)
|
(vs,e) -> prec d 0 ("\\\\" <> commaPunct pp vs <+> "=>" <+> ppTerm q 0 e)
|
||||||
ppTerm q d (T (TTyped t) xs) = "table" <+> ppTerm q 0 t <+> '{' $$
|
ppTerm q d (T (TTyped t) xs) = "table" <+> ppTerm q 0 t <+> '{' $$
|
||||||
nest 2 (vcat (punctuate ';' (map (ppCase q) xs))) $$
|
nest 2 (vcat (punctuate ';' (map (ppCase q) xs))) $$
|
||||||
'}'
|
'}'
|
||||||
ppTerm q d (T (TComp t) xs) = "table" <+> ppTerm q 0 t <+> '{' $$
|
ppTerm q d (T (TComp t) xs) = "table" <+> ppTerm q 0 t <+> '{' $$
|
||||||
nest 2 (vcat (punctuate ';' (map (ppCase q) xs))) $$
|
nest 2 (vcat (punctuate ';' (map (ppCase q) xs))) $$
|
||||||
'}'
|
'}'
|
||||||
ppTerm q d (T (TWild t) xs) = "table" <+> ppTerm q 0 t <+> '{' $$
|
ppTerm q d (T (TWild t) xs) = "table" <+> ppTerm q 0 t <+> '{' $$
|
||||||
nest 2 (vcat (punctuate ';' (map (ppCase q) xs))) $$
|
nest 2 (vcat (punctuate ';' (map (ppCase q) xs))) $$
|
||||||
'}'
|
'}'
|
||||||
ppTerm q d (Prod bt x a b)= if x == identW && bt == Explicit
|
ppTerm q d (Prod bt x a b)= if x == identW && bt == Explicit
|
||||||
then prec d 0 (ppTerm q 4 a <+> "->" <+> ppTerm q 0 b)
|
then prec d 0 (ppTerm q 4 a <+> "->" <+> ppTerm q 0 b)
|
||||||
else prec d 0 (parens (ppBind (bt,x) <+> ':' <+> ppTerm q 0 a) <+> "->" <+> ppTerm q 0 b)
|
else prec d 0 (parens (ppBind (bt,x) <+> ':' <+> ppTerm q 0 a) <+> "->" <+> ppTerm q 0 b)
|
||||||
ppTerm q d (Table kt vt)=prec d 0 (ppTerm q 3 kt <+> "=>" <+> ppTerm q 0 vt)
|
ppTerm q d (Table kt vt)=prec d 0 (ppTerm q 3 kt <+> "=>" <+> ppTerm q 0 vt)
|
||||||
ppTerm q d (Let l e) = let (ls,e') = getLet e
|
ppTerm q d (Let l e) = let (ls,e') = getLet e
|
||||||
in prec d 0 ("let" <+> vcat (map (ppLocDef q) (l:ls)) $$ "in" <+> ppTerm q 0 e')
|
in prec d 0 ("let" <+> vcat (map (ppLocDef q) (l:ls)) $$ "in" <+> ppTerm q 0 e')
|
||||||
ppTerm q d (Example e s)=prec d 0 ("in" <+> ppTerm q 5 e <+> str s)
|
ppTerm q d (Example e s)=prec d 0 ("in" <+> ppTerm q 5 e <+> str s)
|
||||||
ppTerm q d (C e1 e2) =prec d 1 (hang (ppTerm q 2 e1) 2 ("++" <+> ppTerm q 1 e2))
|
ppTerm q d (C e1 e2) =prec d 1 (hang (ppTerm q 2 e1) 2 ("++" <+> ppTerm q 1 e2))
|
||||||
ppTerm q d (Glue e1 e2) =prec d 2 (ppTerm q 3 e1 <+> '+' <+> ppTerm q 2 e2)
|
ppTerm q d (Glue e1 e2) =prec d 2 (ppTerm q 3 e1 <+> '+' <+> ppTerm q 2 e2)
|
||||||
ppTerm q d (S x y) = case x of
|
ppTerm q d (S x y) = case x of
|
||||||
T annot xs -> let e = case annot of
|
T annot xs -> let e = case annot of
|
||||||
TRaw -> y
|
TRaw -> y
|
||||||
TTyped t -> Typed y t
|
TTyped t -> Typed y t
|
||||||
TComp t -> Typed y t
|
TComp t -> Typed y t
|
||||||
TWild t -> Typed y t
|
TWild t -> Typed y t
|
||||||
in "case" <+> ppTerm q 0 e <+>"of" <+> '{' $$
|
in "case" <+> ppTerm q 0 e <+>"of" <+> '{' $$
|
||||||
nest 2 (vcat (punctuate ';' (map (ppCase q) xs))) $$
|
nest 2 (vcat (punctuate ';' (map (ppCase q) xs))) $$
|
||||||
'}'
|
'}'
|
||||||
_ -> prec d 3 (hang (ppTerm q 3 x) 2 ("!" <+> ppTerm q 4 y))
|
_ -> prec d 3 (hang (ppTerm q 3 x) 2 ("!" <+> ppTerm q 4 y))
|
||||||
ppTerm q d (ExtR x y) = prec d 3 (ppTerm q 3 x <+> "**" <+> ppTerm q 4 y)
|
ppTerm q d (ExtR x y) = prec d 3 (ppTerm q 3 x <+> "**" <+> ppTerm q 4 y)
|
||||||
ppTerm q d (App x y) = prec d 4 (ppTerm q 4 x <+> ppTerm q 5 y)
|
ppTerm q d (App x y) = prec d 4 (ppTerm q 4 x <+> ppTerm q 5 y)
|
||||||
ppTerm q d (V e es) = hang "table" 2 (sep [ppTerm q 6 e,brackets (fsep (punctuate ';' (map (ppTerm q 0) es)))])
|
ppTerm q d (V e es) = hang "table" 2 (sep [ppTerm q 6 e,brackets (fsep (punctuate ';' (map (ppTerm q 0) es)))])
|
||||||
ppTerm q d (FV es) = prec d 4 ("variants" <+> braces (fsep (punctuate ';' (map (ppTerm q 0) es))))
|
ppTerm q d (FV es) = prec d 4 ("variants" <+> braces (fsep (punctuate ';' (map (ppTerm q 0) es))))
|
||||||
ppTerm q d (AdHocOverload es) = "overload" <+> braces (fsep (punctuate ';' (map (ppTerm q 0) es)))
|
ppTerm q d (AdHocOverload es) = "overload" <+> braces (fsep (punctuate ';' (map (ppTerm q 0) es)))
|
||||||
ppTerm q d (Alts e xs) = prec d 4 ("pre" <+> braces (ppTerm q 0 e <> ';' <+> fsep (punctuate ';' (map (ppAltern q) xs))))
|
ppTerm q d (Alts e xs) = prec d 4 ("pre" <+> braces (ppTerm q 0 e <> ';' <+> fsep (punctuate ';' (map (ppAltern q) xs))))
|
||||||
ppTerm q d (Strs es) = "strs" <+> braces (fsep (punctuate ';' (map (ppTerm q 0) es)))
|
ppTerm q d (Strs es) = "strs" <+> braces (fsep (punctuate ';' (map (ppTerm q 0) es)))
|
||||||
ppTerm q d (EPatt p) = prec d 4 ('#' <+> ppPatt q 2 p)
|
ppTerm q d (EPatt p) = prec d 4 ('#' <+> ppPatt q 2 p)
|
||||||
ppTerm q d (EPattType t)=prec d 4 ("pattern" <+> ppTerm q 0 t)
|
ppTerm q d (EPattType t)=prec d 4 ("pattern" <+> ppTerm q 0 t)
|
||||||
ppTerm q d (P t l) = prec d 5 (ppTerm q 5 t <> '.' <> l)
|
ppTerm q d (P t l) = prec d 5 (ppTerm q 5 t <> '.' <> l)
|
||||||
ppTerm q d (Cn id) = pp id
|
ppTerm q d (Cn id) = pp id
|
||||||
ppTerm q d (Vr id) = pp id
|
ppTerm q d (Vr id) = pp id
|
||||||
ppTerm q d (Q id) = ppQIdent q id
|
ppTerm q d (Q id) = ppQIdent q id
|
||||||
ppTerm q d (QC id) = ppQIdent q id
|
ppTerm q d (QC id) = ppQIdent q id
|
||||||
ppTerm q d (Sort id) = pp id
|
ppTerm q d (Sort id) = pp id
|
||||||
ppTerm q d (K s) = str s
|
ppTerm q d (K s) = str s
|
||||||
ppTerm q d (EInt n) = pp n
|
ppTerm q d (EInt n) = pp n
|
||||||
ppTerm q d (EFloat f) = pp f
|
ppTerm q d (EFloat f) = pp f
|
||||||
ppTerm q d (Meta i) = ppMeta i
|
ppTerm q d (Meta i) = ppMeta i
|
||||||
ppTerm q d (Empty) = pp "[]"
|
ppTerm q d (Empty) = pp "[]"
|
||||||
ppTerm q d (R []) = pp "<>" -- to distinguish from {} empty RecType
|
ppTerm q d (R []) = pp "<>" -- to distinguish from {} empty RecType
|
||||||
ppTerm q d (R xs) = braces (fsep (punctuate ';' [l <+>
|
ppTerm q d (R xs) = braces (fsep (punctuate ';' [l <+>
|
||||||
fsep [case mb_t of {Just t -> ':' <+> ppTerm q 0 t; Nothing -> empty},
|
fsep [case mb_t of {Just t -> ':' <+> ppTerm q 0 t; Nothing -> empty},
|
||||||
'=' <+> ppTerm q 0 e] | (l,(mb_t,e)) <- xs]))
|
'=' <+> ppTerm q 0 e] | (l,(mb_t,e)) <- xs]))
|
||||||
ppTerm q d (RecType xs)
|
ppTerm q d (RecType xs)
|
||||||
| q == Terse = case [cat | (l,_) <- xs, let (p,cat) = splitAt 5 (showIdent (label2ident l)), p == "lock_"] of
|
| q == Terse = case [cat | (l,_) <- xs, let (p,cat) = splitAt 5 (showIdent (label2ident l)), p == "lock_"] of
|
||||||
[cat] -> pp cat
|
[cat] -> pp cat
|
||||||
_ -> doc
|
_ -> doc
|
||||||
| otherwise = doc
|
| otherwise = doc
|
||||||
where
|
where
|
||||||
doc = braces (fsep (punctuate ';' [l <+> ':' <+> ppTerm q 0 t | (l,t) <- xs]))
|
doc = braces (fsep (punctuate ';' [l <+> ':' <+> ppTerm q 0 t | (l,t) <- xs]))
|
||||||
ppTerm q d (Typed e t) = '<' <> ppTerm q 0 e <+> ':' <+> ppTerm q 0 t <> '>'
|
ppTerm q d (Typed e t) = '<' <> ppTerm q 0 e <+> ':' <+> ppTerm q 0 t <> '>'
|
||||||
ppTerm q d (ImplArg e) = braces (ppTerm q 0 e)
|
ppTerm q d (ImplArg e) = braces (ppTerm q 0 e)
|
||||||
ppTerm q d (ELincat cat t) = prec d 4 ("lincat" <+> cat <+> ppTerm q 5 t)
|
ppTerm q d (ELincat cat t) = prec d 4 ("lincat" <+> cat <+> ppTerm q 5 t)
|
||||||
ppTerm q d (ELin cat t) = prec d 4 ("lin" <+> cat <+> ppTerm q 5 t)
|
ppTerm q d (ELin cat t) = prec d 4 ("lin" <+> cat <+> ppTerm q 5 t)
|
||||||
ppTerm q d (Error s) = prec d 4 ("Predef.error" <+> str s)
|
ppTerm q d (Error s) = prec d 4 ("Predef.error" <+> str s)
|
||||||
|
|
||||||
ppEquation q (ps,e) = hcat (map (ppPatt q 2) ps) <+> "->" <+> ppTerm q 0 e
|
ppEquation q (ps,e) = hcat (map (ppPatt q 2) ps) <+> "->" <+> ppTerm q 0 e
|
||||||
|
|
||||||
ppCase q (p,e) = ppPatt q 0 p <+> "=>" <+> ppTerm q 0 e
|
ppCase q (p,e) = ppPatt q 0 p <+> "=>" <+> ppTerm q 0 e
|
||||||
|
|
||||||
instance Pretty Patt where pp = ppPatt Unqualified 0
|
instance Pretty Patt where pp = ppPatt Unqualified 0
|
||||||
|
|
||||||
ppPatt q d (PAlt p1 p2) = prec d 0 (ppPatt q 0 p1 <+> '|' <+> ppPatt q 1 p2)
|
ppPatt q d (PAlt p1 p2) = prec d 0 (ppPatt q 0 p1 <+> '|' <+> ppPatt q 1 p2)
|
||||||
ppPatt q d (PSeq p1 p2) = prec d 0 (ppPatt q 0 p1 <+> '+' <+> ppPatt q 1 p2)
|
ppPatt q d (PSeq p1 p2) = prec d 0 (ppPatt q 0 p1 <+> '+' <+> ppPatt q 1 p2)
|
||||||
ppPatt q d (PMSeq (_,p1) (_,p2)) = prec d 0 (ppPatt q 0 p1 <+> '+' <+> ppPatt q 1 p2)
|
ppPatt q d (PMSeq (_,p1) (_,p2)) = prec d 0 (ppPatt q 0 p1 <+> '+' <+> ppPatt q 1 p2)
|
||||||
ppPatt q d (PC f ps) = if null ps
|
ppPatt q d (PC f ps) = if null ps
|
||||||
then pp f
|
then pp f
|
||||||
else prec d 1 (f <+> hsep (map (ppPatt q 3) ps))
|
else prec d 1 (f <+> hsep (map (ppPatt q 3) ps))
|
||||||
ppPatt q d (PP f ps) = if null ps
|
ppPatt q d (PP f ps) = if null ps
|
||||||
then ppQIdent q f
|
then ppQIdent q f
|
||||||
else prec d 1 (ppQIdent q f <+> hsep (map (ppPatt q 3) ps))
|
else prec d 1 (ppQIdent q f <+> hsep (map (ppPatt q 3) ps))
|
||||||
ppPatt q d (PRep p) = prec d 1 (ppPatt q 3 p <> '*')
|
ppPatt q d (PRep p) = prec d 1 (ppPatt q 3 p <> '*')
|
||||||
ppPatt q d (PAs f p) = prec d 2 (f <> '@' <> ppPatt q 3 p)
|
ppPatt q d (PAs f p) = prec d 2 (f <> '@' <> ppPatt q 3 p)
|
||||||
ppPatt q d (PNeg p) = prec d 2 ('-' <> ppPatt q 3 p)
|
ppPatt q d (PNeg p) = prec d 2 ('-' <> ppPatt q 3 p)
|
||||||
ppPatt q d (PChar) = pp '?'
|
ppPatt q d (PChar) = pp '?'
|
||||||
ppPatt q d (PChars s) = brackets (str s)
|
ppPatt q d (PChars s) = brackets (str s)
|
||||||
ppPatt q d (PMacro id) = '#' <> id
|
ppPatt q d (PMacro id) = '#' <> id
|
||||||
ppPatt q d (PM id) = '#' <> ppQIdent q id
|
ppPatt q d (PM id) = '#' <> ppQIdent q id
|
||||||
ppPatt q d PW = pp '_'
|
ppPatt q d PW = pp '_'
|
||||||
ppPatt q d (PV id) = pp id
|
ppPatt q d (PV id) = pp id
|
||||||
ppPatt q d (PInt n) = pp n
|
ppPatt q d (PInt n) = pp n
|
||||||
ppPatt q d (PFloat f) = pp f
|
ppPatt q d (PFloat f) = pp f
|
||||||
ppPatt q d (PString s) = str s
|
ppPatt q d (PString s) = str s
|
||||||
ppPatt q d (PR xs) = braces (hsep (punctuate ';' [l <+> '=' <+> ppPatt q 0 e | (l,e) <- xs]))
|
ppPatt q d (PR xs) = braces (hsep (punctuate ';' [l <+> '=' <+> ppPatt q 0 e | (l,e) <- xs]))
|
||||||
ppPatt q d (PImplArg p) = braces (ppPatt q 0 p)
|
ppPatt q d (PImplArg p) = braces (ppPatt q 0 p)
|
||||||
ppPatt q d (PTilde t) = prec d 2 ('~' <> ppTerm q 6 t)
|
ppPatt q d (PTilde t) = prec d 2 ('~' <> ppTerm q 6 t)
|
||||||
|
|
||||||
ppValue :: TermPrintQual -> Int -> Val -> Doc
|
ppValue :: TermPrintQual -> Int -> Val -> Doc
|
||||||
ppValue q d (VGen i x) = x <> "{-" <> i <> "-}" ---- latter part for debugging
|
ppValue q d (VGen i x) = x <> "{-" <> i <> "-}" ---- latter part for debugging
|
||||||
ppValue q d (VApp u v) = prec d 4 (ppValue q 4 u <+> ppValue q 5 v)
|
ppValue q d (VApp u v) = prec d 4 (ppValue q 4 u <+> ppValue q 5 v)
|
||||||
ppValue q d (VCn (_,c)) = pp c
|
ppValue q d (VCn (_,c)) = pp c
|
||||||
ppValue q d (VClos env e) = case e of
|
ppValue q d (VClos env e) = case e of
|
||||||
Meta _ -> ppTerm q d e <> ppEnv env
|
Meta _ -> ppTerm q d e <> ppEnv env
|
||||||
_ -> ppTerm q d e ---- ++ prEnv env ---- for debugging
|
_ -> ppTerm q d e ---- ++ prEnv env ---- for debugging
|
||||||
ppValue q d (VRecType xs) = braces (hsep (punctuate ',' [l <> '=' <> ppValue q 0 v | (l,v) <- xs]))
|
ppValue q d (VRecType xs) = braces (hsep (punctuate ',' [l <> '=' <> ppValue q 0 v | (l,v) <- xs]))
|
||||||
ppValue q d VType = pp "Type"
|
ppValue q d VType = pp "Type"
|
||||||
|
|
||||||
ppConstrs :: Constraints -> [Doc]
|
ppConstrs :: Constraints -> [Doc]
|
||||||
ppConstrs = map (\(v,w) -> braces (ppValue Unqualified 0 v <+> "<>" <+> ppValue Unqualified 0 w))
|
ppConstrs = map (\(v,w) -> braces (ppValue Unqualified 0 v <+> "<>" <+> ppValue Unqualified 0 w))
|
||||||
|
|
||||||
ppEnv :: Env -> Doc
|
ppEnv :: Env -> Doc
|
||||||
ppEnv e = hcat (map (\(x,t) -> braces (x <> ":=" <> ppValue Unqualified 0 t)) e)
|
ppEnv e = hcat (map (\(x,t) -> braces (x <> ":=" <> ppValue Unqualified 0 t)) e)
|
||||||
|
|
||||||
str s = doubleQuotes s
|
str s = doubleQuotes s
|
||||||
|
|
||||||
ppDecl q (_,id,typ)
|
ppDecl q (_,id,typ)
|
||||||
| id == identW = ppTerm q 3 typ
|
| id == identW = ppTerm q 3 typ
|
||||||
| otherwise = parens (id <+> ':' <+> ppTerm q 0 typ)
|
| otherwise = parens (id <+> ':' <+> ppTerm q 0 typ)
|
||||||
|
|
||||||
ppDDecl q (_,id,typ)
|
ppDDecl q (_,id,typ)
|
||||||
| id == identW = ppTerm q 6 typ
|
| id == identW = ppTerm q 6 typ
|
||||||
| otherwise = parens (id <+> ':' <+> ppTerm q 0 typ)
|
| otherwise = parens (id <+> ':' <+> ppTerm q 0 typ)
|
||||||
|
|
||||||
ppQIdent :: TermPrintQual -> QIdent -> Doc
|
ppQIdent :: TermPrintQual -> QIdent -> Doc
|
||||||
ppQIdent q (m,id) =
|
ppQIdent q (m,id) =
|
||||||
case q of
|
case q of
|
||||||
Terse -> pp id
|
Terse -> pp id
|
||||||
Unqualified -> pp id
|
Unqualified -> pp id
|
||||||
Qualified -> m <> '.' <> id
|
Qualified -> m <> '.' <> id
|
||||||
Internal -> m <> '.' <> id
|
Internal -> m <> '.' <> id
|
||||||
|
|
||||||
|
|
||||||
instance Pretty Label where pp = pp . label2ident
|
instance Pretty Label where pp = pp . label2ident
|
||||||
|
|
||||||
ppOpenSpec (OSimple id) = pp id
|
ppOpenSpec (OSimple id) = pp id
|
||||||
ppOpenSpec (OQualif id n) = parens (id <+> '=' <+> n)
|
ppOpenSpec (OQualif id n) = parens (id <+> '=' <+> n)
|
||||||
|
|
||||||
ppInstSpec (id,n) = parens (id <+> '=' <+> n)
|
ppInstSpec (id,n) = parens (id <+> '=' <+> n)
|
||||||
|
|
||||||
ppLocDef q (id, (mbt, e)) =
|
ppLocDef q (id, (mbt, e)) =
|
||||||
id <+>
|
id <+>
|
||||||
(case mbt of {Just t -> ':' <+> ppTerm q 0 t; Nothing -> empty} <+> '=' <+> ppTerm q 0 e) <+> ';'
|
(case mbt of {Just t -> ':' <+> ppTerm q 0 t; Nothing -> empty} <+> '=' <+> ppTerm q 0 e) <+> ';'
|
||||||
|
|
||||||
ppBind (Explicit,v) = pp v
|
ppBind (Explicit,v) = pp v
|
||||||
ppBind (Implicit,v) = braces v
|
ppBind (Implicit,v) = braces v
|
||||||
|
|
||||||
ppAltern q (x,y) = ppTerm q 0 x <+> '/' <+> ppTerm q 0 y
|
ppAltern q (x,y) = ppTerm q 0 x <+> '/' <+> ppTerm q 0 y
|
||||||
|
|
||||||
ppParams q ps = fsep (intersperse (pp '|') (map (ppParam q) ps))
|
ppParams q ps = fsep (intersperse (pp '|') (map (ppParam q) ps))
|
||||||
ppParam q (id,cxt) = id <+> hsep (map (ppDDecl q) cxt)
|
ppParam q (id,cxt) = id <+> hsep (map (ppDDecl q) cxt)
|
||||||
|
|
||||||
ppProduction (Production fid funid args) =
|
ppProduction (Production fid funid args) =
|
||||||
ppFId fid <+> "->" <+> ppFunId funid <>
|
ppFId fid <+> "->" <+> ppFunId funid <>
|
||||||
brackets (hcat (punctuate "," (map (hsep . intersperse (pp '|') . map ppFId) args)))
|
brackets (hcat (punctuate "," (map (hsep . intersperse (pp '|') . map ppFId) args)))
|
||||||
|
|
||||||
ppSequences q seqsArr
|
ppSequences q seqsArr
|
||||||
| null seqs || q /= Internal = empty
|
| null seqs || q /= Internal = empty
|
||||||
| otherwise = "sequences" <+> '{' $$
|
| otherwise = "sequences" <+> '{' $$
|
||||||
nest 2 (vcat (map ppSeq seqs)) $$
|
nest 2 (vcat (map ppSeq seqs)) $$
|
||||||
'}'
|
'}'
|
||||||
where
|
where
|
||||||
seqs = Array.assocs seqsArr
|
seqs = Array.assocs seqsArr
|
||||||
|
|
||||||
commaPunct f ds = (hcat (punctuate "," (map f ds)))
|
commaPunct f ds = (hcat (punctuate "," (map f ds)))
|
||||||
|
|
||||||
prec d1 d2 doc
|
prec d1 d2 doc
|
||||||
| d1 > d2 = parens doc
|
| d1 > d2 = parens doc
|
||||||
| otherwise = doc
|
| otherwise = doc
|
||||||
|
|
||||||
getAbs :: Term -> ([(BindType,Ident)], Term)
|
getAbs :: Term -> ([(BindType,Ident)], Term)
|
||||||
getAbs (Abs bt v e) = let (xs,e') = getAbs e
|
getAbs (Abs bt v e) = let (xs,e') = getAbs e
|
||||||
in ((bt,v):xs,e')
|
in ((bt,v):xs,e')
|
||||||
getAbs e = ([],e)
|
getAbs e = ([],e)
|
||||||
|
|
||||||
getCTable :: Term -> ([Ident], Term)
|
getCTable :: Term -> ([Ident], Term)
|
||||||
getCTable (T TRaw [(PV v,e)]) = let (vs,e') = getCTable e
|
getCTable (T TRaw [(PV v,e)]) = let (vs,e') = getCTable e
|
||||||
in (v:vs,e')
|
in (v:vs,e')
|
||||||
getCTable (T TRaw [(PW, e)]) = let (vs,e') = getCTable e
|
getCTable (T TRaw [(PW, e)]) = let (vs,e') = getCTable e
|
||||||
in (identW:vs,e')
|
in (identW:vs,e')
|
||||||
getCTable e = ([],e)
|
getCTable e = ([],e)
|
||||||
|
|
||||||
getLet :: Term -> ([LocalDef], Term)
|
getLet :: Term -> ([LocalDef], Term)
|
||||||
getLet (Let l e) = let (ls,e') = getLet e
|
getLet (Let l e) = let (ls,e') = getLet e
|
||||||
in (l:ls,e')
|
in (l:ls,e')
|
||||||
getLet e = ([],e)
|
getLet e = ([],e)
|
||||||
|
|
||||||
ppFunId funid = pp 'F' <> pp funid
|
|
||||||
ppSeqId seqid = pp 'S' <> pp seqid
|
|
||||||
|
|
||||||
ppFId fid
|
|
||||||
| fid == PGF2.fidString = pp "CString"
|
|
||||||
| fid == PGF2.fidInt = pp "CInt"
|
|
||||||
| fid == PGF2.fidFloat = pp "CFloat"
|
|
||||||
| fid == PGF2.fidVar = pp "CVar"
|
|
||||||
| fid == PGF2.fidStart = pp "CStart"
|
|
||||||
| otherwise = pp 'C' <> pp fid
|
|
||||||
|
|
||||||
ppMeta :: Int -> Doc
|
|
||||||
ppMeta n
|
|
||||||
| n == 0 = pp '?'
|
|
||||||
| otherwise = pp '?' <> pp n
|
|
||||||
|
|
||||||
ppLit (PGF2.LStr s) = pp (show s)
|
|
||||||
ppLit (PGF2.LInt n) = pp n
|
|
||||||
ppLit (PGF2.LFlt d) = pp d
|
|
||||||
|
|
||||||
ppSeq (seqid,seq) =
|
|
||||||
ppSeqId seqid <+> pp ":=" <+> hsep (map ppSymbol seq)
|
|
||||||
|
|
||||||
ppSymbol (PGF2.SymCat d r) = pp '<' <> pp d <> pp ',' <> pp r <> pp '>'
|
|
||||||
ppSymbol (PGF2.SymLit d r) = pp '{' <> pp d <> pp ',' <> pp r <> pp '}'
|
|
||||||
ppSymbol (PGF2.SymVar d r) = pp '<' <> pp d <> pp ',' <> pp '$' <> pp r <> pp '>'
|
|
||||||
ppSymbol (PGF2.SymKS t) = doubleQuotes (pp t)
|
|
||||||
ppSymbol PGF2.SymNE = pp "nonExist"
|
|
||||||
ppSymbol PGF2.SymBIND = pp "BIND"
|
|
||||||
ppSymbol PGF2.SymSOFT_BIND = pp "SOFT_BIND"
|
|
||||||
ppSymbol PGF2.SymSOFT_SPACE= pp "SOFT_SPACE"
|
|
||||||
ppSymbol PGF2.SymCAPIT = pp "CAPIT"
|
|
||||||
ppSymbol PGF2.SymALL_CAPIT = pp "ALL_CAPIT"
|
|
||||||
ppSymbol (PGF2.SymKP syms alts) = pp "pre" <+> braces (hsep (punctuate (pp ';') (hsep (map ppSymbol syms) : map ppAlt alts)))
|
|
||||||
|
|
||||||
ppAlt (syms,ps) = hsep (map ppSymbol syms) <+> pp '/' <+> hsep (map (doubleQuotes . pp) ps)
|
|
||||||
|
|||||||
@@ -5,23 +5,22 @@
|
|||||||
-- Stability : (stable)
|
-- Stability : (stable)
|
||||||
-- Portability : (portable)
|
-- Portability : (portable)
|
||||||
--
|
--
|
||||||
-- > CVS $Date: 2005/04/21 16:22:32 $
|
-- > CVS $Date: 2005/04/21 16:22:32 $
|
||||||
-- > CVS $Author: bringert $
|
-- > CVS $Author: bringert $
|
||||||
-- > CVS $Revision: 1.7 $
|
-- > CVS $Revision: 1.7 $
|
||||||
--
|
--
|
||||||
-- (Description of the module)
|
-- (Description of the module)
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
|
|
||||||
module GF.Grammar.Values (
|
module GF.Grammar.Values (-- ** Values used in TC type checking
|
||||||
-- ** Values used in TC type checking
|
Val(..), Env,
|
||||||
Val(..), Env,
|
-- ** Annotated tree used in editing
|
||||||
-- ** Annotated tree used in editing
|
|
||||||
Binds, Constraints, MetaSubst,
|
Binds, Constraints, MetaSubst,
|
||||||
-- ** For TC
|
-- ** For TC
|
||||||
valAbsInt, valAbsFloat, valAbsString, vType,
|
valAbsInt, valAbsFloat, valAbsString, vType,
|
||||||
isPredefCat,
|
isPredefCat,
|
||||||
eType,
|
eType,
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import GF.Infra.Ident
|
import GF.Infra.Ident
|
||||||
import GF.Grammar.Grammar
|
import GF.Grammar.Grammar
|
||||||
|
|||||||
@@ -14,3 +14,9 @@ buildInfo =
|
|||||||
#ifdef SERVER_MODE
|
#ifdef SERVER_MODE
|
||||||
++" server"
|
++" server"
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef NEW_COMP
|
||||||
|
++" new-comp"
|
||||||
|
#endif
|
||||||
|
#ifdef C_RUNTIME
|
||||||
|
++" c-runtime"
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
-- Stability : (stable)
|
-- Stability : (stable)
|
||||||
-- Portability : (portable)
|
-- Portability : (portable)
|
||||||
--
|
--
|
||||||
-- > CVS $Date: 2005/04/21 16:22:33 $
|
-- > CVS $Date: 2005/04/21 16:22:33 $
|
||||||
-- > CVS $Author: bringert $
|
-- > CVS $Author: bringert $
|
||||||
-- > CVS $Revision: 1.5 $
|
-- > CVS $Revision: 1.5 $
|
||||||
--
|
--
|
||||||
@@ -14,12 +14,12 @@
|
|||||||
|
|
||||||
module GF.Infra.CheckM
|
module GF.Infra.CheckM
|
||||||
(Check, CheckResult, Message, runCheck, runCheck',
|
(Check, CheckResult, Message, runCheck, runCheck',
|
||||||
checkError, checkCond, checkWarn, checkWarnings, checkAccumError,
|
checkError, checkCond, checkWarn, checkWarnings, checkAccumError,
|
||||||
checkIn, checkInModule, checkMap, checkMapRecover,
|
checkIn, checkInModule, checkMap, checkMapRecover,
|
||||||
parallelCheck, accumulateError, commitCheck,
|
parallelCheck, accumulateError, commitCheck,
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Prelude hiding ((<>)) -- GHC 8.4.1 clash with Text.PrettyPrint
|
import Prelude hiding ((<>)) -- GHC 8.4.1 clash with Text.PrettyPrint
|
||||||
|
|
||||||
import GF.Data.Operations
|
import GF.Data.Operations
|
||||||
--import GF.Infra.Ident
|
--import GF.Infra.Ident
|
||||||
--import GF.Grammar.Grammar(msrc) -- ,Context
|
--import GF.Grammar.Grammar(msrc) -- ,Context
|
||||||
@@ -141,10 +141,10 @@ checkMapRecover f = fmap Map.fromList . parallelCheck . map f' . Map.toList
|
|||||||
where f' (k,v) = fmap ((,)k) (f k v)
|
where f' (k,v) = fmap ((,)k) (f k v)
|
||||||
|
|
||||||
{-
|
{-
|
||||||
checkMapRecover f mp = do
|
checkMapRecover f mp = do
|
||||||
let xs = map (\ (k,v) -> (k,runCheck (f k v))) (Map.toList mp)
|
let xs = map (\ (k,v) -> (k,runCheck (f k v))) (Map.toList mp)
|
||||||
case [s | (_,Bad s) <- xs] of
|
case [s | (_,Bad s) <- xs] of
|
||||||
ss@(_:_) -> checkError (text (unlines ss))
|
ss@(_:_) -> checkError (text (unlines ss))
|
||||||
_ -> do
|
_ -> do
|
||||||
let (kx,ss) = unzip [((k,x),s) | (k, Ok (x,s)) <- xs]
|
let (kx,ss) = unzip [((k,x),s) | (k, Ok (x,s)) <- xs]
|
||||||
if not (all null ss) then checkWarn (text (unlines ss)) else return ()
|
if not (all null ss) then checkWarn (text (unlines ss)) else return ()
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
-- Stability : (stable)
|
-- Stability : (stable)
|
||||||
-- Portability : (portable)
|
-- Portability : (portable)
|
||||||
--
|
--
|
||||||
-- > CVS $Date: 2005/11/15 11:43:33 $
|
-- > CVS $Date: 2005/11/15 11:43:33 $
|
||||||
-- > CVS $Author: aarne $
|
-- > CVS $Author: aarne $
|
||||||
-- > CVS $Revision: 1.8 $
|
-- > CVS $Revision: 1.8 $
|
||||||
--
|
--
|
||||||
@@ -13,25 +13,25 @@
|
|||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
|
|
||||||
module GF.Infra.Ident (-- ** Identifiers
|
module GF.Infra.Ident (-- ** Identifiers
|
||||||
ModuleName(..), moduleNameS,
|
ModuleName(..), moduleNameS,
|
||||||
Ident, ident2utf8, showIdent, prefixIdent,
|
Ident, ident2utf8, showIdent, prefixIdent,
|
||||||
-- *** Normal identifiers (returned by the parser)
|
-- *** Normal identifiers (returned by the parser)
|
||||||
identS, identC, identW,
|
identS, identC, identW,
|
||||||
-- *** Special identifiers for internal use
|
-- *** Special identifiers for internal use
|
||||||
identV, identA, identAV,
|
identV, identA, identAV,
|
||||||
argIdent, isArgIdent, getArgIndex,
|
argIdent, isArgIdent, getArgIndex,
|
||||||
varStr, varX, isWildIdent, varIndex,
|
varStr, varX, isWildIdent, varIndex,
|
||||||
-- *** Raw identifiers
|
-- *** Raw identifiers
|
||||||
RawIdent, rawIdentS, rawIdentC, ident2raw, prefixRawIdent,
|
RawIdent, rawIdentS, rawIdentC, ident2raw, prefixRawIdent,
|
||||||
isPrefixOf, showRawIdent
|
isPrefixOf, showRawIdent
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import qualified Data.ByteString.UTF8 as UTF8
|
import qualified Data.ByteString.UTF8 as UTF8
|
||||||
import qualified Data.ByteString.Char8 as BS(append,isPrefixOf)
|
import qualified Data.ByteString.Char8 as BS(append,isPrefixOf)
|
||||||
-- Limit use of BS functions to the ones that work correctly on
|
-- Limit use of BS functions to the ones that work correctly on
|
||||||
-- UTF-8-encoded bytestrings!
|
-- UTF-8-encoded bytestrings!
|
||||||
import Data.Char(isDigit)
|
import Data.Char(isDigit)
|
||||||
import Data.Binary(Binary(..))
|
import PGF.Internal(Binary(..))
|
||||||
import GF.Text.Pretty
|
import GF.Text.Pretty
|
||||||
|
|
||||||
|
|
||||||
@@ -46,7 +46,7 @@ instance Pretty ModuleName where pp (MN m) = pp m
|
|||||||
|
|
||||||
-- | the constructors labelled /INTERNAL/ are
|
-- | the constructors labelled /INTERNAL/ are
|
||||||
-- internal representation never returned by the parser
|
-- internal representation never returned by the parser
|
||||||
data Ident =
|
data Ident =
|
||||||
IC {-# UNPACK #-} !RawIdent -- ^ raw identifier after parsing, resolved in Rename
|
IC {-# UNPACK #-} !RawIdent -- ^ raw identifier after parsing, resolved in Rename
|
||||||
| IW -- ^ wildcard
|
| IW -- ^ wildcard
|
||||||
--
|
--
|
||||||
@@ -54,7 +54,7 @@ data Ident =
|
|||||||
| IV {-# UNPACK #-} !RawIdent {-# UNPACK #-} !Int -- ^ /INTERNAL/ variable
|
| IV {-# UNPACK #-} !RawIdent {-# UNPACK #-} !Int -- ^ /INTERNAL/ variable
|
||||||
| IA {-# UNPACK #-} !RawIdent {-# UNPACK #-} !Int -- ^ /INTERNAL/ argument of cat at position
|
| IA {-# UNPACK #-} !RawIdent {-# UNPACK #-} !Int -- ^ /INTERNAL/ argument of cat at position
|
||||||
| IAV {-# UNPACK #-} !RawIdent {-# UNPACK #-} !Int {-# UNPACK #-} !Int -- ^ /INTERNAL/ argument of cat with bindings at position
|
| IAV {-# UNPACK #-} !RawIdent {-# UNPACK #-} !Int {-# UNPACK #-} !Int -- ^ /INTERNAL/ argument of cat with bindings at position
|
||||||
--
|
--
|
||||||
deriving (Eq, Ord, Show, Read)
|
deriving (Eq, Ord, Show, Read)
|
||||||
|
|
||||||
-- | Identifiers are stored as UTF-8-encoded bytestrings.
|
-- | Identifiers are stored as UTF-8-encoded bytestrings.
|
||||||
@@ -70,13 +70,14 @@ rawIdentS = Id . pack
|
|||||||
rawIdentC = Id
|
rawIdentC = Id
|
||||||
showRawIdent = unpack . rawId2utf8
|
showRawIdent = unpack . rawId2utf8
|
||||||
|
|
||||||
prefixRawIdent (Id x) (Id y) = Id (BS.append x y)
|
prefixRawIdent (Id x) (Id y) = Id (BS.append x y)
|
||||||
isPrefixOf (Id x) (Id y) = BS.isPrefixOf x y
|
isPrefixOf (Id x) (Id y) = BS.isPrefixOf x y
|
||||||
|
|
||||||
instance Binary RawIdent where
|
instance Binary RawIdent where
|
||||||
put = put . rawId2utf8
|
put = put . rawId2utf8
|
||||||
get = fmap rawIdentC get
|
get = fmap rawIdentC get
|
||||||
|
|
||||||
|
|
||||||
-- | This function should be used with care, since the returned ByteString is
|
-- | This function should be used with care, since the returned ByteString is
|
||||||
-- UTF-8-encoded.
|
-- UTF-8-encoded.
|
||||||
ident2utf8 :: Ident -> UTF8.ByteString
|
ident2utf8 :: Ident -> UTF8.ByteString
|
||||||
@@ -87,7 +88,6 @@ ident2utf8 i = case i of
|
|||||||
IAV (Id s) b j -> BS.append s (pack ('_':show b ++ '_':show j))
|
IAV (Id s) b j -> BS.append s (pack ('_':show b ++ '_':show j))
|
||||||
IW -> pack "_"
|
IW -> pack "_"
|
||||||
|
|
||||||
ident2raw :: Ident -> RawIdent
|
|
||||||
ident2raw = Id . ident2utf8
|
ident2raw = Id . ident2utf8
|
||||||
|
|
||||||
showIdent :: Ident -> String
|
showIdent :: Ident -> String
|
||||||
@@ -95,14 +95,13 @@ showIdent i = unpack $! ident2utf8 i
|
|||||||
|
|
||||||
instance Pretty Ident where pp = pp . showIdent
|
instance Pretty Ident where pp = pp . showIdent
|
||||||
|
|
||||||
instance Pretty RawIdent where pp = pp . showRawIdent
|
|
||||||
|
|
||||||
identS :: String -> Ident
|
identS :: String -> Ident
|
||||||
identS = identC . rawIdentS
|
identS = identC . rawIdentS
|
||||||
|
|
||||||
identC :: RawIdent -> Ident
|
identC :: RawIdent -> Ident
|
||||||
identW :: Ident
|
identW :: Ident
|
||||||
|
|
||||||
|
|
||||||
prefixIdent :: String -> Ident -> Ident
|
prefixIdent :: String -> Ident -> Ident
|
||||||
prefixIdent pref = identC . Id . BS.append (pack pref) . ident2utf8
|
prefixIdent pref = identC . Id . BS.append (pack pref) . ident2utf8
|
||||||
|
|
||||||
@@ -113,7 +112,7 @@ identV :: RawIdent -> Int -> Ident
|
|||||||
identA :: RawIdent -> Int -> Ident
|
identA :: RawIdent -> Int -> Ident
|
||||||
identAV:: RawIdent -> Int -> Int -> Ident
|
identAV:: RawIdent -> Int -> Int -> Ident
|
||||||
|
|
||||||
(identC, identV, identA, identAV, identW) =
|
(identC, identV, identA, identAV, identW) =
|
||||||
(IC, IV, IA, IAV, IW)
|
(IC, IV, IA, IAV, IW)
|
||||||
|
|
||||||
-- | to mark argument variables
|
-- | to mark argument variables
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
-- | Source locations
|
-- | Source locations
|
||||||
module GF.Infra.Location where
|
module GF.Infra.Location where
|
||||||
import Prelude hiding ((<>))
|
import Prelude hiding ((<>)) -- GHC 8.4.1 clash with Text.PrettyPrint
|
||||||
import GF.Text.Pretty
|
import GF.Text.Pretty
|
||||||
|
|
||||||
-- ** Source locations
|
-- ** Source locations
|
||||||
|
|||||||
@@ -34,14 +34,16 @@ import Data.Maybe
|
|||||||
import GF.Infra.Ident
|
import GF.Infra.Ident
|
||||||
import GF.Infra.GetOpt
|
import GF.Infra.GetOpt
|
||||||
import GF.Grammar.Predef
|
import GF.Grammar.Predef
|
||||||
|
--import System.Console.GetOpt
|
||||||
import System.FilePath
|
import System.FilePath
|
||||||
import PGF2.Internal(Literal(..))
|
--import System.IO
|
||||||
|
|
||||||
import GF.Data.Operations(Err,ErrorMonad(..),liftErr)
|
import GF.Data.Operations(Err,ErrorMonad(..),liftErr)
|
||||||
|
|
||||||
import Data.Set (Set)
|
import Data.Set (Set)
|
||||||
import qualified Data.Set as Set
|
import qualified Data.Set as Set
|
||||||
|
|
||||||
|
import PGF.Internal(Literal(..))
|
||||||
import qualified Control.Monad.Fail as Fail
|
import qualified Control.Monad.Fail as Fail
|
||||||
|
|
||||||
usageHeader :: String
|
usageHeader :: String
|
||||||
@@ -74,6 +76,7 @@ errors = raise . unlines
|
|||||||
|
|
||||||
data Mode = ModeVersion | ModeHelp
|
data Mode = ModeVersion | ModeHelp
|
||||||
| ModeInteractive | ModeRun
|
| ModeInteractive | ModeRun
|
||||||
|
| ModeInteractive2 | ModeRun2
|
||||||
| ModeCompiler
|
| ModeCompiler
|
||||||
| ModeServer {-port::-}Int
|
| ModeServer {-port::-}Int
|
||||||
deriving (Show,Eq,Ord)
|
deriving (Show,Eq,Ord)
|
||||||
@@ -84,7 +87,8 @@ data Verbosity = Quiet | Normal | Verbose | Debug
|
|||||||
data Phase = Preproc | Convert | Compile | Link
|
data Phase = Preproc | Convert | Compile | Link
|
||||||
deriving (Show,Eq,Ord)
|
deriving (Show,Eq,Ord)
|
||||||
|
|
||||||
data OutputFormat = FmtPGFPretty
|
data OutputFormat = FmtLPGF
|
||||||
|
| FmtPGFPretty
|
||||||
| FmtCanonicalGF
|
| FmtCanonicalGF
|
||||||
| FmtCanonicalJson
|
| FmtCanonicalJson
|
||||||
| FmtJavaScript
|
| FmtJavaScript
|
||||||
@@ -92,6 +96,7 @@ data OutputFormat = FmtPGFPretty
|
|||||||
| FmtPython
|
| FmtPython
|
||||||
| FmtHaskell
|
| FmtHaskell
|
||||||
| FmtJava
|
| FmtJava
|
||||||
|
| FmtProlog
|
||||||
| FmtBNF
|
| FmtBNF
|
||||||
| FmtEBNF
|
| FmtEBNF
|
||||||
| FmtRegular
|
| FmtRegular
|
||||||
@@ -127,13 +132,8 @@ data CFGTransform = CFGNoLR
|
|||||||
| CFGRemoveCycles
|
| CFGRemoveCycles
|
||||||
deriving (Show,Eq,Ord)
|
deriving (Show,Eq,Ord)
|
||||||
|
|
||||||
data HaskellOption = HaskellNoPrefix
|
data HaskellOption = HaskellNoPrefix | HaskellGADT | HaskellLexical
|
||||||
| HaskellGADT
|
| HaskellConcrete | HaskellVariants | HaskellData
|
||||||
| HaskellLexical
|
|
||||||
| HaskellConcrete
|
|
||||||
| HaskellVariants
|
|
||||||
| HaskellData
|
|
||||||
| HaskellPGF2
|
|
||||||
deriving (Show,Eq,Ord)
|
deriving (Show,Eq,Ord)
|
||||||
|
|
||||||
data Warning = WarnMissingLincat
|
data Warning = WarnMissingLincat
|
||||||
@@ -158,7 +158,7 @@ data Flags = Flags {
|
|||||||
optLiteralCats :: Set Ident,
|
optLiteralCats :: Set Ident,
|
||||||
optGFODir :: Maybe FilePath,
|
optGFODir :: Maybe FilePath,
|
||||||
optOutputDir :: Maybe FilePath,
|
optOutputDir :: Maybe FilePath,
|
||||||
optGFLibPath :: Maybe FilePath,
|
optGFLibPath :: Maybe [FilePath],
|
||||||
optDocumentRoot :: Maybe FilePath, -- For --server mode
|
optDocumentRoot :: Maybe FilePath, -- For --server mode
|
||||||
optRecomp :: Recomp,
|
optRecomp :: Recomp,
|
||||||
optProbsFile :: Maybe FilePath,
|
optProbsFile :: Maybe FilePath,
|
||||||
@@ -213,9 +213,10 @@ parseModuleOptions args = do
|
|||||||
then return opts
|
then return opts
|
||||||
else errors $ map ("Non-option among module options: " ++) nonopts
|
else errors $ map ("Non-option among module options: " ++) nonopts
|
||||||
|
|
||||||
fixRelativeLibPaths curr_dir lib_dir (Options o) = Options (fixPathFlags . o)
|
fixRelativeLibPaths curr_dir lib_dirs (Options o) = Options (fixPathFlags . o)
|
||||||
where
|
where
|
||||||
fixPathFlags f@(Flags{optLibraryPath=path}) = f{optLibraryPath=concatMap (\dir -> [curr_dir </> dir, lib_dir </> dir]) path}
|
fixPathFlags f@(Flags{optLibraryPath=path}) = f{optLibraryPath=concatMap (\dir -> [parent </> dir
|
||||||
|
| parent <- curr_dir : lib_dirs]) path}
|
||||||
|
|
||||||
-- Showing options
|
-- Showing options
|
||||||
|
|
||||||
@@ -311,6 +312,8 @@ optDescr =
|
|||||||
Option ['j'] ["jobs"] (OptArg jobs "N") "Compile N modules in parallel with -batch (default 1).",
|
Option ['j'] ["jobs"] (OptArg jobs "N") "Compile N modules in parallel with -batch (default 1).",
|
||||||
Option [] ["interactive"] (NoArg (mode ModeInteractive)) "Run in interactive mode (default).",
|
Option [] ["interactive"] (NoArg (mode ModeInteractive)) "Run in interactive mode (default).",
|
||||||
Option [] ["run"] (NoArg (mode ModeRun)) "Run in interactive mode, showing output only (no other messages).",
|
Option [] ["run"] (NoArg (mode ModeRun)) "Run in interactive mode, showing output only (no other messages).",
|
||||||
|
Option [] ["cshell"] (NoArg (mode ModeInteractive2)) "Start the C run-time shell.",
|
||||||
|
Option [] ["crun"] (NoArg (mode ModeRun2)) "Start the C run-time shell, showing output only (no other messages).",
|
||||||
Option [] ["server"] (OptArg modeServer "port") $
|
Option [] ["server"] (OptArg modeServer "port") $
|
||||||
"Run in HTTP server mode on given port (default "++show defaultPort++").",
|
"Run in HTTP server mode on given port (default "++show defaultPort++").",
|
||||||
Option [] ["document-root"] (ReqArg gfDocuRoot "DIR")
|
Option [] ["document-root"] (ReqArg gfDocuRoot "DIR")
|
||||||
@@ -328,7 +331,7 @@ optDescr =
|
|||||||
Option ['f'] ["output-format"] (ReqArg outFmt "FMT")
|
Option ['f'] ["output-format"] (ReqArg outFmt "FMT")
|
||||||
(unlines ["Output format. FMT can be one of:",
|
(unlines ["Output format. FMT can be one of:",
|
||||||
"Canonical GF grammar: canonical_gf, canonical_json, (and haskell with option --haskell=concrete)",
|
"Canonical GF grammar: canonical_gf, canonical_json, (and haskell with option --haskell=concrete)",
|
||||||
"Multiple concrete: pgf (default), json, js, pgf_pretty, prolog, python, ...", -- gar,
|
"Multiple concrete: pgf (default), lpgf, json, js, pgf_pretty, prolog, python, ...", -- gar,
|
||||||
"Single concrete only: bnf, ebnf, fa, gsl, jsgf, regexp, slf, srgs_xml, srgs_abnf, vxml, ....", -- cf, lbnf,
|
"Single concrete only: bnf, ebnf, fa, gsl, jsgf, regexp, slf, srgs_xml, srgs_abnf, vxml, ....", -- cf, lbnf,
|
||||||
"Abstract only: haskell, ..."]), -- prolog_abs,
|
"Abstract only: haskell, ..."]), -- prolog_abs,
|
||||||
Option [] ["sisr"] (ReqArg sisrFmt "FMT")
|
Option [] ["sisr"] (ReqArg sisrFmt "FMT")
|
||||||
@@ -425,7 +428,7 @@ optDescr =
|
|||||||
literalCat x = set $ \o -> o { optLiteralCats = foldr Set.insert (optLiteralCats o) ((map identS . splitBy (==',')) x) }
|
literalCat x = set $ \o -> o { optLiteralCats = foldr Set.insert (optLiteralCats o) ((map identS . splitBy (==',')) x) }
|
||||||
lexicalCat x = set $ \o -> o { optLexicalCats = foldr Set.insert (optLexicalCats o) (splitBy (==',') x) }
|
lexicalCat x = set $ \o -> o { optLexicalCats = foldr Set.insert (optLexicalCats o) (splitBy (==',') x) }
|
||||||
outDir x = set $ \o -> o { optOutputDir = Just x }
|
outDir x = set $ \o -> o { optOutputDir = Just x }
|
||||||
gfLibPath x = set $ \o -> o { optGFLibPath = Just x }
|
gfLibPath x = set $ \o -> o { optGFLibPath = Just $ splitInModuleSearchPath x }
|
||||||
gfDocuRoot x = set $ \o -> o { optDocumentRoot = Just x }
|
gfDocuRoot x = set $ \o -> o { optDocumentRoot = Just x }
|
||||||
recomp x = set $ \o -> o { optRecomp = x }
|
recomp x = set $ \o -> o { optRecomp = x }
|
||||||
probsFile x = set $ \o -> o { optProbsFile = Just x }
|
probsFile x = set $ \o -> o { optProbsFile = Just x }
|
||||||
@@ -470,12 +473,16 @@ outputFormats = map fst outputFormatsExpl
|
|||||||
|
|
||||||
outputFormatsExpl :: [((String,OutputFormat),String)]
|
outputFormatsExpl :: [((String,OutputFormat),String)]
|
||||||
outputFormatsExpl =
|
outputFormatsExpl =
|
||||||
[(("pgf_pretty", FmtPGFPretty),"human-readable pgf"),
|
[(("lpgf", FmtLPGF),"Linearisation-only PGF"),
|
||||||
|
(("pgf_pretty", FmtPGFPretty),"Human-readable PGF"),
|
||||||
(("canonical_gf", FmtCanonicalGF),"Canonical GF source files"),
|
(("canonical_gf", FmtCanonicalGF),"Canonical GF source files"),
|
||||||
(("canonical_json", FmtCanonicalJson),"Canonical JSON source files"),
|
(("canonical_json", FmtCanonicalJson),"Canonical JSON source files"),
|
||||||
|
(("js", FmtJavaScript),"JavaScript (whole grammar)"),
|
||||||
(("json", FmtJSON),"JSON (whole grammar)"),
|
(("json", FmtJSON),"JSON (whole grammar)"),
|
||||||
|
(("python", FmtPython),"Python (whole grammar)"),
|
||||||
(("haskell", FmtHaskell),"Haskell (abstract syntax)"),
|
(("haskell", FmtHaskell),"Haskell (abstract syntax)"),
|
||||||
(("java", FmtJava),"Java (abstract syntax)"),
|
(("java", FmtJava),"Java (abstract syntax)"),
|
||||||
|
(("prolog", FmtProlog),"Prolog (whole grammar)"),
|
||||||
(("bnf", FmtBNF),"BNF (context-free grammar)"),
|
(("bnf", FmtBNF),"BNF (context-free grammar)"),
|
||||||
(("ebnf", FmtEBNF),"Extended BNF"),
|
(("ebnf", FmtEBNF),"Extended BNF"),
|
||||||
(("regular", FmtRegular),"* regular grammar"),
|
(("regular", FmtRegular),"* regular grammar"),
|
||||||
@@ -527,8 +534,7 @@ haskellOptionNames =
|
|||||||
("lexical", HaskellLexical),
|
("lexical", HaskellLexical),
|
||||||
("concrete", HaskellConcrete),
|
("concrete", HaskellConcrete),
|
||||||
("variants", HaskellVariants),
|
("variants", HaskellVariants),
|
||||||
("data", HaskellData),
|
("data", HaskellData)]
|
||||||
("pgf2", HaskellPGF2)]
|
|
||||||
|
|
||||||
-- | This is for bacward compatibility. Since GHC 6.12 we
|
-- | This is for bacward compatibility. Since GHC 6.12 we
|
||||||
-- started using the native Unicode support in GHC but it
|
-- started using the native Unicode support in GHC but it
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ module GF.Infra.SIO(
|
|||||||
newStdGen,print,putStr,putStrLn,
|
newStdGen,print,putStr,putStrLn,
|
||||||
-- ** Specific to GF
|
-- ** Specific to GF
|
||||||
importGrammar,importSource,
|
importGrammar,importSource,
|
||||||
|
#ifdef C_RUNTIME
|
||||||
|
readPGF2,
|
||||||
|
#endif
|
||||||
putStrLnFlush,runInterruptibly,lazySIO,
|
putStrLnFlush,runInterruptibly,lazySIO,
|
||||||
-- * Restricted accesss to arbitrary (potentially unsafe) IO operations
|
-- * Restricted accesss to arbitrary (potentially unsafe) IO operations
|
||||||
-- | If the environment variable GF_RESTRICTED is defined, these
|
-- | If the environment variable GF_RESTRICTED is defined, these
|
||||||
@@ -36,6 +39,9 @@ import qualified System.Random as IO(newStdGen)
|
|||||||
import qualified GF.Infra.UseIO as IO(getLibraryDirectory)
|
import qualified GF.Infra.UseIO as IO(getLibraryDirectory)
|
||||||
import qualified GF.System.Signal as IO(runInterruptibly)
|
import qualified GF.System.Signal as IO(runInterruptibly)
|
||||||
import qualified GF.Command.Importing as GF(importGrammar, importSource)
|
import qualified GF.Command.Importing as GF(importGrammar, importSource)
|
||||||
|
#ifdef C_RUNTIME
|
||||||
|
import qualified PGF2
|
||||||
|
#endif
|
||||||
import qualified Control.Monad.Fail as Fail
|
import qualified Control.Monad.Fail as Fail
|
||||||
|
|
||||||
-- * The SIO monad
|
-- * The SIO monad
|
||||||
@@ -121,3 +127,7 @@ lazySIO = lift1 lazyIO
|
|||||||
|
|
||||||
importGrammar pgf opts files = lift0 $ GF.importGrammar pgf opts files
|
importGrammar pgf opts files = lift0 $ GF.importGrammar pgf opts files
|
||||||
importSource opts files = lift0 $ GF.importSource opts files
|
importSource opts files = lift0 $ GF.importSource opts files
|
||||||
|
|
||||||
|
#ifdef C_RUNTIME
|
||||||
|
readPGF2 = lift0 . PGF2.readPGF
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ import Control.Monad(when,liftM,foldM)
|
|||||||
import Control.Monad.Trans(MonadIO(..))
|
import Control.Monad.Trans(MonadIO(..))
|
||||||
import Control.Monad.State(StateT,lift)
|
import Control.Monad.State(StateT,lift)
|
||||||
import Control.Exception(evaluate)
|
import Control.Exception(evaluate)
|
||||||
|
import Data.List (nub)
|
||||||
|
|
||||||
--putIfVerb :: MonadIO io => Options -> String -> io ()
|
--putIfVerb :: MonadIO io => Options -> String -> io ()
|
||||||
putIfVerb opts msg = when (verbAtLeast opts Verbose) $ putStrLnE msg
|
putIfVerb opts msg = when (verbAtLeast opts Verbose) $ putStrLnE msg
|
||||||
@@ -51,28 +52,32 @@ type FullPath = String
|
|||||||
gfLibraryPath = "GF_LIB_PATH"
|
gfLibraryPath = "GF_LIB_PATH"
|
||||||
gfGrammarPathVar = "GF_GRAMMAR_PATH"
|
gfGrammarPathVar = "GF_GRAMMAR_PATH"
|
||||||
|
|
||||||
getLibraryDirectory :: MonadIO io => Options -> io FilePath
|
getLibraryDirectory :: MonadIO io => Options -> io [FilePath]
|
||||||
getLibraryDirectory opts =
|
getLibraryDirectory opts =
|
||||||
case flag optGFLibPath opts of
|
case flag optGFLibPath opts of
|
||||||
Just path -> return path
|
Just path -> return path
|
||||||
Nothing -> liftIO $ catch (getEnv gfLibraryPath)
|
Nothing -> liftM splitSearchPath $ liftIO (catch (getEnv gfLibraryPath)
|
||||||
(\ex -> fmap (</> "lib") getDataDir)
|
(\ex -> fmap (</> "lib") getDataDir))
|
||||||
|
|
||||||
getGrammarPath :: MonadIO io => FilePath -> io [FilePath]
|
getGrammarPath :: MonadIO io => [FilePath] -> io [FilePath]
|
||||||
getGrammarPath lib_dir = liftIO $ do
|
getGrammarPath lib_dirs = liftIO $ do
|
||||||
catch (fmap splitSearchPath $ getEnv gfGrammarPathVar)
|
catch (fmap splitSearchPath $ getEnv gfGrammarPathVar)
|
||||||
(\_ -> return [lib_dir </> "alltenses",lib_dir </> "prelude"]) -- e.g. GF_GRAMMAR_PATH
|
(\_ -> return $ concat [[lib_dir </> "alltenses", lib_dir </> "prelude"]
|
||||||
|
| lib_dir <- lib_dirs ]) -- e.g. GF_GRAMMAR_PATH
|
||||||
|
|
||||||
-- | extends the search path with the
|
-- | extends the search path with the
|
||||||
-- 'gfLibraryPath' and 'gfGrammarPathVar'
|
-- 'gfLibraryPath' and 'gfGrammarPathVar'
|
||||||
-- environment variables. Returns only existing paths.
|
-- environment variables. Returns only existing paths.
|
||||||
extendPathEnv :: MonadIO io => Options -> io [FilePath]
|
extendPathEnv :: MonadIO io => Options -> io [FilePath]
|
||||||
extendPathEnv opts = liftIO $ do
|
extendPathEnv opts = liftIO $ do
|
||||||
let opt_path = flag optLibraryPath opts -- e.g. paths given as options
|
let opt_path = nub $ flag optLibraryPath opts -- e.g. paths given as options
|
||||||
lib_dir <- getLibraryDirectory opts -- e.g. GF_LIB_PATH
|
lib_dirs <- getLibraryDirectory opts -- e.g. GF_LIB_PATH
|
||||||
grm_path <- getGrammarPath lib_dir -- e.g. GF_GRAMMAR_PATH
|
grm_path <- getGrammarPath lib_dirs -- e.g. GF_GRAMMAR_PATH
|
||||||
let paths = opt_path ++ [lib_dir] ++ grm_path
|
let paths = opt_path ++ lib_dirs ++ grm_path
|
||||||
ps <- liftM concat $ mapM allSubdirs paths
|
when (verbAtLeast opts Verbose) $ putStrLn ("extendPathEnv: opt_path is "++ show opt_path)
|
||||||
|
when (verbAtLeast opts Verbose) $ putStrLn ("extendPathEnv: lib_dirs is "++ show lib_dirs)
|
||||||
|
when (verbAtLeast opts Verbose) $ putStrLn ("extendPathEnv: grm_path is "++ show grm_path)
|
||||||
|
ps <- liftM (nub . concat) $ mapM allSubdirs (nub paths)
|
||||||
mapM canonicalizePath ps
|
mapM canonicalizePath ps
|
||||||
where
|
where
|
||||||
allSubdirs :: FilePath -> IO [FilePath]
|
allSubdirs :: FilePath -> IO [FilePath]
|
||||||
@@ -80,11 +85,15 @@ extendPathEnv opts = liftIO $ do
|
|||||||
allSubdirs p = case last p of
|
allSubdirs p = case last p of
|
||||||
'*' -> do let path = init p
|
'*' -> do let path = init p
|
||||||
fs <- getSubdirs path
|
fs <- getSubdirs path
|
||||||
return [path </> f | f <- fs]
|
let starpaths = [path </> f | f <- fs]
|
||||||
|
when (verbAtLeast opts Verbose) $ putStrLn ("extendPathEnv: allSubdirs: * found "++show starpaths)
|
||||||
|
return starpaths
|
||||||
_ -> do exists <- doesDirectoryExist p
|
_ -> do exists <- doesDirectoryExist p
|
||||||
if exists
|
if exists
|
||||||
then return [p]
|
then do
|
||||||
else do when (verbAtLeast opts Verbose) $ putStrLn ("ignore path "++p)
|
when (verbAtLeast opts Verbose) $ putStrLn ("extendPathEnv: allSubdirs: found path "++show p)
|
||||||
|
return [p]
|
||||||
|
else do when (verbAtLeast opts Verbose) $ putStrLn ("extendPathEnv: allSubdirs: ignore path "++ show p)
|
||||||
return []
|
return []
|
||||||
|
|
||||||
getSubdirs :: FilePath -> IO [FilePath]
|
getSubdirs :: FilePath -> IO [FilePath]
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ module GF.Interactive (mainGFI,mainRunGFI,mainServerGFI) where
|
|||||||
import Prelude hiding (putStrLn,print)
|
import Prelude hiding (putStrLn,print)
|
||||||
import qualified Prelude as P(putStrLn)
|
import qualified Prelude as P(putStrLn)
|
||||||
import GF.Command.Interpreter(CommandEnv(..),mkCommandEnv,interpretCommandLine)
|
import GF.Command.Interpreter(CommandEnv(..),mkCommandEnv,interpretCommandLine)
|
||||||
import GF.Command.Commands(HasPGF(..),pgfCommands)
|
import GF.Command.Commands(PGFEnv,HasPGFEnv(..),pgf,pgfEnv,pgfCommands)
|
||||||
import GF.Command.CommonCommands(commonCommands,extend)
|
import GF.Command.CommonCommands(commonCommands,extend)
|
||||||
import GF.Command.SourceCommands
|
import GF.Command.SourceCommands
|
||||||
import GF.Command.CommandInfo
|
import GF.Command.CommandInfo
|
||||||
@@ -20,12 +20,15 @@ import GF.Infra.SIO
|
|||||||
import GF.Infra.Option
|
import GF.Infra.Option
|
||||||
import qualified System.Console.Haskeline as Haskeline
|
import qualified System.Console.Haskeline as Haskeline
|
||||||
|
|
||||||
import PGF2
|
import PGF
|
||||||
|
import PGF.Internal(abstract,funs,lookStartCat,emptyPGF)
|
||||||
|
|
||||||
import Data.Char
|
import Data.Char
|
||||||
import Data.List(isPrefixOf)
|
import Data.List(isPrefixOf)
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
import qualified Text.ParserCombinators.ReadP as RP
|
import qualified Text.ParserCombinators.ReadP as RP
|
||||||
|
--import System.IO(utf8)
|
||||||
|
--import System.CPUTime(getCPUTime)
|
||||||
import System.Directory({-getCurrentDirectory,-}getAppUserDataDirectory)
|
import System.Directory({-getCurrentDirectory,-}getAppUserDataDirectory)
|
||||||
import Control.Exception(SomeException,fromException,evaluate,try)
|
import Control.Exception(SomeException,fromException,evaluate,try)
|
||||||
import Control.Monad.State hiding (void)
|
import Control.Monad.State hiding (void)
|
||||||
@@ -35,6 +38,9 @@ import GF.Server(server)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
import GF.Command.Messages(welcome)
|
import GF.Command.Messages(welcome)
|
||||||
|
import GF.Infra.UseIO (Output)
|
||||||
|
-- Provides an orphan instance of MonadFail for StateT in ghc versions < 8
|
||||||
|
import Control.Monad.Trans.Instances ()
|
||||||
|
|
||||||
-- | Run the GF Shell in quiet mode (@gf -run@).
|
-- | Run the GF Shell in quiet mode (@gf -run@).
|
||||||
mainRunGFI :: Options -> [FilePath] -> IO ()
|
mainRunGFI :: Options -> [FilePath] -> IO ()
|
||||||
@@ -50,7 +56,6 @@ mainGFI opts files = do
|
|||||||
|
|
||||||
shell opts files = flip evalStateT (emptyGFEnv opts) $
|
shell opts files = flip evalStateT (emptyGFEnv opts) $
|
||||||
do mapStateT runSIO $ importInEnv opts files
|
do mapStateT runSIO $ importInEnv opts files
|
||||||
modify $ \ gfenv0 -> gfenv0 {history = [unwords ("i":files)]}
|
|
||||||
loop
|
loop
|
||||||
|
|
||||||
#ifdef SERVER_MODE
|
#ifdef SERVER_MODE
|
||||||
@@ -275,18 +280,17 @@ importInEnv opts files =
|
|||||||
if flag optRetainResource opts
|
if flag optRetainResource opts
|
||||||
then do src <- lift $ importSource opts files
|
then do src <- lift $ importSource opts files
|
||||||
pgf <- lift . lazySIO $ importPGF pgf0 -- duplicates some work, better to link src
|
pgf <- lift . lazySIO $ importPGF pgf0 -- duplicates some work, better to link src
|
||||||
modify $ \ gfenv -> gfenv {retain=True, pgfenv = (src,pgf)}
|
modify $ \ gfenv -> gfenv {retain=True, pgfenv = (src,pgfEnv pgf)}
|
||||||
else do pgf1 <- lift $ importPGF pgf0
|
else do pgf1 <- lift $ importPGF pgf0
|
||||||
modify $ \ gfenv->gfenv { retain=False,
|
modify $ \ gfenv->gfenv { retain=False,
|
||||||
pgfenv = (emptyGrammar,pgf1) }
|
pgfenv = (emptyGrammar,pgfEnv pgf1) }
|
||||||
where
|
where
|
||||||
importPGF pgf0 =
|
importPGF pgf0 =
|
||||||
do let opts' = addOptions (setOptimization OptCSE False) opts
|
do let opts' = addOptions (setOptimization OptCSE False) opts
|
||||||
pgf1 <- importGrammar pgf0 opts' files
|
pgf1 <- importGrammar pgf0 opts' files
|
||||||
if (verbAtLeast opts Normal)
|
if (verbAtLeast opts Normal)
|
||||||
then case pgf1 of
|
then putStrLnFlush $
|
||||||
Just pgf -> putStrLnFlush $ unwords $ "\nLanguages:" : Map.keys (languages pgf)
|
unwords $ "\nLanguages:" : map showCId (languages pgf1)
|
||||||
Nothing -> return ()
|
|
||||||
else return ()
|
else return ()
|
||||||
return pgf1
|
return pgf1
|
||||||
|
|
||||||
@@ -297,12 +301,12 @@ tryGetLine = do
|
|||||||
Right l -> return l
|
Right l -> return l
|
||||||
|
|
||||||
prompt env
|
prompt env
|
||||||
| retain env = "> "
|
| retain env || abs == wildCId = "> "
|
||||||
| otherwise = case multigrammar env of
|
| otherwise = showCId abs ++ "> "
|
||||||
Just pgf -> abstractName pgf ++ "> "
|
where
|
||||||
Nothing -> "> "
|
abs = abstractName (multigrammar env)
|
||||||
|
|
||||||
type CmdEnv = (Grammar,Maybe PGF)
|
type CmdEnv = (Grammar,PGFEnv)
|
||||||
|
|
||||||
data GFEnv = GFEnv {
|
data GFEnv = GFEnv {
|
||||||
startOpts :: Options,
|
startOpts :: Options,
|
||||||
@@ -314,10 +318,10 @@ data GFEnv = GFEnv {
|
|||||||
|
|
||||||
emptyGFEnv opts = GFEnv opts False emptyCmdEnv emptyCommandEnv []
|
emptyGFEnv opts = GFEnv opts False emptyCmdEnv emptyCommandEnv []
|
||||||
|
|
||||||
emptyCmdEnv = (emptyGrammar,Nothing)
|
emptyCmdEnv = (emptyGrammar,pgfEnv emptyPGF)
|
||||||
|
|
||||||
emptyCommandEnv = mkCommandEnv allCommands
|
emptyCommandEnv = mkCommandEnv allCommands
|
||||||
multigrammar = snd . pgfenv
|
multigrammar = pgf . snd . pgfenv
|
||||||
|
|
||||||
allCommands =
|
allCommands =
|
||||||
extend pgfCommands (helpCommand allCommands:moreCommands)
|
extend pgfCommands (helpCommand allCommands:moreCommands)
|
||||||
@@ -325,35 +329,24 @@ allCommands =
|
|||||||
`Map.union` commonCommands
|
`Map.union` commonCommands
|
||||||
|
|
||||||
instance HasGrammar ShellM where getGrammar = gets (fst . pgfenv)
|
instance HasGrammar ShellM where getGrammar = gets (fst . pgfenv)
|
||||||
instance HasPGF ShellM where getPGF = gets (snd . pgfenv)
|
instance HasPGFEnv ShellM where getPGFEnv = gets (snd . pgfenv)
|
||||||
|
|
||||||
wordCompletion gfenv (left,right) = do
|
wordCompletion gfenv (left,right) = do
|
||||||
case wc_type (reverse left) of
|
case wc_type (reverse left) of
|
||||||
CmplCmd pref
|
CmplCmd pref
|
||||||
-> ret (length pref) [Haskeline.simpleCompletion name | name <- Map.keys (commands cmdEnv), isPrefixOf pref name]
|
-> ret (length pref) [Haskeline.simpleCompletion name | name <- Map.keys (commands cmdEnv), isPrefixOf pref name]
|
||||||
CmplStr (Just (Command _ opts _)) s0
|
CmplStr (Just (Command _ opts _)) s0
|
||||||
-> case multigrammar gfenv of
|
-> do mb_state0 <- try (evaluate (initState pgf (optLang opts) (optType opts)))
|
||||||
Just pgf -> let langs = languages pgf
|
case mb_state0 of
|
||||||
optLang opts = case valStrOpts "lang" "" opts of
|
Right state0 -> let (rprefix,rs) = break isSpace (reverse s0)
|
||||||
"" -> case Map.minView langs of
|
s = reverse rs
|
||||||
Nothing -> Nothing
|
prefix = reverse rprefix
|
||||||
Just (concr,_) -> Just concr
|
ws = words s
|
||||||
lang -> mplus (Map.lookup lang langs)
|
in case loop state0 ws of
|
||||||
(Map.lookup (abstractName pgf ++ lang) langs)
|
Nothing -> ret 0 []
|
||||||
optType opts = let readOpt str = case readType str of
|
Just state -> let compls = getCompletions state prefix
|
||||||
Just ty -> case checkType pgf ty of
|
in ret (length prefix) (map (\x -> Haskeline.simpleCompletion x) (Map.keys compls))
|
||||||
Left _ -> Nothing
|
Left (_ :: SomeException) -> ret 0 []
|
||||||
Right ty -> Just ty
|
|
||||||
Nothing -> Nothing
|
|
||||||
in maybeStrOpts "cat" (Just (startCat pgf)) readOpt opts
|
|
||||||
(rprefix,rs) = break isSpace (reverse s0)
|
|
||||||
s = reverse rs
|
|
||||||
prefix = reverse rprefix
|
|
||||||
in case (optLang opts, optType opts) of
|
|
||||||
(Just lang,Just cat) -> let compls = [t | ParseOk res <- [complete lang cat s prefix], (t,_,_,_) <- res]
|
|
||||||
in ret (length prefix) (map Haskeline.simpleCompletion compls)
|
|
||||||
_ -> ret 0 []
|
|
||||||
Nothing -> ret 0 []
|
|
||||||
CmplOpt (Just (Command n _ _)) pref
|
CmplOpt (Just (Command n _ _)) pref
|
||||||
-> case Map.lookup n (commands cmdEnv) of
|
-> case Map.lookup n (commands cmdEnv) of
|
||||||
Just inf -> do let flg_compls = [Haskeline.Completion ('-':flg++"=") ('-':flg) False | (flg,_) <- flags inf, isPrefixOf pref flg]
|
Just inf -> do let flg_compls = [Haskeline.Completion ('-':flg++"=") ('-':flg) False | (flg,_) <- flags inf, isPrefixOf pref flg]
|
||||||
@@ -364,15 +357,23 @@ wordCompletion gfenv (left,right) = do
|
|||||||
CmplIdent (Just (Command "i" _ _)) _ -- HACK: file name completion for command i
|
CmplIdent (Just (Command "i" _ _)) _ -- HACK: file name completion for command i
|
||||||
-> Haskeline.completeFilename (left,right)
|
-> Haskeline.completeFilename (left,right)
|
||||||
CmplIdent _ pref
|
CmplIdent _ pref
|
||||||
-> case multigrammar gfenv of
|
-> do mb_abs <- try (evaluate (abstract pgf))
|
||||||
Just pgf -> ret (length pref) [Haskeline.simpleCompletion name | name <- functions pgf, isPrefixOf pref name]
|
case mb_abs of
|
||||||
Nothing -> ret (length pref) []
|
Right abs -> ret (length pref) [Haskeline.simpleCompletion name | cid <- Map.keys (funs abs), let name = showCId cid, isPrefixOf pref name]
|
||||||
|
Left (_ :: SomeException) -> ret (length pref) []
|
||||||
_ -> ret 0 []
|
_ -> ret 0 []
|
||||||
where
|
where
|
||||||
|
pgf = multigrammar gfenv
|
||||||
cmdEnv = commandenv gfenv
|
cmdEnv = commandenv gfenv
|
||||||
|
optLang opts = valCIdOpts "lang" (head (languages pgf)) opts
|
||||||
|
optType opts =
|
||||||
|
let str = valStrOpts "cat" (showCId $ lookStartCat pgf) opts
|
||||||
|
in case readType str of
|
||||||
|
Just ty -> ty
|
||||||
|
Nothing -> error ("Can't parse '"++str++"' as type")
|
||||||
|
|
||||||
loop ps [] = Just ps
|
loop ps [] = Just ps
|
||||||
loop ps (t:ts) = case error "nextState ps (simpleParseInput t)" of
|
loop ps (t:ts) = case nextState ps (simpleParseInput t) of
|
||||||
Left es -> Nothing
|
Left es -> Nothing
|
||||||
Right ps -> loop ps ts
|
Right ps -> loop ps ts
|
||||||
|
|
||||||
@@ -432,7 +433,7 @@ wc_type = cmd_name
|
|||||||
x2 = takeWhile (\c -> isIdent c || isSpace c || c == '-' || c == '=' || c == '"') x1
|
x2 = takeWhile (\c -> isIdent c || isSpace c || c == '-' || c == '=' || c == '"') x1
|
||||||
|
|
||||||
cmd = case [x | (x,cs) <- RP.readP_to_S pCommand x2, all isSpace cs] of
|
cmd = case [x | (x,cs) <- RP.readP_to_S pCommand x2, all isSpace cs] of
|
||||||
[x] -> Just x
|
[x] -> Just x
|
||||||
_ -> Nothing
|
_ -> Nothing
|
||||||
|
|
||||||
isIdent c = c == '_' || c == '\'' || isAlphaNum c
|
isIdent c = c == '_' || c == '\'' || isAlphaNum c
|
||||||
|
|||||||
442
src/compiler/GF/Interactive2.hs
Normal file
442
src/compiler/GF/Interactive2.hs
Normal file
@@ -0,0 +1,442 @@
|
|||||||
|
{-# LANGUAGE CPP, ScopedTypeVariables, TypeSynonymInstances, FlexibleInstances, FlexibleContexts #-}
|
||||||
|
-- | GF interactive mode (with the C run-time system)
|
||||||
|
module GF.Interactive2 (mainGFI,mainRunGFI{-,mainServerGFI-}) where
|
||||||
|
import Prelude hiding (putStrLn,print)
|
||||||
|
import qualified Prelude as P(putStrLn)
|
||||||
|
import GF.Command.Interpreter(CommandEnv(..),commands,mkCommandEnv,interpretCommandLine)
|
||||||
|
import GF.Command.Commands2(PGFEnv,HasPGFEnv(..),pgf,concs,pgfEnv,emptyPGFEnv,pgfCommands)
|
||||||
|
import GF.Command.CommonCommands
|
||||||
|
import GF.Command.CommandInfo
|
||||||
|
import GF.Command.Help(helpCommand)
|
||||||
|
import GF.Command.Abstract
|
||||||
|
import GF.Command.Parse(readCommandLine,pCommand)
|
||||||
|
import GF.Data.Operations (Err(..))
|
||||||
|
import GF.Data.Utilities(whenM,repeatM)
|
||||||
|
|
||||||
|
import GF.Infra.UseIO(ioErrorText,putStrLnE)
|
||||||
|
import GF.Infra.SIO
|
||||||
|
import GF.Infra.Option
|
||||||
|
import qualified System.Console.Haskeline as Haskeline
|
||||||
|
|
||||||
|
import qualified PGF2 as C
|
||||||
|
import qualified PGF as H
|
||||||
|
|
||||||
|
import Data.Char
|
||||||
|
import Data.List(isPrefixOf)
|
||||||
|
import qualified Data.Map as Map
|
||||||
|
|
||||||
|
import qualified Text.ParserCombinators.ReadP as RP
|
||||||
|
--import System.IO(utf8)
|
||||||
|
--import System.CPUTime(getCPUTime)
|
||||||
|
import System.Directory({-getCurrentDirectory,-}getAppUserDataDirectory)
|
||||||
|
import System.FilePath(takeExtensions)
|
||||||
|
import Control.Exception(SomeException,fromException,try)
|
||||||
|
--import Control.Monad
|
||||||
|
import Control.Monad.State hiding (void)
|
||||||
|
|
||||||
|
import qualified GF.System.Signal as IO(runInterruptibly)
|
||||||
|
{-
|
||||||
|
#ifdef SERVER_MODE
|
||||||
|
import GF.Server(server)
|
||||||
|
#endif
|
||||||
|
-}
|
||||||
|
|
||||||
|
import GF.Command.Messages(welcome)
|
||||||
|
|
||||||
|
-- | Run the GF Shell in quiet mode (@gf -run@).
|
||||||
|
mainRunGFI :: Options -> [FilePath] -> IO ()
|
||||||
|
mainRunGFI opts files = shell (beQuiet opts) files
|
||||||
|
|
||||||
|
beQuiet = addOptions (modifyFlags (\f -> f{optVerbosity=Quiet}))
|
||||||
|
|
||||||
|
-- | Run the interactive GF Shell
|
||||||
|
mainGFI :: Options -> [FilePath] -> IO ()
|
||||||
|
mainGFI opts files = do
|
||||||
|
P.putStrLn welcome
|
||||||
|
P.putStrLn "This shell uses the C run-time system. See help for available commands."
|
||||||
|
shell opts files
|
||||||
|
|
||||||
|
shell opts files = flip evalStateT (emptyGFEnv opts) $
|
||||||
|
do mapStateT runSIO $ importInEnv opts files
|
||||||
|
loop
|
||||||
|
|
||||||
|
{-
|
||||||
|
#ifdef SERVER_MODE
|
||||||
|
-- | Run the GF Server (@gf -server@).
|
||||||
|
-- The 'Int' argument is the port number for the HTTP service.
|
||||||
|
mainServerGFI opts0 port files =
|
||||||
|
server jobs port root (execute1 opts)
|
||||||
|
=<< runSIO (importInEnv (emptyGFEnv opts) opts files)
|
||||||
|
where
|
||||||
|
root = flag optDocumentRoot opts
|
||||||
|
opts = beQuiet opts0
|
||||||
|
jobs = join (flag optJobs opts)
|
||||||
|
#else
|
||||||
|
mainServerGFI opts port files =
|
||||||
|
error "GF has not been compiled with server mode support"
|
||||||
|
#endif
|
||||||
|
-}
|
||||||
|
-- | Read end execute commands until it is time to quit
|
||||||
|
loop :: StateT GFEnv IO ()
|
||||||
|
loop = repeatM readAndExecute1
|
||||||
|
|
||||||
|
-- | Read and execute one command, returning 'True' to continue execution,
|
||||||
|
-- | 'False' when it is time to quit
|
||||||
|
readAndExecute1 :: StateT GFEnv IO Bool
|
||||||
|
readAndExecute1 = mapStateT runSIO . execute1 =<< readCommand
|
||||||
|
|
||||||
|
-- | Read a command
|
||||||
|
readCommand :: StateT GFEnv IO String
|
||||||
|
readCommand =
|
||||||
|
do opts <- gets startOpts
|
||||||
|
case flag optMode opts of
|
||||||
|
ModeRun -> lift tryGetLine
|
||||||
|
_ -> lift . fetchCommand =<< get
|
||||||
|
|
||||||
|
timeIt act =
|
||||||
|
do t1 <- liftSIO $ getCPUTime
|
||||||
|
a <- act
|
||||||
|
t2 <- liftSIO $ getCPUTime
|
||||||
|
return (t2-t1,a)
|
||||||
|
|
||||||
|
-- | Optionally show how much CPU time was used to run an IO action
|
||||||
|
optionallyShowCPUTime :: (Monad m,MonadSIO m) => Options -> m a -> m a
|
||||||
|
optionallyShowCPUTime opts act
|
||||||
|
| not (verbAtLeast opts Normal) = act
|
||||||
|
| otherwise = do (dt,r) <- timeIt act
|
||||||
|
liftSIO $ putStrLnFlush $ show (dt `div` 1000000000) ++ " msec"
|
||||||
|
return r
|
||||||
|
|
||||||
|
type ShellM = StateT GFEnv SIO
|
||||||
|
|
||||||
|
-- | Execute a given command line, returning 'True' to continue execution,
|
||||||
|
-- | 'False' when it is time to quit
|
||||||
|
execute1 :: String -> ShellM Bool
|
||||||
|
execute1 s0 =
|
||||||
|
do modify $ \ gfenv0 -> gfenv0 {history = s0 : history gfenv0}
|
||||||
|
execute1' s0
|
||||||
|
|
||||||
|
-- | Execute a given command line, without adding it to the history
|
||||||
|
execute1' s0 =
|
||||||
|
do opts <- gets startOpts
|
||||||
|
interruptible $ optionallyShowCPUTime opts $
|
||||||
|
case pwords s0 of
|
||||||
|
-- cc, sd, so, ss and dg are now in GF.Commands.SourceCommands
|
||||||
|
-- special commands
|
||||||
|
"q" :_ -> quit
|
||||||
|
"!" :ws -> system_command ws
|
||||||
|
"eh":ws -> execute_history ws
|
||||||
|
"i" :ws -> do import_ ws; continue
|
||||||
|
-- other special commands, working on GFEnv
|
||||||
|
"dc":ws -> define_command ws
|
||||||
|
"dt":ws -> define_tree ws
|
||||||
|
-- ordinary commands
|
||||||
|
_ -> do env <- gets commandenv
|
||||||
|
interpretCommandLine env s0
|
||||||
|
continue
|
||||||
|
where
|
||||||
|
continue,stop :: ShellM Bool
|
||||||
|
continue = return True
|
||||||
|
stop = return False
|
||||||
|
|
||||||
|
interruptible :: ShellM Bool -> ShellM Bool
|
||||||
|
interruptible act =
|
||||||
|
do gfenv <- get
|
||||||
|
mapStateT (
|
||||||
|
either (\e -> printException e >> return (True,gfenv)) return
|
||||||
|
<=< runInterruptibly) act
|
||||||
|
|
||||||
|
-- Special commands:
|
||||||
|
|
||||||
|
quit = do opts <- gets startOpts
|
||||||
|
when (verbAtLeast opts Normal) $ putStrLnE "See you."
|
||||||
|
stop
|
||||||
|
|
||||||
|
system_command ws = do lift $ restrictedSystem $ unwords ws ; continue
|
||||||
|
|
||||||
|
|
||||||
|
{-"eh":w:_ -> do
|
||||||
|
cs <- readFile w >>= return . map words . lines
|
||||||
|
gfenv' <- foldM (flip (process False benv)) gfenv cs
|
||||||
|
loopNewCPU gfenv' -}
|
||||||
|
execute_history [w] =
|
||||||
|
do execute . lines =<< lift (restricted (readFile w))
|
||||||
|
continue
|
||||||
|
where
|
||||||
|
execute :: [String] -> ShellM ()
|
||||||
|
execute [] = return ()
|
||||||
|
execute (line:lines) = whenM (execute1' line) (execute lines)
|
||||||
|
|
||||||
|
execute_history _ =
|
||||||
|
do putStrLnE "eh command not parsed"
|
||||||
|
continue
|
||||||
|
|
||||||
|
define_command (f:ws) =
|
||||||
|
case readCommandLine (unwords ws) of
|
||||||
|
Just comm ->
|
||||||
|
do modify $
|
||||||
|
\ gfenv ->
|
||||||
|
let env = commandenv gfenv
|
||||||
|
in gfenv {
|
||||||
|
commandenv = env {
|
||||||
|
commandmacros = Map.insert f comm (commandmacros env)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
_ -> dc_not_parsed
|
||||||
|
define_command _ = dc_not_parsed
|
||||||
|
|
||||||
|
dc_not_parsed = putStrLnE "command definition not parsed" >> continue
|
||||||
|
|
||||||
|
define_tree (f:ws) =
|
||||||
|
case H.readExpr (unwords ws) of
|
||||||
|
Just exp ->
|
||||||
|
do modify $
|
||||||
|
\ gfenv ->
|
||||||
|
let env = commandenv gfenv
|
||||||
|
in gfenv { commandenv = env {
|
||||||
|
expmacros = Map.insert f exp (expmacros env) } }
|
||||||
|
continue
|
||||||
|
_ -> dt_not_parsed
|
||||||
|
define_tree _ = dt_not_parsed
|
||||||
|
|
||||||
|
dt_not_parsed = putStrLnE "value definition not parsed" >> continue
|
||||||
|
|
||||||
|
pwords s = case words s of
|
||||||
|
w:ws -> getCommandOp w :ws
|
||||||
|
ws -> ws
|
||||||
|
import_ args =
|
||||||
|
do case parseOptions args of
|
||||||
|
Ok (opts',files) -> do
|
||||||
|
opts <- gets startOpts
|
||||||
|
curr_dir <- lift getCurrentDirectory
|
||||||
|
lib_dir <- lift $ getLibraryDirectory (addOptions opts opts')
|
||||||
|
importInEnv (addOptions opts (fixRelativeLibPaths curr_dir lib_dir opts')) files
|
||||||
|
Bad err ->
|
||||||
|
do putStrLnE $ "Command parse error: " ++ err
|
||||||
|
|
||||||
|
-- | Commands that work on 'GFEnv'
|
||||||
|
moreCommands = [
|
||||||
|
("e", emptyCommandInfo {
|
||||||
|
longname = "empty",
|
||||||
|
synopsis = "empty the environment (except the command history)",
|
||||||
|
exec = \ _ _ ->
|
||||||
|
do modify $ \ gfenv -> (emptyGFEnv (startOpts gfenv))
|
||||||
|
{ history=history gfenv }
|
||||||
|
return void
|
||||||
|
}),
|
||||||
|
("ph", emptyCommandInfo {
|
||||||
|
longname = "print_history",
|
||||||
|
synopsis = "print command history",
|
||||||
|
explanation = unlines [
|
||||||
|
"Prints the commands issued during the GF session.",
|
||||||
|
"The result is readable by the eh command.",
|
||||||
|
"The result can be used as a script when starting GF."
|
||||||
|
],
|
||||||
|
examples = [
|
||||||
|
mkEx "ph | wf -file=foo.gfs -- save the history into a file"
|
||||||
|
],
|
||||||
|
exec = \ _ _ ->
|
||||||
|
fmap (fromString . unlines . reverse . drop 1 . history) get
|
||||||
|
}),
|
||||||
|
("r", emptyCommandInfo {
|
||||||
|
longname = "reload",
|
||||||
|
synopsis = "repeat the latest import command",
|
||||||
|
exec = \ _ _ ->
|
||||||
|
do gfenv0 <- get
|
||||||
|
let imports = [(s,ws) | s <- history gfenv0, ("i":ws) <- [pwords s]]
|
||||||
|
case imports of
|
||||||
|
(s,ws):_ -> do
|
||||||
|
putStrLnE $ "repeating latest import: " ++ s
|
||||||
|
import_ ws
|
||||||
|
_ -> do
|
||||||
|
putStrLnE $ "no import in history"
|
||||||
|
return void
|
||||||
|
})
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
printException e = maybe (print e) (putStrLn . ioErrorText) (fromException e)
|
||||||
|
|
||||||
|
fetchCommand :: GFEnv -> IO String
|
||||||
|
fetchCommand gfenv = do
|
||||||
|
path <- getAppUserDataDirectory "gf_history"
|
||||||
|
let settings =
|
||||||
|
Haskeline.Settings {
|
||||||
|
Haskeline.complete = wordCompletion gfenv,
|
||||||
|
Haskeline.historyFile = Just path,
|
||||||
|
Haskeline.autoAddHistory = True
|
||||||
|
}
|
||||||
|
res <- IO.runInterruptibly $ Haskeline.runInputT settings (Haskeline.getInputLine (prompt gfenv))
|
||||||
|
case res of
|
||||||
|
Left _ -> return ""
|
||||||
|
Right Nothing -> return "q"
|
||||||
|
Right (Just s) -> return s
|
||||||
|
|
||||||
|
importInEnv :: Options -> [FilePath] -> ShellM ()
|
||||||
|
importInEnv opts files =
|
||||||
|
case files of
|
||||||
|
_ | flag optRetainResource opts ->
|
||||||
|
putStrLnE "Flag -retain is not supported in this shell"
|
||||||
|
[file] | takeExtensions file == ".pgf" -> importPGF file
|
||||||
|
[] -> return ()
|
||||||
|
_ -> do putStrLnE "Can only import one .pgf file"
|
||||||
|
where
|
||||||
|
importPGF file =
|
||||||
|
do gfenv <- get
|
||||||
|
case multigrammar gfenv of
|
||||||
|
Just _ -> putStrLnE "Discarding previous grammar"
|
||||||
|
_ -> return ()
|
||||||
|
pgf1 <- lift $ readPGF2 file
|
||||||
|
let gfenv' = gfenv { pgfenv = pgfEnv pgf1 }
|
||||||
|
when (verbAtLeast opts Normal) $
|
||||||
|
let langs = Map.keys . concretes $ gfenv'
|
||||||
|
in putStrLnE . unwords $ "\nLanguages:":langs
|
||||||
|
put gfenv'
|
||||||
|
|
||||||
|
tryGetLine = do
|
||||||
|
res <- try getLine
|
||||||
|
case res of
|
||||||
|
Left (e :: SomeException) -> return "q"
|
||||||
|
Right l -> return l
|
||||||
|
|
||||||
|
prompt env = abs ++ "> "
|
||||||
|
where
|
||||||
|
abs = maybe "" C.abstractName (multigrammar env)
|
||||||
|
|
||||||
|
data GFEnv = GFEnv {
|
||||||
|
startOpts :: Options,
|
||||||
|
--grammar :: (), -- gfo grammar -retain
|
||||||
|
--retain :: (), -- grammar was imported with -retain flag
|
||||||
|
pgfenv :: PGFEnv,
|
||||||
|
commandenv :: CommandEnv ShellM,
|
||||||
|
history :: [String]
|
||||||
|
}
|
||||||
|
|
||||||
|
emptyGFEnv opts = GFEnv opts {-() ()-} emptyPGFEnv emptyCommandEnv []
|
||||||
|
|
||||||
|
emptyCommandEnv = mkCommandEnv allCommands
|
||||||
|
multigrammar = pgf . pgfenv
|
||||||
|
concretes = concs . pgfenv
|
||||||
|
|
||||||
|
allCommands =
|
||||||
|
extend pgfCommands (helpCommand allCommands:moreCommands)
|
||||||
|
`Map.union` commonCommands
|
||||||
|
|
||||||
|
instance HasPGFEnv ShellM where getPGFEnv = gets pgfenv
|
||||||
|
|
||||||
|
-- ** Completion
|
||||||
|
|
||||||
|
wordCompletion gfenv (left,right) = do
|
||||||
|
case wc_type (reverse left) of
|
||||||
|
CmplCmd pref
|
||||||
|
-> ret (length pref) [Haskeline.simpleCompletion name | name <- Map.keys (commands cmdEnv), isPrefixOf pref name]
|
||||||
|
{-
|
||||||
|
CmplStr (Just (Command _ opts _)) s0
|
||||||
|
-> do mb_state0 <- try (evaluate (H.initState pgf (optLang opts) (optType opts)))
|
||||||
|
case mb_state0 of
|
||||||
|
Right state0 -> let (rprefix,rs) = break isSpace (reverse s0)
|
||||||
|
s = reverse rs
|
||||||
|
prefix = reverse rprefix
|
||||||
|
ws = words s
|
||||||
|
in case loop state0 ws of
|
||||||
|
Nothing -> ret 0 []
|
||||||
|
Just state -> let compls = H.getCompletions state prefix
|
||||||
|
in ret (length prefix) (map (\x -> Haskeline.simpleCompletion x) (Map.keys compls))
|
||||||
|
Left (_ :: SomeException) -> ret 0 []
|
||||||
|
-}
|
||||||
|
CmplOpt (Just (Command n _ _)) pref
|
||||||
|
-> case Map.lookup n (commands cmdEnv) of
|
||||||
|
Just inf -> do let flg_compls = [Haskeline.Completion ('-':flg++"=") ('-':flg) False | (flg,_) <- flags inf, isPrefixOf pref flg]
|
||||||
|
opt_compls = [Haskeline.Completion ('-':opt) ('-':opt) True | (opt,_) <- options inf, isPrefixOf pref opt]
|
||||||
|
ret (length pref+1)
|
||||||
|
(flg_compls++opt_compls)
|
||||||
|
Nothing -> ret (length pref) []
|
||||||
|
CmplIdent (Just (Command "i" _ _)) _ -- HACK: file name completion for command i
|
||||||
|
-> Haskeline.completeFilename (left,right)
|
||||||
|
|
||||||
|
CmplIdent _ pref
|
||||||
|
-> case mb_pgf of
|
||||||
|
Just pgf -> ret (length pref)
|
||||||
|
[Haskeline.simpleCompletion name
|
||||||
|
| name <- C.functions pgf,
|
||||||
|
isPrefixOf pref name]
|
||||||
|
_ -> ret (length pref) []
|
||||||
|
|
||||||
|
_ -> ret 0 []
|
||||||
|
where
|
||||||
|
mb_pgf = multigrammar gfenv
|
||||||
|
cmdEnv = commandenv gfenv
|
||||||
|
{-
|
||||||
|
optLang opts = valStrOpts "lang" (head $ Map.keys (concretes cmdEnv)) opts
|
||||||
|
optType opts =
|
||||||
|
let str = valStrOpts "cat" (H.showCId $ H.lookStartCat pgf) opts
|
||||||
|
in case H.readType str of
|
||||||
|
Just ty -> ty
|
||||||
|
Nothing -> error ("Can't parse '"++str++"' as type")
|
||||||
|
|
||||||
|
loop ps [] = Just ps
|
||||||
|
loop ps (t:ts) = case H.nextState ps (H.simpleParseInput t) of
|
||||||
|
Left es -> Nothing
|
||||||
|
Right ps -> loop ps ts
|
||||||
|
-}
|
||||||
|
ret len xs = return (drop len left,xs)
|
||||||
|
|
||||||
|
|
||||||
|
data CompletionType
|
||||||
|
= CmplCmd Ident
|
||||||
|
| CmplStr (Maybe Command) String
|
||||||
|
| CmplOpt (Maybe Command) Ident
|
||||||
|
| CmplIdent (Maybe Command) Ident
|
||||||
|
deriving Show
|
||||||
|
|
||||||
|
wc_type :: String -> CompletionType
|
||||||
|
wc_type = cmd_name
|
||||||
|
where
|
||||||
|
cmd_name cs =
|
||||||
|
let cs1 = dropWhile isSpace cs
|
||||||
|
in go cs1 cs1
|
||||||
|
where
|
||||||
|
go x [] = CmplCmd x
|
||||||
|
go x (c:cs)
|
||||||
|
| isIdent c = go x cs
|
||||||
|
| otherwise = cmd x cs
|
||||||
|
|
||||||
|
cmd x [] = ret CmplIdent x "" 0
|
||||||
|
cmd _ ('|':cs) = cmd_name cs
|
||||||
|
cmd _ (';':cs) = cmd_name cs
|
||||||
|
cmd x ('"':cs) = str x cs cs
|
||||||
|
cmd x ('-':cs) = option x cs cs
|
||||||
|
cmd x (c :cs)
|
||||||
|
| isIdent c = ident x (c:cs) cs
|
||||||
|
| otherwise = cmd x cs
|
||||||
|
|
||||||
|
option x y [] = ret CmplOpt x y 1
|
||||||
|
option x y ('=':cs) = optValue x y cs
|
||||||
|
option x y (c :cs)
|
||||||
|
| isIdent c = option x y cs
|
||||||
|
| otherwise = cmd x cs
|
||||||
|
|
||||||
|
optValue x y ('"':cs) = str x y cs
|
||||||
|
optValue x y cs = cmd x cs
|
||||||
|
|
||||||
|
ident x y [] = ret CmplIdent x y 0
|
||||||
|
ident x y (c:cs)
|
||||||
|
| isIdent c = ident x y cs
|
||||||
|
| otherwise = cmd x cs
|
||||||
|
|
||||||
|
str x y [] = ret CmplStr x y 1
|
||||||
|
str x y ('\"':cs) = cmd x cs
|
||||||
|
str x y ('\\':c:cs) = str x y cs
|
||||||
|
str x y (c:cs) = str x y cs
|
||||||
|
|
||||||
|
ret f x y d = f cmd y
|
||||||
|
where
|
||||||
|
x1 = take (length x - length y - d) x
|
||||||
|
x2 = takeWhile (\c -> isIdent c || isSpace c || c == '-' || c == '=' || c == '"') x1
|
||||||
|
|
||||||
|
cmd = case [x | (x,cs) <- RP.readP_to_S pCommand x2, all isSpace cs] of
|
||||||
|
[x] -> Just x
|
||||||
|
_ -> Nothing
|
||||||
|
|
||||||
|
isIdent c = c == '_' || c == '\'' || isAlphaNum c
|
||||||
@@ -2,7 +2,10 @@
|
|||||||
{-# LANGUAGE CPP #-}
|
{-# LANGUAGE CPP #-}
|
||||||
module GF.Main where
|
module GF.Main where
|
||||||
import GF.Compiler
|
import GF.Compiler
|
||||||
import GF.Interactive
|
import qualified GF.Interactive as GFI1
|
||||||
|
#ifdef C_RUNTIME
|
||||||
|
import qualified GF.Interactive2 as GFI2
|
||||||
|
#endif
|
||||||
import GF.Data.ErrM
|
import GF.Data.ErrM
|
||||||
import GF.Infra.Option
|
import GF.Infra.Option
|
||||||
import GF.Infra.UseIO
|
import GF.Infra.UseIO
|
||||||
@@ -13,19 +16,18 @@ import Data.Version
|
|||||||
import System.Directory
|
import System.Directory
|
||||||
import System.Environment (getArgs)
|
import System.Environment (getArgs)
|
||||||
import System.Exit
|
import System.Exit
|
||||||
-- import GF.System.Console (setConsoleEncoding)
|
import GF.System.Console (setConsoleEncoding)
|
||||||
|
|
||||||
-- | Run the GF main program, taking arguments from the command line.
|
-- | Run the GF main program, taking arguments from the command line.
|
||||||
-- (It calls 'setConsoleEncoding' and 'getOptions', then 'mainOpts'.)
|
-- (It calls 'setConsoleEncoding' and 'getOptions', then 'mainOpts'.)
|
||||||
-- Run @gf --help@ for usage info.
|
-- Run @gf --help@ for usage info.
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = do
|
main = do
|
||||||
-- setConsoleEncoding
|
--setConsoleEncoding
|
||||||
uncurry mainOpts =<< getOptions
|
uncurry mainOpts =<< getOptions
|
||||||
|
|
||||||
-- | Get and parse GF command line arguments. Fix relative paths.
|
-- | Get and parse GF command line arguments. Fix relative paths.
|
||||||
-- Calls 'getArgs' and 'parseOptions'.
|
-- Calls 'getArgs' and 'parseOptions'.
|
||||||
getOptions :: IO (Options, [FilePath])
|
|
||||||
getOptions = do
|
getOptions = do
|
||||||
args <- getArgs
|
args <- getArgs
|
||||||
case parseOptions args of
|
case parseOptions args of
|
||||||
@@ -41,11 +43,21 @@ getOptions = do
|
|||||||
-- the options it invokes 'mainGFC', 'mainGFI', 'mainRunGFI', 'mainServerGFI',
|
-- the options it invokes 'mainGFC', 'mainGFI', 'mainRunGFI', 'mainServerGFI',
|
||||||
-- or it just prints version/usage info.
|
-- or it just prints version/usage info.
|
||||||
mainOpts :: Options -> [FilePath] -> IO ()
|
mainOpts :: Options -> [FilePath] -> IO ()
|
||||||
mainOpts opts files =
|
mainOpts opts files =
|
||||||
case flag optMode opts of
|
case flag optMode opts of
|
||||||
ModeVersion -> putStrLn $ "Grammatical Framework (GF) version " ++ showVersion version ++ "\n" ++ buildInfo
|
ModeVersion -> putStrLn $ "Grammatical Framework (GF) version " ++ showVersion version ++ "\n" ++ buildInfo
|
||||||
ModeHelp -> putStrLn helpMessage
|
ModeHelp -> putStrLn helpMessage
|
||||||
ModeServer port -> mainServerGFI opts port files
|
ModeServer port -> GFI1.mainServerGFI opts port files
|
||||||
ModeCompiler -> mainGFC opts files
|
ModeCompiler -> mainGFC opts files
|
||||||
ModeInteractive -> mainGFI opts files
|
ModeInteractive -> GFI1.mainGFI opts files
|
||||||
ModeRun -> mainRunGFI opts files
|
ModeRun -> GFI1.mainRunGFI opts files
|
||||||
|
#ifdef C_RUNTIME
|
||||||
|
ModeInteractive2 -> GFI2.mainGFI opts files
|
||||||
|
ModeRun2 -> GFI2.mainRunGFI opts files
|
||||||
|
#else
|
||||||
|
ModeInteractive2 -> noCruntime
|
||||||
|
ModeRun2 -> noCruntime
|
||||||
|
where
|
||||||
|
noCruntime = do ePutStrLn "GF configured without C run-time support"
|
||||||
|
exitFailure
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -18,8 +18,13 @@ module GF.Quiz (
|
|||||||
morphologyList
|
morphologyList
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import PGF2
|
import PGF
|
||||||
|
--import PGF.Linearize
|
||||||
import GF.Data.Operations
|
import GF.Data.Operations
|
||||||
|
--import GF.Infra.UseIO
|
||||||
|
--import GF.Infra.Option
|
||||||
|
--import PGF.Probabilistic
|
||||||
|
|
||||||
import System.Random
|
import System.Random
|
||||||
import Data.List (nub)
|
import Data.List (nub)
|
||||||
|
|
||||||
@@ -33,7 +38,7 @@ mkQuiz msg tts = do
|
|||||||
teachDialogue qas msg
|
teachDialogue qas msg
|
||||||
|
|
||||||
translationList ::
|
translationList ::
|
||||||
Maybe Expr -> PGF -> Concr -> Concr -> Type -> Int -> IO [(String,[String])]
|
Maybe Expr -> PGF -> Language -> Language -> Type -> Int -> IO [(String,[String])]
|
||||||
translationList mex pgf ig og typ number = do
|
translationList mex pgf ig og typ number = do
|
||||||
gen <- newStdGen
|
gen <- newStdGen
|
||||||
let ts = take number $ case mex of
|
let ts = take number $ case mex of
|
||||||
@@ -41,22 +46,19 @@ translationList mex pgf ig og typ number = do
|
|||||||
Nothing -> generateRandom gen pgf typ
|
Nothing -> generateRandom gen pgf typ
|
||||||
return $ map mkOne $ ts
|
return $ map mkOne $ ts
|
||||||
where
|
where
|
||||||
mkOne t = (norml (linearize ig t),
|
mkOne t = (norml (linearize pgf ig t),
|
||||||
map norml (concatMap lins (homonyms t)))
|
map norml (concatMap lins (homonyms t)))
|
||||||
homonyms t =
|
homonyms = parse pgf ig typ . linearize pgf ig
|
||||||
case (parse ig typ . linearize ig) t of
|
lins = nub . concatMap (map snd) . tabularLinearizes pgf og
|
||||||
ParseOk res -> map fst res
|
|
||||||
_ -> []
|
|
||||||
lins = nub . concatMap (map snd) . tabularLinearizeAll og
|
|
||||||
|
|
||||||
morphologyList ::
|
morphologyList ::
|
||||||
Maybe Expr -> PGF -> Concr -> Type -> Int -> IO [(String,[String])]
|
Maybe Expr -> PGF -> Language -> Type -> Int -> IO [(String,[String])]
|
||||||
morphologyList mex pgf ig typ number = do
|
morphologyList mex pgf ig typ number = do
|
||||||
gen <- newStdGen
|
gen <- newStdGen
|
||||||
let ts = take (max 1 number) $ case mex of
|
let ts = take (max 1 number) $ case mex of
|
||||||
Just ex -> generateRandomFrom gen pgf ex
|
Just ex -> generateRandomFrom gen pgf ex
|
||||||
Nothing -> generateRandom gen pgf typ
|
Nothing -> generateRandom gen pgf typ
|
||||||
let ss = map (tabularLinearizeAll ig) ts
|
let ss = map (tabularLinearizes pgf ig) ts
|
||||||
let size = length (head (head ss))
|
let size = length (head (head ss))
|
||||||
let forms = take number $ randomRs (0,size-1) gen
|
let forms = take number $ randomRs (0,size-1) gen
|
||||||
return [(snd (head pws0) +++ fst (pws0 !! i), ws) |
|
return [(snd (head pws0) +++ fst (pws0 !! i), ws) |
|
||||||
|
|||||||
@@ -3,9 +3,10 @@
|
|||||||
module GF.Server(server) where
|
module GF.Server(server) where
|
||||||
import Data.List(partition,stripPrefix,isInfixOf)
|
import Data.List(partition,stripPrefix,isInfixOf)
|
||||||
import qualified Data.Map as M
|
import qualified Data.Map as M
|
||||||
|
import Control.Applicative -- for GHC<7.10
|
||||||
import Control.Monad(when)
|
import Control.Monad(when)
|
||||||
import Control.Monad.State(StateT(..),get,gets,put)
|
import Control.Monad.State(StateT(..),get,gets,put)
|
||||||
import Control.Monad.Except(ExceptT(..),runExceptT)
|
import Control.Monad.Error(ErrorT(..),Error(..))
|
||||||
import System.Random(randomRIO)
|
import System.Random(randomRIO)
|
||||||
--import System.IO(stderr,hPutStrLn)
|
--import System.IO(stderr,hPutStrLn)
|
||||||
import GF.System.Catch(try)
|
import GF.System.Catch(try)
|
||||||
@@ -33,7 +34,7 @@ import Network.Shed.Httpd(initServer,Request(..),Response(..),noCache)
|
|||||||
--import qualified Network.FastCGI as FCGI -- from hackage direct-fastcgi
|
--import qualified Network.FastCGI as FCGI -- from hackage direct-fastcgi
|
||||||
import Network.CGI(handleErrors,liftIO)
|
import Network.CGI(handleErrors,liftIO)
|
||||||
import CGIUtils(handleCGIErrors)--,outputJSONP,stderrToFile
|
import CGIUtils(handleCGIErrors)--,outputJSONP,stderrToFile
|
||||||
import Text.JSON(encode,showJSON,makeObj)
|
import Text.JSON(JSValue(..),Result(..),valFromObj,encode,decode,showJSON,makeObj)
|
||||||
--import System.IO.Silently(hCapture)
|
--import System.IO.Silently(hCapture)
|
||||||
import System.Process(readProcessWithExitCode)
|
import System.Process(readProcessWithExitCode)
|
||||||
import System.Exit(ExitCode(..))
|
import System.Exit(ExitCode(..))
|
||||||
@@ -42,6 +43,7 @@ import GF.Infra.UseIO(readBinaryFile,writeBinaryFile,ePutStrLn)
|
|||||||
import GF.Infra.SIO(captureSIO)
|
import GF.Infra.SIO(captureSIO)
|
||||||
import GF.Data.Utilities(apSnd,mapSnd)
|
import GF.Data.Utilities(apSnd,mapSnd)
|
||||||
import qualified PGFService as PS
|
import qualified PGFService as PS
|
||||||
|
import qualified ExampleService as ES
|
||||||
import Data.Version(showVersion)
|
import Data.Version(showVersion)
|
||||||
import Paths_gf(getDataDir,version)
|
import Paths_gf(getDataDir,version)
|
||||||
import GF.Infra.BuildInfo (buildInfo)
|
import GF.Infra.BuildInfo (buildInfo)
|
||||||
@@ -106,9 +108,9 @@ handle_fcgi execute1 state0 stateM cache =
|
|||||||
|
|
||||||
-- * Request handler
|
-- * Request handler
|
||||||
-- | Handler monad
|
-- | Handler monad
|
||||||
type HM s a = StateT (Q,s) (ExceptT Response IO) a
|
type HM s a = StateT (Q,s) (ErrorT Response IO) a
|
||||||
run :: HM s Response -> (Q,s) -> IO (s,Response)
|
run :: HM s Response -> (Q,s) -> IO (s,Response)
|
||||||
run m s = either bad ok =<< runExceptT (runStateT m s)
|
run m s = either bad ok =<< runErrorT (runStateT m s)
|
||||||
where
|
where
|
||||||
bad resp = return (snd s,resp)
|
bad resp = return (snd s,resp)
|
||||||
ok (resp,(qs,state)) = return (state,resp)
|
ok (resp,(qs,state)) = return (state,resp)
|
||||||
@@ -121,12 +123,12 @@ put_qs qs = do state <- get_state; put (qs,state)
|
|||||||
put_state state = do qs <- get_qs; put (qs,state)
|
put_state state = do qs <- get_qs; put (qs,state)
|
||||||
|
|
||||||
err :: Response -> HM s a
|
err :: Response -> HM s a
|
||||||
err e = StateT $ \ s -> ExceptT $ return $ Left e
|
err e = StateT $ \ s -> ErrorT $ return $ Left e
|
||||||
|
|
||||||
hmbracket_ :: IO () -> IO () -> HM s a -> HM s a
|
hmbracket_ :: IO () -> IO () -> HM s a -> HM s a
|
||||||
hmbracket_ pre post m =
|
hmbracket_ pre post m =
|
||||||
do s <- get
|
do s <- get
|
||||||
e <- liftIO $ bracket_ pre post $ runExceptT $ runStateT m s
|
e <- liftIO $ bracket_ pre post $ runErrorT $ runStateT m s
|
||||||
case e of
|
case e of
|
||||||
Left resp -> err resp
|
Left resp -> err resp
|
||||||
Right (a,s) -> do put s;return a
|
Right (a,s) -> do put s;return a
|
||||||
@@ -169,6 +171,7 @@ handle logLn documentroot state0 cache execute1 stateVar
|
|||||||
(_ ,_ ,".pgf") -> do --debug $ "PGF service: "++path
|
(_ ,_ ,".pgf") -> do --debug $ "PGF service: "++path
|
||||||
wrapCGI $ PS.cgiMain' cache path
|
wrapCGI $ PS.cgiMain' cache path
|
||||||
(dir,"grammars.cgi",_ ) -> grammarList dir (decoded qs)
|
(dir,"grammars.cgi",_ ) -> grammarList dir (decoded qs)
|
||||||
|
(dir ,"exb.fcgi" ,_ ) -> wrapCGI $ ES.cgiMain' root dir (PS.pgfCache cache)
|
||||||
_ -> serveStaticFile rpath path
|
_ -> serveStaticFile rpath path
|
||||||
where path = translatePath rpath
|
where path = translatePath rpath
|
||||||
_ -> return $ resp400 upath
|
_ -> return $ resp400 upath
|
||||||
@@ -177,7 +180,7 @@ handle logLn documentroot state0 cache execute1 stateVar
|
|||||||
|
|
||||||
translatePath rpath = root</>rpath -- hmm, check for ".."
|
translatePath rpath = root</>rpath -- hmm, check for ".."
|
||||||
|
|
||||||
versionInfo c =
|
versionInfo (c1,c2) =
|
||||||
html200 . unlines $
|
html200 . unlines $
|
||||||
"<!DOCTYPE html>":
|
"<!DOCTYPE html>":
|
||||||
"<meta name = \"viewport\" content = \"width = device-width\">":
|
"<meta name = \"viewport\" content = \"width = device-width\">":
|
||||||
@@ -185,7 +188,8 @@ handle logLn documentroot state0 cache execute1 stateVar
|
|||||||
"":
|
"":
|
||||||
("<h2>"++hdr++"</h2>"):
|
("<h2>"++hdr++"</h2>"):
|
||||||
(zipWith (++) ("<p>":repeat "<br>") buildinfo)++
|
(zipWith (++) ("<p>":repeat "<br>") buildinfo)++
|
||||||
sh "Run-time system" c
|
sh "Haskell run-time system" c1++
|
||||||
|
sh "C run-time system" c2
|
||||||
where
|
where
|
||||||
hdr:buildinfo = lines gf_version
|
hdr:buildinfo = lines gf_version
|
||||||
rel = makeRelative documentroot
|
rel = makeRelative documentroot
|
||||||
@@ -280,13 +284,17 @@ handle logLn documentroot state0 cache execute1 stateVar
|
|||||||
skip_empty = filter (not.null.snd)
|
skip_empty = filter (not.null.snd)
|
||||||
|
|
||||||
jsonList = jsonList' return
|
jsonList = jsonList' return
|
||||||
jsonListLong = jsonList' (mapM addTime)
|
jsonListLong ext = jsonList' (mapM (addTime ext)) ext
|
||||||
jsonList' details ext = fmap (json200) (details =<< ls_ext "." ext)
|
jsonList' details ext = fmap (json200) (details =<< ls_ext "." ext)
|
||||||
|
|
||||||
addTime path =
|
addTime ext path =
|
||||||
do t <- getModificationTime path
|
do t <- getModificationTime path
|
||||||
return $ makeObj ["path".=path,"time".=format t]
|
if ext==".json"
|
||||||
|
then addComment (time t) <$> liftIO (try $ getComment path)
|
||||||
|
else return . makeObj $ time t
|
||||||
where
|
where
|
||||||
|
addComment t = makeObj . either (const t) (\c->t++["comment".=c])
|
||||||
|
time t = ["path".=path,"time".=format t]
|
||||||
format = formatTime defaultTimeLocale rfc822DateFormat
|
format = formatTime defaultTimeLocale rfc822DateFormat
|
||||||
|
|
||||||
rm path | takeExtension path `elem` ok_to_delete =
|
rm path | takeExtension path `elem` ok_to_delete =
|
||||||
@@ -328,6 +336,11 @@ handle logLn documentroot state0 cache execute1 stateVar
|
|||||||
do paths <- getDirectoryContents dir
|
do paths <- getDirectoryContents dir
|
||||||
return [path | path<-paths, takeExtension path==ext]
|
return [path | path<-paths, takeExtension path==ext]
|
||||||
|
|
||||||
|
getComment path =
|
||||||
|
do Ok (JSObject obj) <- decode <$> readFile path
|
||||||
|
Ok cmnt <- return (valFromObj "comment" obj)
|
||||||
|
return (cmnt::String)
|
||||||
|
|
||||||
-- * Dynamic content
|
-- * Dynamic content
|
||||||
|
|
||||||
jsonresult cwd dir cmd (ecode,stdout,stderr) files =
|
jsonresult cwd dir cmd (ecode,stdout,stderr) files =
|
||||||
@@ -394,6 +407,9 @@ resp404 path = Response 404 [plain,xo] $ "Not found: "++path++"\n"
|
|||||||
resp500 msg = Response 500 [plain,xo] $ "Internal error: "++msg++"\n"
|
resp500 msg = Response 500 [plain,xo] $ "Internal error: "++msg++"\n"
|
||||||
resp501 msg = Response 501 [plain,xo] $ "Not implemented: "++msg++"\n"
|
resp501 msg = Response 501 [plain,xo] $ "Not implemented: "++msg++"\n"
|
||||||
|
|
||||||
|
instance Error Response where
|
||||||
|
noMsg = resp500 "no message"
|
||||||
|
strMsg = resp500
|
||||||
|
|
||||||
-- * Content types
|
-- * Content types
|
||||||
plain = ct "text/plain" ""
|
plain = ct "text/plain" ""
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import qualified Data.Map as Map
|
|||||||
import Data.Set (Set)
|
import Data.Set (Set)
|
||||||
import qualified Data.Set as Set
|
import qualified Data.Set as Set
|
||||||
|
|
||||||
|
import PGF.Internal
|
||||||
import GF.Data.Utilities
|
import GF.Data.Utilities
|
||||||
import GF.Grammar.CFG
|
import GF.Grammar.CFG
|
||||||
--import GF.Speech.PGFToCFG
|
--import GF.Speech.PGFToCFG
|
||||||
|
|||||||
@@ -5,37 +5,37 @@
|
|||||||
-- Stability : (stable)
|
-- Stability : (stable)
|
||||||
-- Portability : (portable)
|
-- Portability : (portable)
|
||||||
--
|
--
|
||||||
-- > CVS $Date: 2005/11/10 16:43:44 $
|
-- > CVS $Date: 2005/11/10 16:43:44 $
|
||||||
-- > CVS $Author: bringert $
|
-- > CVS $Author: bringert $
|
||||||
-- > CVS $Revision: 1.16 $
|
-- > CVS $Revision: 1.16 $
|
||||||
--
|
--
|
||||||
-- A simple finite state network module.
|
-- A simple finite state network module.
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
module GF.Speech.FiniteState (FA(..), State, NFA, DFA,
|
module GF.Speech.FiniteState (FA(..), State, NFA, DFA,
|
||||||
startState, finalStates,
|
startState, finalStates,
|
||||||
states, transitions,
|
states, transitions,
|
||||||
isInternal,
|
isInternal,
|
||||||
newFA, newFA_,
|
newFA, newFA_,
|
||||||
addFinalState,
|
addFinalState,
|
||||||
newState, newStates,
|
newState, newStates,
|
||||||
newTransition, newTransitions,
|
newTransition, newTransitions,
|
||||||
insertTransitionWith, insertTransitionsWith,
|
insertTransitionWith, insertTransitionsWith,
|
||||||
mapStates, mapTransitions,
|
mapStates, mapTransitions,
|
||||||
modifyTransitions,
|
modifyTransitions,
|
||||||
nonLoopTransitionsTo, nonLoopTransitionsFrom,
|
nonLoopTransitionsTo, nonLoopTransitionsFrom,
|
||||||
loops,
|
loops,
|
||||||
removeState,
|
removeState,
|
||||||
oneFinalState,
|
oneFinalState,
|
||||||
insertNFA,
|
insertNFA,
|
||||||
onGraph,
|
onGraph,
|
||||||
moveLabelsToNodes, removeTrivialEmptyNodes,
|
moveLabelsToNodes, removeTrivialEmptyNodes,
|
||||||
minimize,
|
minimize,
|
||||||
dfa2nfa,
|
dfa2nfa,
|
||||||
unusedNames, renameStates,
|
unusedNames, renameStates,
|
||||||
prFAGraphviz, faToGraphviz) where
|
prFAGraphviz, faToGraphviz) where
|
||||||
|
|
||||||
import Data.List
|
import Data.List
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
--import Data.Map (Map)
|
--import Data.Map (Map)
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
import Data.Set (Set)
|
import Data.Set (Set)
|
||||||
@@ -98,13 +98,13 @@ newTransition f t l = onGraph (newEdge (f,t,l))
|
|||||||
newTransitions :: [(n, n, b)] -> FA n a b -> FA n a b
|
newTransitions :: [(n, n, b)] -> FA n a b -> FA n a b
|
||||||
newTransitions es = onGraph (newEdges es)
|
newTransitions es = onGraph (newEdges es)
|
||||||
|
|
||||||
insertTransitionWith :: Eq n =>
|
insertTransitionWith :: Eq n =>
|
||||||
(b -> b -> b) -> (n, n, b) -> FA n a b -> FA n a b
|
(b -> b -> b) -> (n, n, b) -> FA n a b -> FA n a b
|
||||||
insertTransitionWith f t = onGraph (insertEdgeWith f t)
|
insertTransitionWith f t = onGraph (insertEdgeWith f t)
|
||||||
|
|
||||||
insertTransitionsWith :: Eq n =>
|
insertTransitionsWith :: Eq n =>
|
||||||
(b -> b -> b) -> [(n, n, b)] -> FA n a b -> FA n a b
|
(b -> b -> b) -> [(n, n, b)] -> FA n a b -> FA n a b
|
||||||
insertTransitionsWith f ts fa =
|
insertTransitionsWith f ts fa =
|
||||||
foldl' (flip (insertTransitionWith f)) fa ts
|
foldl' (flip (insertTransitionWith f)) fa ts
|
||||||
|
|
||||||
mapStates :: (a -> c) -> FA n a b -> FA n c b
|
mapStates :: (a -> c) -> FA n a b -> FA n c b
|
||||||
@@ -128,11 +128,11 @@ unusedNames (FA (Graph names _ _) _ _) = names
|
|||||||
-- | Gets all incoming transitions to a given state, excluding
|
-- | Gets all incoming transitions to a given state, excluding
|
||||||
-- transtions from the state itself.
|
-- transtions from the state itself.
|
||||||
nonLoopTransitionsTo :: Eq n => n -> FA n a b -> [(n,b)]
|
nonLoopTransitionsTo :: Eq n => n -> FA n a b -> [(n,b)]
|
||||||
nonLoopTransitionsTo s fa =
|
nonLoopTransitionsTo s fa =
|
||||||
[(f,l) | (f,t,l) <- transitions fa, t == s && f /= s]
|
[(f,l) | (f,t,l) <- transitions fa, t == s && f /= s]
|
||||||
|
|
||||||
nonLoopTransitionsFrom :: Eq n => n -> FA n a b -> [(n,b)]
|
nonLoopTransitionsFrom :: Eq n => n -> FA n a b -> [(n,b)]
|
||||||
nonLoopTransitionsFrom s fa =
|
nonLoopTransitionsFrom s fa =
|
||||||
[(t,l) | (f,t,l) <- transitions fa, f == s && t /= s]
|
[(t,l) | (f,t,l) <- transitions fa, f == s && t /= s]
|
||||||
|
|
||||||
loops :: Eq n => n -> FA n a b -> [b]
|
loops :: Eq n => n -> FA n a b -> [b]
|
||||||
@@ -145,7 +145,7 @@ renameStates :: Ord x => [y] -- ^ Infinite supply of new names
|
|||||||
renameStates supply (FA g s fs) = FA (renameNodes newName rest g) s' fs'
|
renameStates supply (FA g s fs) = FA (renameNodes newName rest g) s' fs'
|
||||||
where (ns,rest) = splitAt (length (nodes g)) supply
|
where (ns,rest) = splitAt (length (nodes g)) supply
|
||||||
newNodes = Map.fromList (zip (map fst (nodes g)) ns)
|
newNodes = Map.fromList (zip (map fst (nodes g)) ns)
|
||||||
newName n = Map.findWithDefault (error "FiniteState.newName") n newNodes
|
newName n = Map.findWithDefault (error "FiniteState.newName") n newNodes
|
||||||
s' = newName s
|
s' = newName s
|
||||||
fs' = map newName fs
|
fs' = map newName fs
|
||||||
|
|
||||||
@@ -154,9 +154,9 @@ insertNFA :: NFA a -- ^ NFA to insert into
|
|||||||
-> (State, State) -- ^ States to insert between
|
-> (State, State) -- ^ States to insert between
|
||||||
-> NFA a -- ^ NFA to insert.
|
-> NFA a -- ^ NFA to insert.
|
||||||
-> NFA a
|
-> NFA a
|
||||||
insertNFA (FA g1 s1 fs1) (f,t) (FA g2 s2 fs2)
|
insertNFA (FA g1 s1 fs1) (f,t) (FA g2 s2 fs2)
|
||||||
= FA (newEdges es g') s1 fs1
|
= FA (newEdges es g') s1 fs1
|
||||||
where
|
where
|
||||||
es = (f,ren s2,Nothing):[(ren f2,t,Nothing) | f2 <- fs2]
|
es = (f,ren s2,Nothing):[(ren f2,t,Nothing) | f2 <- fs2]
|
||||||
(g',ren) = mergeGraphs g1 g2
|
(g',ren) = mergeGraphs g1 g2
|
||||||
|
|
||||||
@@ -182,9 +182,9 @@ oneFinalState nl el fa =
|
|||||||
moveLabelsToNodes :: (Ord n,Eq a) => FA n () (Maybe a) -> FA n (Maybe a) ()
|
moveLabelsToNodes :: (Ord n,Eq a) => FA n () (Maybe a) -> FA n (Maybe a) ()
|
||||||
moveLabelsToNodes = onGraph f
|
moveLabelsToNodes = onGraph f
|
||||||
where f g@(Graph c _ _) = Graph c' ns (concat ess)
|
where f g@(Graph c _ _) = Graph c' ns (concat ess)
|
||||||
where is = [ ((n,l),inc) | (n, (l,inc,_)) <- Map.toList (nodeInfo g)]
|
where is = [ ((n,l),inc) | (n, (l,inc,_)) <- Map.toList (nodeInfo g)]
|
||||||
(c',is') = mapAccumL fixIncoming c is
|
(c',is') = mapAccumL fixIncoming c is
|
||||||
(ns,ess) = unzip (concat is')
|
(ns,ess) = unzip (concat is')
|
||||||
|
|
||||||
|
|
||||||
-- | Remove empty nodes which are not start or final, and have
|
-- | Remove empty nodes which are not start or final, and have
|
||||||
@@ -196,12 +196,12 @@ removeTrivialEmptyNodes = pruneUnusable . skipSimpleEmptyNodes
|
|||||||
-- This is not done if the pointed-to node is a final node.
|
-- This is not done if the pointed-to node is a final node.
|
||||||
skipSimpleEmptyNodes :: (Eq a, Ord n) => FA n (Maybe a) () -> FA n (Maybe a) ()
|
skipSimpleEmptyNodes :: (Eq a, Ord n) => FA n (Maybe a) () -> FA n (Maybe a) ()
|
||||||
skipSimpleEmptyNodes fa = onGraph og fa
|
skipSimpleEmptyNodes fa = onGraph og fa
|
||||||
where
|
where
|
||||||
og g@(Graph c ns es) = if es' == es then g else og (Graph c ns es')
|
og g@(Graph c ns es) = if es' == es then g else og (Graph c ns es')
|
||||||
where
|
where
|
||||||
es' = concatMap changeEdge es
|
es' = concatMap changeEdge es
|
||||||
info = nodeInfo g
|
info = nodeInfo g
|
||||||
changeEdge e@(f,t,())
|
changeEdge e@(f,t,())
|
||||||
| isNothing (getNodeLabel info t)
|
| isNothing (getNodeLabel info t)
|
||||||
-- && (i * o <= i + o)
|
-- && (i * o <= i + o)
|
||||||
&& not (isFinal fa t)
|
&& not (isFinal fa t)
|
||||||
@@ -223,28 +223,28 @@ pruneUnusable fa = onGraph f fa
|
|||||||
where
|
where
|
||||||
f g = if Set.null rns then g else f (removeNodes rns g)
|
f g = if Set.null rns then g else f (removeNodes rns g)
|
||||||
where info = nodeInfo g
|
where info = nodeInfo g
|
||||||
rns = Set.fromList [ n | (n,_) <- nodes g,
|
rns = Set.fromList [ n | (n,_) <- nodes g,
|
||||||
isInternal fa n,
|
isInternal fa n,
|
||||||
inDegree info n == 0
|
inDegree info n == 0
|
||||||
|| outDegree info n == 0]
|
|| outDegree info n == 0]
|
||||||
|
|
||||||
fixIncoming :: (Ord n, Eq a) => [n]
|
fixIncoming :: (Ord n, Eq a) => [n]
|
||||||
-> (Node n (),[Edge n (Maybe a)]) -- ^ A node and its incoming edges
|
-> (Node n (),[Edge n (Maybe a)]) -- ^ A node and its incoming edges
|
||||||
-> ([n],[(Node n (Maybe a),[Edge n ()])]) -- ^ Replacement nodes with their
|
-> ([n],[(Node n (Maybe a),[Edge n ()])]) -- ^ Replacement nodes with their
|
||||||
-- incoming edges.
|
-- incoming edges.
|
||||||
fixIncoming cs c@((n,()),es) = (cs'', ((n,Nothing),es'):newContexts)
|
fixIncoming cs c@((n,()),es) = (cs'', ((n,Nothing),es'):newContexts)
|
||||||
where ls = nub $ map edgeLabel es
|
where ls = nub $ map edgeLabel es
|
||||||
(cs',cs'') = splitAt (length ls) cs
|
(cs',cs'') = splitAt (length ls) cs
|
||||||
newNodes = zip cs' ls
|
newNodes = zip cs' ls
|
||||||
es' = [ (x,n,()) | x <- map fst newNodes ]
|
es' = [ (x,n,()) | x <- map fst newNodes ]
|
||||||
-- separate cyclic and non-cyclic edges
|
-- separate cyclic and non-cyclic edges
|
||||||
(cyc,ncyc) = partition (\ (f,_,_) -> f == n) es
|
(cyc,ncyc) = partition (\ (f,_,_) -> f == n) es
|
||||||
-- keep all incoming non-cyclic edges with the right label
|
-- keep all incoming non-cyclic edges with the right label
|
||||||
to (x,l) = [ (f,x,()) | (f,_,l') <- ncyc, l == l']
|
to (x,l) = [ (f,x,()) | (f,_,l') <- ncyc, l == l']
|
||||||
-- for each cyclic edge with the right label,
|
-- for each cyclic edge with the right label,
|
||||||
-- add an edge from each of the new nodes (including this one)
|
-- add an edge from each of the new nodes (including this one)
|
||||||
++ [ (y,x,()) | (f,_,l') <- cyc, l == l', (y,_) <- newNodes]
|
++ [ (y,x,()) | (f,_,l') <- cyc, l == l', (y,_) <- newNodes]
|
||||||
newContexts = [ (v, to v) | v <- newNodes ]
|
newContexts = [ (v, to v) | v <- newNodes ]
|
||||||
|
|
||||||
--alphabet :: Eq b => Graph n a (Maybe b) -> [b]
|
--alphabet :: Eq b => Graph n a (Maybe b) -> [b]
|
||||||
--alphabet = nub . catMaybes . map edgeLabel . edges
|
--alphabet = nub . catMaybes . map edgeLabel . edges
|
||||||
@@ -254,19 +254,19 @@ determinize (FA g s f) = let (ns,es) = h (Set.singleton start) Set.empty Set.emp
|
|||||||
(ns',es') = (Set.toList ns, Set.toList es)
|
(ns',es') = (Set.toList ns, Set.toList es)
|
||||||
final = filter isDFAFinal ns'
|
final = filter isDFAFinal ns'
|
||||||
fa = FA (Graph undefined [(n,()) | n <- ns'] es') start final
|
fa = FA (Graph undefined [(n,()) | n <- ns'] es') start final
|
||||||
in renameStates [0..] fa
|
in renameStates [0..] fa
|
||||||
where info = nodeInfo g
|
where info = nodeInfo g
|
||||||
-- reach = nodesReachable out
|
-- reach = nodesReachable out
|
||||||
start = closure info $ Set.singleton s
|
start = closure info $ Set.singleton s
|
||||||
isDFAFinal n = not (Set.null (Set.fromList f `Set.intersection` n))
|
isDFAFinal n = not (Set.null (Set.fromList f `Set.intersection` n))
|
||||||
h currentStates oldStates es
|
h currentStates oldStates es
|
||||||
| Set.null currentStates = (oldStates,es)
|
| Set.null currentStates = (oldStates,es)
|
||||||
| otherwise = ((h $! uniqueNewStates) $! allOldStates) $! es'
|
| otherwise = ((h $! uniqueNewStates) $! allOldStates) $! es'
|
||||||
where
|
where
|
||||||
allOldStates = oldStates `Set.union` currentStates
|
allOldStates = oldStates `Set.union` currentStates
|
||||||
(newStates,es') = new (Set.toList currentStates) Set.empty es
|
(newStates,es') = new (Set.toList currentStates) Set.empty es
|
||||||
uniqueNewStates = newStates Set.\\ allOldStates
|
uniqueNewStates = newStates Set.\\ allOldStates
|
||||||
-- Get the sets of states reachable from the given states
|
-- Get the sets of states reachable from the given states
|
||||||
-- by consuming one symbol, and the associated edges.
|
-- by consuming one symbol, and the associated edges.
|
||||||
new [] rs es = (rs,es)
|
new [] rs es = (rs,es)
|
||||||
new (n:ns) rs es = new ns rs' es'
|
new (n:ns) rs es = new ns rs' es'
|
||||||
@@ -281,7 +281,7 @@ closure info x = closure_ x x
|
|||||||
where closure_ acc check | Set.null check = acc
|
where closure_ acc check | Set.null check = acc
|
||||||
| otherwise = closure_ acc' check'
|
| otherwise = closure_ acc' check'
|
||||||
where
|
where
|
||||||
reach = Set.fromList [y | x <- Set.toList check,
|
reach = Set.fromList [y | x <- Set.toList check,
|
||||||
(_,y,Nothing) <- getOutgoing info x]
|
(_,y,Nothing) <- getOutgoing info x]
|
||||||
acc' = acc `Set.union` reach
|
acc' = acc `Set.union` reach
|
||||||
check' = reach Set.\\ acc
|
check' = reach Set.\\ acc
|
||||||
@@ -296,8 +296,8 @@ reachable1 info ns = Map.fromListWith (++) [(c, [y]) | n <- Set.toList ns, (_,y,
|
|||||||
reverseNFA :: NFA a -> NFA a
|
reverseNFA :: NFA a -> NFA a
|
||||||
reverseNFA (FA g s fs) = FA g''' s' [s]
|
reverseNFA (FA g s fs) = FA g''' s' [s]
|
||||||
where g' = reverseGraph g
|
where g' = reverseGraph g
|
||||||
(g'',s') = newNode () g'
|
(g'',s') = newNode () g'
|
||||||
g''' = newEdges [(s',f,Nothing) | f <- fs] g''
|
g''' = newEdges [(s',f,Nothing) | f <- fs] g''
|
||||||
|
|
||||||
dfa2nfa :: DFA a -> NFA a
|
dfa2nfa :: DFA a -> NFA a
|
||||||
dfa2nfa = mapTransitions Just
|
dfa2nfa = mapTransitions Just
|
||||||
@@ -313,13 +313,13 @@ prFAGraphviz = Dot.prGraphviz . faToGraphviz
|
|||||||
--prFAGraphviz_ = Dot.prGraphviz . faToGraphviz . mapStates show . mapTransitions show
|
--prFAGraphviz_ = Dot.prGraphviz . faToGraphviz . mapStates show . mapTransitions show
|
||||||
|
|
||||||
faToGraphviz :: (Eq n,Show n) => FA n String String -> Dot.Graph
|
faToGraphviz :: (Eq n,Show n) => FA n String String -> Dot.Graph
|
||||||
faToGraphviz (FA (Graph _ ns es) s f)
|
faToGraphviz (FA (Graph _ ns es) s f)
|
||||||
= Dot.Graph Dot.Directed Nothing [] (map mkNode ns) (map mkEdge es) []
|
= Dot.Graph Dot.Directed Nothing [] (map mkNode ns) (map mkEdge es) []
|
||||||
where mkNode (n,l) = Dot.Node (show n) attrs
|
where mkNode (n,l) = Dot.Node (show n) attrs
|
||||||
where attrs = [("label",l)]
|
where attrs = [("label",l)]
|
||||||
++ if n == s then [("shape","box")] else []
|
++ if n == s then [("shape","box")] else []
|
||||||
++ if n `elem` f then [("style","bold")] else []
|
++ if n `elem` f then [("style","bold")] else []
|
||||||
mkEdge (x,y,l) = Dot.Edge (show x) (show y) [("label",l)]
|
mkEdge (x,y,l) = Dot.Edge (show x) (show y) [("label",l)]
|
||||||
|
|
||||||
--
|
--
|
||||||
-- * Utilities
|
-- * Utilities
|
||||||
|
|||||||
@@ -7,13 +7,15 @@
|
|||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
|
|
||||||
module GF.Speech.GSL (gslPrinter) where
|
module GF.Speech.GSL (gslPrinter) where
|
||||||
|
import Prelude hiding ((<>)) -- GHC 8.4.1 clash with Text.PrettyPrint
|
||||||
|
|
||||||
import Prelude hiding ((<>))
|
--import GF.Data.Utilities
|
||||||
import GF.Grammar.CFG
|
import GF.Grammar.CFG
|
||||||
import GF.Speech.SRG
|
import GF.Speech.SRG
|
||||||
import GF.Speech.RegExp
|
import GF.Speech.RegExp
|
||||||
import GF.Infra.Option
|
import GF.Infra.Option
|
||||||
import PGF2
|
--import GF.Infra.Ident
|
||||||
|
import PGF
|
||||||
|
|
||||||
import Data.Char (toUpper,toLower)
|
import Data.Char (toUpper,toLower)
|
||||||
import Data.List (partition)
|
import Data.List (partition)
|
||||||
@@ -22,16 +24,16 @@ import GF.Text.Pretty
|
|||||||
width :: Int
|
width :: Int
|
||||||
width = 75
|
width = 75
|
||||||
|
|
||||||
gslPrinter :: Options -> PGF -> Concr -> String
|
gslPrinter :: Options -> PGF -> CId -> String
|
||||||
gslPrinter opts pgf cnc = renderStyle st $ prGSL $ makeNonLeftRecursiveSRG opts pgf cnc
|
gslPrinter opts pgf cnc = renderStyle st $ prGSL $ makeNonLeftRecursiveSRG opts pgf cnc
|
||||||
where st = style { lineLength = width }
|
where st = style { lineLength = width }
|
||||||
|
|
||||||
prGSL :: SRG -> Doc
|
prGSL :: SRG -> Doc
|
||||||
prGSL srg = header $++$ mainCat $++$ foldr ($++$) empty (map prRule (srgRules srg))
|
prGSL srg = header $++$ mainCat $++$ foldr ($++$) empty (map prRule (srgRules srg))
|
||||||
where
|
where
|
||||||
header = ";GSL2.0" $$
|
header = ";GSL2.0" $$
|
||||||
comment ("Nuance speech recognition grammar for " ++ srgName srg) $$
|
comment ("Nuance speech recognition grammar for " ++ srgName srg) $$
|
||||||
comment ("Generated by GF")
|
comment ("Generated by GF")
|
||||||
mainCat = ".MAIN" <+> prCat (srgStartCat srg)
|
mainCat = ".MAIN" <+> prCat (srgStartCat srg)
|
||||||
prRule (SRGRule cat rhs) = prCat cat <+> union (map prAlt rhs)
|
prRule (SRGRule cat rhs) = prCat cat <+> union (map prAlt rhs)
|
||||||
-- FIXME: use the probability
|
-- FIXME: use the probability
|
||||||
|
|||||||
@@ -11,14 +11,15 @@
|
|||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
|
|
||||||
module GF.Speech.JSGF (jsgfPrinter) where
|
module GF.Speech.JSGF (jsgfPrinter) where
|
||||||
|
import Prelude hiding ((<>)) -- GHC 8.4.1 clash with Text.PrettyPrint
|
||||||
|
|
||||||
import Prelude hiding ((<>))
|
--import GF.Data.Utilities
|
||||||
import GF.Infra.Option
|
import GF.Infra.Option
|
||||||
import GF.Grammar.CFG
|
import GF.Grammar.CFG
|
||||||
import GF.Speech.RegExp
|
import GF.Speech.RegExp
|
||||||
import GF.Speech.SISR
|
import GF.Speech.SISR
|
||||||
import GF.Speech.SRG
|
import GF.Speech.SRG
|
||||||
import PGF2
|
import PGF
|
||||||
|
|
||||||
import Data.Char
|
import Data.Char
|
||||||
import Data.List
|
import Data.List
|
||||||
@@ -30,8 +31,8 @@ width :: Int
|
|||||||
width = 75
|
width = 75
|
||||||
|
|
||||||
jsgfPrinter :: Options
|
jsgfPrinter :: Options
|
||||||
-> PGF
|
-> PGF
|
||||||
-> Concr -> String
|
-> CId -> String
|
||||||
jsgfPrinter opts pgf cnc = renderStyle st $ prJSGF sisr $ makeNonLeftRecursiveSRG opts pgf cnc
|
jsgfPrinter opts pgf cnc = renderStyle st $ prJSGF sisr $ makeNonLeftRecursiveSRG opts pgf cnc
|
||||||
where st = style { lineLength = width }
|
where st = style { lineLength = width }
|
||||||
sisr = flag optSISR opts
|
sisr = flag optSISR opts
|
||||||
@@ -43,7 +44,7 @@ prJSGF sisr srg
|
|||||||
header = "#JSGF" <+> "V1.0" <+> "UTF-8" <+> lang <> ';' $$
|
header = "#JSGF" <+> "V1.0" <+> "UTF-8" <+> lang <> ';' $$
|
||||||
comment ("JSGF speech recognition grammar for " ++ srgName srg) $$
|
comment ("JSGF speech recognition grammar for " ++ srgName srg) $$
|
||||||
comment "Generated by GF" $$
|
comment "Generated by GF" $$
|
||||||
("grammar " ++ srgName srg ++ ";")
|
("grammar " ++ srgName srg ++ ";")
|
||||||
lang = maybe empty pp (srgLanguage srg)
|
lang = maybe empty pp (srgLanguage srg)
|
||||||
mainCat = rule True "MAIN" [prCat (srgStartCat srg)]
|
mainCat = rule True "MAIN" [prCat (srgStartCat srg)]
|
||||||
prRule (SRGRule cat rhs) = rule (isExternalCat srg cat) cat (map prAlt rhs)
|
prRule (SRGRule cat rhs) = rule (isExternalCat srg cat) cat (map prAlt rhs)
|
||||||
@@ -61,7 +62,7 @@ prItem :: Maybe SISRFormat -> CFTerm -> SRGItem -> Doc
|
|||||||
prItem sisr t = f 0
|
prItem sisr t = f 0
|
||||||
where
|
where
|
||||||
f _ (REUnion []) = pp "<VOID>"
|
f _ (REUnion []) = pp "<VOID>"
|
||||||
f p (REUnion xs)
|
f p (REUnion xs)
|
||||||
| not (null es) = brackets (f 0 (REUnion nes))
|
| not (null es) = brackets (f 0 (REUnion nes))
|
||||||
| otherwise = (if p >= 1 then parens else id) (alts (map (f 1) xs))
|
| otherwise = (if p >= 1 then parens else id) (alts (map (f 1) xs))
|
||||||
where (es,nes) = partition isEpsilon xs
|
where (es,nes) = partition isEpsilon xs
|
||||||
@@ -109,3 +110,4 @@ prepunctuate p (x:xs) = x : map (p <>) xs
|
|||||||
|
|
||||||
($++$) :: Doc -> Doc -> Doc
|
($++$) :: Doc -> Doc -> Doc
|
||||||
x $++$ y = x $$ emptyLine $$ y
|
x $++$ y = x $$ emptyLine $$ y
|
||||||
|
|
||||||
|
|||||||
@@ -6,54 +6,60 @@
|
|||||||
----------------------------------------------------------------------
|
----------------------------------------------------------------------
|
||||||
module GF.Speech.PGFToCFG (bnfPrinter, pgfToCFG) where
|
module GF.Speech.PGFToCFG (bnfPrinter, pgfToCFG) where
|
||||||
|
|
||||||
import PGF2
|
import PGF(showCId)
|
||||||
import PGF2.Internal
|
import PGF.Internal as PGF
|
||||||
|
--import GF.Infra.Ident
|
||||||
import GF.Grammar.CFG hiding (Symbol)
|
import GF.Grammar.CFG hiding (Symbol)
|
||||||
|
|
||||||
|
import Data.Array.IArray as Array
|
||||||
|
--import Data.List
|
||||||
import Data.Map (Map)
|
import Data.Map (Map)
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
import qualified Data.IntMap as IntMap
|
import qualified Data.IntMap as IntMap
|
||||||
|
--import Data.Maybe
|
||||||
import Data.Set (Set)
|
import Data.Set (Set)
|
||||||
import qualified Data.Set as Set
|
import qualified Data.Set as Set
|
||||||
|
|
||||||
bnfPrinter :: PGF -> Concr -> String
|
bnfPrinter :: PGF -> CId -> String
|
||||||
bnfPrinter = toBNF id
|
bnfPrinter = toBNF id
|
||||||
|
|
||||||
toBNF :: (CFG -> CFG) -> PGF -> Concr -> String
|
toBNF :: (CFG -> CFG) -> PGF -> CId -> String
|
||||||
toBNF f pgf cnc = prCFG $ f $ pgfToCFG pgf cnc
|
toBNF f pgf cnc = prCFG $ f $ pgfToCFG pgf cnc
|
||||||
|
|
||||||
type Profile = [Int]
|
type Profile = [Int]
|
||||||
|
|
||||||
pgfToCFG :: PGF -> Concr -> CFG
|
pgfToCFG :: PGF
|
||||||
pgfToCFG pgf cnc = mkCFG start_cat extCats (startRules ++ concatMap ruleToCFRule rules)
|
-> CId -- ^ Concrete syntax name
|
||||||
|
-> CFG
|
||||||
|
pgfToCFG pgf lang = mkCFG (showCId (lookStartCat pgf)) extCats (startRules ++ concatMap ruleToCFRule rules)
|
||||||
where
|
where
|
||||||
(_,start_cat,_) = unType (startCat pgf)
|
cnc = lookConcr pgf lang
|
||||||
|
|
||||||
rules :: [(FId,Production)]
|
rules :: [(FId,Production)]
|
||||||
rules = [(fcat,prod) | fcat <- [0..concrTotalCats cnc],
|
rules = [(fcat,prod) | (fcat,set) <- IntMap.toList (PGF.productions cnc)
|
||||||
prod <- concrProductions cnc fcat]
|
, prod <- Set.toList set]
|
||||||
|
|
||||||
fcatCats :: Map FId Cat
|
fcatCats :: Map FId Cat
|
||||||
fcatCats = Map.fromList [(fc, c ++ "_" ++ show i)
|
fcatCats = Map.fromList [(fc, showCId c ++ "_" ++ show i)
|
||||||
| (c,s,e,lbls) <- concrCategories cnc,
|
| (c,CncCat s e lbls) <- Map.toList (cnccats cnc),
|
||||||
(fc,i) <- zip [s..e] [1..]]
|
(fc,i) <- zip (range (s,e)) [1..]]
|
||||||
|
|
||||||
fcatCat :: FId -> Cat
|
fcatCat :: FId -> Cat
|
||||||
fcatCat c = Map.findWithDefault ("Unknown_" ++ show c) c fcatCats
|
fcatCat c = Map.findWithDefault ("Unknown_" ++ show c) c fcatCats
|
||||||
|
|
||||||
fcatToCat :: FId -> Int -> Cat
|
fcatToCat :: FId -> LIndex -> Cat
|
||||||
fcatToCat c l = fcatCat c ++ row
|
fcatToCat c l = fcatCat c ++ row
|
||||||
where row = if catLinArity c == 1 then "" else "_" ++ show l
|
where row = if catLinArity c == 1 then "" else "_" ++ show l
|
||||||
|
|
||||||
-- gets the number of fields in the lincat for the given category
|
-- gets the number of fields in the lincat for the given category
|
||||||
catLinArity :: FId -> Int
|
catLinArity :: FId -> Int
|
||||||
catLinArity c = maximum (1:[length rhs | ((_,rhs), _) <- topdownRules c])
|
catLinArity c = maximum (1:[rangeSize (bounds rhs) | (CncFun _ rhs, _) <- topdownRules c])
|
||||||
|
|
||||||
topdownRules cat = f cat []
|
topdownRules cat = f cat []
|
||||||
where
|
where
|
||||||
f cat rules = foldr g rules (concrProductions cnc cat)
|
f cat rules = maybe rules (Set.foldr g rules) (IntMap.lookup cat (productions cnc))
|
||||||
|
|
||||||
g (PApply funid args) rules = (concrFunction cnc funid,args) : rules
|
g (PApply funid args) rules = (cncfuns cnc ! funid,args) : rules
|
||||||
g (PCoerce cat) rules = f cat rules
|
g (PCoerce cat) rules = f cat rules
|
||||||
|
|
||||||
|
|
||||||
@@ -61,26 +67,26 @@ pgfToCFG pgf cnc = mkCFG start_cat extCats (startRules ++ concatMap ruleToCFRule
|
|||||||
extCats = Set.fromList $ map ruleLhs startRules
|
extCats = Set.fromList $ map ruleLhs startRules
|
||||||
|
|
||||||
startRules :: [CFRule]
|
startRules :: [CFRule]
|
||||||
startRules = [Rule c [NonTerminal (fcatToCat fc r)] (CFRes 0)
|
startRules = [Rule (showCId c) [NonTerminal (fcatToCat fc r)] (CFRes 0)
|
||||||
| (c,s,e,lbls) <- concrCategories cnc,
|
| (c,CncCat s e lbls) <- Map.toList (cnccats cnc),
|
||||||
fc <- [s..e], not (isPredefFId fc),
|
fc <- range (s,e), not (isPredefFId fc),
|
||||||
r <- [0..catLinArity fc-1]]
|
r <- [0..catLinArity fc-1]]
|
||||||
|
|
||||||
ruleToCFRule :: (FId,Production) -> [CFRule]
|
ruleToCFRule :: (FId,Production) -> [CFRule]
|
||||||
ruleToCFRule (c,PApply funid args) =
|
ruleToCFRule (c,PApply funid args) =
|
||||||
[Rule (fcatToCat c l) (mkRhs row) (profilesToTerm [fixProfile row n | n <- [0..length args-1]])
|
[Rule (fcatToCat c l) (mkRhs row) (profilesToTerm [fixProfile row n | n <- [0..length args-1]])
|
||||||
| (l,seqid) <- zip [0..] rhs
|
| (l,seqid) <- Array.assocs rhs
|
||||||
, let row = concrSequence cnc seqid
|
, let row = sequences cnc ! seqid
|
||||||
, not (containsLiterals row)]
|
, not (containsLiterals row)]
|
||||||
where
|
where
|
||||||
(f, rhs) = concrFunction cnc funid
|
CncFun f rhs = cncfuns cnc ! funid
|
||||||
|
|
||||||
mkRhs :: [Symbol] -> [CFSymbol]
|
mkRhs :: Array DotPos Symbol -> [CFSymbol]
|
||||||
mkRhs = concatMap symbolToCFSymbol
|
mkRhs = concatMap symbolToCFSymbol . Array.elems
|
||||||
|
|
||||||
containsLiterals :: [Symbol] -> Bool
|
containsLiterals :: Array DotPos Symbol -> Bool
|
||||||
containsLiterals row = not (null ([n | SymLit n _ <- row] ++
|
containsLiterals row = not (null ([n | SymLit n _ <- Array.elems row] ++
|
||||||
[n | SymVar n _ <- row]))
|
[n | SymVar n _ <- Array.elems row]))
|
||||||
|
|
||||||
symbolToCFSymbol :: Symbol -> [CFSymbol]
|
symbolToCFSymbol :: Symbol -> [CFSymbol]
|
||||||
symbolToCFSymbol (SymCat n l) = [let PArg _ fid = args!!n in NonTerminal (fcatToCat fid l)]
|
symbolToCFSymbol (SymCat n l) = [let PArg _ fid = args!!n in NonTerminal (fcatToCat fid l)]
|
||||||
@@ -96,21 +102,20 @@ pgfToCFG pgf cnc = mkCFG start_cat extCats (startRules ++ concatMap ruleToCFRule
|
|||||||
symbolToCFSymbol SymALL_CAPIT = [Terminal "&|"]
|
symbolToCFSymbol SymALL_CAPIT = [Terminal "&|"]
|
||||||
symbolToCFSymbol SymNE = []
|
symbolToCFSymbol SymNE = []
|
||||||
|
|
||||||
fixProfile :: [Symbol] -> Int -> Profile
|
fixProfile :: Array DotPos Symbol -> Int -> Profile
|
||||||
fixProfile row i = [k | (k,j) <- nts, j == i]
|
fixProfile row i = [k | (k,j) <- nts, j == i]
|
||||||
where
|
where
|
||||||
nts = zip [0..] [j | nt <- row, j <- getPos nt]
|
nts = zip [0..] [j | nt <- Array.elems row, j <- getPos nt]
|
||||||
|
|
||||||
getPos (SymCat j _) = [j]
|
getPos (SymCat j _) = [j]
|
||||||
getPos (SymLit j _) = [j]
|
getPos (SymLit j _) = [j]
|
||||||
getPos _ = []
|
getPos _ = []
|
||||||
|
|
||||||
profilesToTerm :: [Profile] -> CFTerm
|
profilesToTerm :: [Profile] -> CFTerm
|
||||||
profilesToTerm ps = CFObj f (zipWith profileToTerm argTypes ps)
|
profilesToTerm ps = CFObj f (zipWith profileToTerm argTypes ps)
|
||||||
where Just (hypos,_,_) = fmap unType (functionType pgf f)
|
where (argTypes,_) = catSkeleton $ lookType (abstract pgf) f
|
||||||
argTypes = [cat | (_,_,ty) <- hypos, let (_,cat,_) = unType ty]
|
|
||||||
|
|
||||||
profileToTerm :: Fun -> Profile -> CFTerm
|
profileToTerm :: CId -> Profile -> CFTerm
|
||||||
profileToTerm t [] = CFMeta t
|
profileToTerm t [] = CFMeta t
|
||||||
profileToTerm _ xs = CFRes (last xs) -- FIXME: unify
|
profileToTerm _ xs = CFRes (last xs) -- FIXME: unify
|
||||||
ruleToCFRule (c,PCoerce c') =
|
ruleToCFRule (c,PCoerce c') =
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user