79 Commits

Author SHA1 Message Date
krangelov
4c6872615c remove RConcrete 2021-07-30 12:10:40 +02:00
krangelov
155657709a Merge branch 'master' into c-runtime 2021-07-30 11:20:04 +02:00
krangelov
265f08d6ee added link to vis-network.min.js 2021-07-26 16:57:05 +02:00
krangelov
e47042424e Merge branch 'master' of https://github.com/GrammaticalFramework/gf-core 2021-07-26 16:52:11 +02:00
krangelov
ecf309a28e fix links to WordNet 2021-07-26 16:51:58 +02:00
Inari Listenmaa
d0a881f903 add VS code on the list of editor modes 2021-07-26 14:11:48 +08:00
Inari Listenmaa
810640822d Update documentation for release 3.11 2021-07-25 15:37:12 +08:00
Inari Listenmaa
ed79955931 Merge pull request #129 from anka-213/automate-release
Automatically upload release assets after building for release
2021-07-25 08:20:41 +02:00
Andreas Källberg
1867bfc8a1 Rename packages based on git tag 2021-07-25 11:08:21 +08:00
Andreas Källberg
6ef4f27d32 Upload release assets automatically as well 2021-07-25 10:43:36 +08:00
Inari Listenmaa
3ab07ec58f Update debian changelog for GF 3.11 2021-07-25 10:30:49 +08:00
Inari Listenmaa
b8324fe3e6 Merge pull request #116 from anka-213/fix-binary-package-build
Update scripts to use `cabal v1-...` so they work on newer cabal
2021-07-25 04:15:07 +02:00
Andreas Källberg
8814fde817 Only run the script once per release 2021-07-25 09:30:36 +08:00
Andreas Källberg
375b3cf285 Update release script to build for two ubuntu versions 2021-07-25 08:23:25 +08:00
Andreas Källberg
3c4f42db15 Build ubuntu packages on ubuntu-latest
Fixes #74
2021-07-25 08:23:25 +08:00
John J. Camilleri
0474a37af6 Make Makefile compatible with stack and old/new cabal (with v1- prefix when necessary) 2021-07-25 08:23:25 +08:00
Andreas Källberg
e3498d5ead Update to newest haskell github action
Also fix so the stack builds use the correct ghc versions
2021-07-25 08:23:25 +08:00
Andreas Källberg
4c5927c98c Update scripts to use cabal v1-... so they work on newer cabal
Fixes build failures like https://github.com/GrammaticalFramework/gf-core/runs/2949099280?check_suite_focus=true
2021-07-25 08:23:25 +08:00
John J. Camilleri
bb51224e8e IRC link pre-fills channel. Link to logs gives newest first. 2021-07-23 16:07:34 +02:00
John J. Camilleri
9533edc3ca Merge pull request #128 from GrammaticalFramework/windows-binary
Fixes to building Windows binary
2021-07-23 15:55:37 +02:00
John J. Camilleri
4df8999ed5 Change Python 3.8 to 3.9 2021-07-23 08:05:35 +02:00
John J. Camilleri
7fdbf3f400 Update path in main workflow for binaries 2021-07-22 23:11:01 +02:00
John J. Camilleri
0d6c67f6b1 Try without rewriting envvar 2021-07-22 23:02:22 +02:00
John J. Camilleri
2610219f6a Update path 2021-07-22 22:56:39 +02:00
John J. Camilleri
7674f078d6 Try another path 2021-07-22 22:49:44 +02:00
John J. Camilleri
c67fe05c08 Narrow search, print env var 2021-07-22 22:44:53 +02:00
John J. Camilleri
7b9bb780a2 Find Java stuff 2021-07-22 22:34:26 +02:00
John J. Camilleri
4f256447e2 Add separate Windows binary CI action for easier testing 2021-07-22 22:27:15 +02:00
Inari Listenmaa
dfa5b9276d #gf IRC channel has moved to Libera 2021-07-22 01:08:00 +02:00
Inari Listenmaa
667bfd30bd Merge pull request #87 from anka-213/make-it-fast
Remove the `Either Int` from value2term
2021-07-20 04:35:37 +02:00
Inari Listenmaa
66ae31e99e Merge pull request #126 from inariksit/developers-documentation
Update developers' documentation
2021-07-15 05:16:55 +02:00
Inari Listenmaa
a677f0373c General restructuring, various minor changes 2021-07-15 10:40:26 +08:00
Inari Listenmaa
13f845d127 Update C runtime instructions 2021-07-15 10:39:54 +08:00
Inari Listenmaa
aa530233fb Remove instructions to create binaries
Those are in github actions
2021-07-15 10:27:57 +08:00
Inari Listenmaa
45bc5595c0 Update C runtime install instructions 2021-07-15 09:54:15 +08:00
Inari Listenmaa
6d12754e4f Split the Cabal instructions to another page
and link from main instructions
2021-07-15 08:21:29 +08:00
1Regina
a09d9bd006 install and upgrade stack 2021-07-14 17:20:20 +08:00
Meowyam
fffe3161d4 updated docs to reflect binaries generated via github actions
fix merge conflicts

resolve merge conflict
2021-07-14 17:20:20 +08:00
Meowyam
743f5e55d4 add missing install.sh file for c runtime 2021-07-14 17:20:20 +08:00
Inari Listenmaa
9e209bbaba Changes in Git instructions 2021-07-14 17:20:07 +08:00
Inari Listenmaa
a1594e6a69 updated doc with instructions for C runtime for ubuntu and fedora 2021-07-14 16:44:44 +08:00
Inari Listenmaa
06e0a986d1 Changes in Git instructions 2021-07-14 16:12:11 +08:00
Meowyam
6f2a4bcd2c update doc for linux installation 2021-07-14 15:32:02 +08:00
Inari Listenmaa
f345f615f4 Update information about test suite
Co-Authored-By: 1Regina <46968488+1Regina@users.noreply.github.com>
2021-07-14 15:16:23 +08:00
Inari Listenmaa
80d16fcf94 Update instructions about C runtime 2021-07-14 15:03:59 +08:00
Andreas Källberg
7faf8c9dad Clean up redundant case expressions 2021-07-12 16:38:29 +08:00
Andreas Källberg
c2ffa6763b Github actions: Fix build for stack 2021-07-12 15:53:49 +08:00
Andreas Källberg
b3881570c7 Remove last traces of the Either in value2term 2021-07-12 15:53:49 +08:00
Andreas Källberg
bd270b05ff Remove the Either Int from value2term
This prevents HUGE space leak and makes compiling a PGF a LOT faster

For example, an application grammar moved from taking over 50GB
of ram and taking 5 minutes (most of which is spent on garbage colelction)
to taking 1.2 seconds and using 42mb of memory

The price we pay is that the "variable #n is out of scope" error is now
lazy and will happen when we try to evaluate the term instead of
happening when the function returns and allowing the caller to chose how
to handle the error.
I don't think this should matter in practice, since it's very rare;
at least Inari has never encountered it.
2021-07-12 15:50:43 +08:00
John J. Camilleri
a1fd3ea142 Fix bug introduced in cdbe73eb47
Apparently I don't understand how pattern-matching works in Haskell
2021-07-08 13:56:58 +02:00
John J. Camilleri
cdbe73eb47 Remove two missing-methods warnings 2021-07-08 12:10:41 +02:00
John J. Camilleri
6077d5dd5b Merge pull request #124 from GrammaticalFramework/cabal-cleanup
More cabal file cleanup
2021-07-08 08:56:31 +02:00
John J. Camilleri
0954b4cbab More cabal file cleanup. Remove some more tabs from Haskell source. 2021-07-07 13:04:09 +02:00
John J. Camilleri
f2e52d6f2c Replace tabs for whitespace in source code 2021-07-07 09:40:41 +02:00
John J. Camilleri
a2b23d5897 Make whitespace uniform in Cabal files, add a few more dependency bounds 2021-07-07 09:11:46 +02:00
John J. Camilleri
0886eb520d Update 3.11 release notes 2021-07-06 15:45:21 +02:00
John J. Camilleri
ef42216415 Add import from command line invocation to command history
Closes #64
2021-07-06 15:35:03 +02:00
John J. Camilleri
0c3ca3d79a Add note in PGF2 documentation about risk for integer overflow.
Closes #109
2021-07-06 14:43:21 +02:00
John J. Camilleri
e2e5033075 Merge pull request #122 from 2jacobtan/master
specify version bounds in *.cabal files
2021-07-06 14:31:29 +02:00
John J. Camilleri
84b4b6fab9 Some more cabal file cleanup. Add stack files for pgf, pgf2. 2021-07-06 14:11:30 +02:00
Inari Listenmaa
5e052ff499 Merge pull request #119 from GrammaticalFramework/concrete-new
Clean up Compute.ConcreteNew and TypeCheck.RConcrete
2021-07-06 14:05:00 +02:00
2jacobtan
e1a40640cd specify version bounds in pgf.cabal and pgf2.cabal 2021-07-06 05:42:34 +08:00
2jacobtan
be231584f6 set stack.yaml to lts-18.0 2021-07-06 05:20:09 +08:00
2jacobtan
12c564f97c specify version bounds in gf.cabal 2021-07-06 05:08:00 +08:00
krangelov
eece3e86b3 Merge branch 'master' into c-runtime 2019-09-20 16:19:08 +02:00
krangelov
c119d5e34b silence encoding error 2019-09-20 14:07:07 +02:00
krangelov
a33a84df3d funnel the generated byte code to the runtime 2019-09-20 11:18:17 +02:00
krangelov
8a419f66a6 Merge branch 'master' into c-runtime 2019-09-20 10:52:40 +02:00
krangelov
a27bcb8092 Merge branch 'master' into c-runtime 2019-09-20 10:42:50 +02:00
krangelov
084b345663 added option to show the probabilities of results 2019-09-20 08:09:54 +02:00
krangelov
a0cfe09e09 added option -number to limit the number of parse results 2019-09-20 07:18:58 +02:00
krangelov
b3c07d45b9 remove the old Haskell runtime 2019-09-19 22:40:40 +02:00
krangelov
acb70ccc1b cleanup 2019-09-19 22:30:08 +02:00
krangelov
4a71464ca7 Merge with master and drop the Haskell runtime completely 2019-09-19 22:01:57 +02:00
krangelov
e993ae59f8 drop the haskell runtime, part 2 2019-09-19 10:06:06 +02:00
krangelov
f12557acf8 remove the dependency to the Haskell runtime completely 2019-09-19 10:03:04 +02:00
Krasimir Angelov
6a5053daeb move the PGF optimizer in the compiler 2018-11-02 14:48:30 +01:00
Krasimir Angelov
5a2b200948 manually copy the "c-runtime" branch from the old repository. 2018-11-02 14:38:44 +01:00
Krasimir Angelov
bf5abe2948 the compiler and the Haskell runtime now support abstract senses 2018-11-02 14:01:54 +01:00
179 changed files with 4251 additions and 11989 deletions

View File

@@ -14,7 +14,7 @@ jobs:
strategy: strategy:
matrix: matrix:
os: [ubuntu-latest, macos-latest, windows-latest] os: [ubuntu-latest, macos-latest, windows-latest]
cabal: ["3.2"] cabal: ["latest"]
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: actions/setup-haskell@v1.1.4 - uses: haskell/actions/setup@v1
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: ["2.3.3"] stack: ["latest"]
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,11 +73,12 @@ 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: actions/setup-haskell@v1.1.4 - uses: haskell/actions/setup@v1
name: Setup Haskell Stack name: Setup Haskell Stack
with: with:
# ghc-version: ${{ matrix.ghc }} ghc-version: ${{ matrix.ghc }}
stack-version: ${{ matrix.stack }} stack-version: 'latest'
enable-stack: true
- uses: actions/cache@v1 - uses: actions/cache@v1
name: Cache ~/.stack name: Cache ~/.stack

View File

@@ -3,6 +3,7 @@ name: Build Binary Packages
on: on:
workflow_dispatch: workflow_dispatch:
release: release:
types: ["created"]
jobs: jobs:
@@ -10,11 +11,13 @@ jobs:
ubuntu: ubuntu:
name: Build Ubuntu package name: Build Ubuntu package
runs-on: ubuntu-18.04 strategy:
# strategy: matrix:
# matrix: os:
# ghc: ["8.6.5"] - ubuntu-18.04
# cabal: ["2.4"] - ubuntu-20.04
runs-on: ${{ matrix.os }}
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
@@ -53,19 +56,33 @@ jobs:
- name: Upload artifact - name: Upload artifact
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v2
with: with:
name: gf-${{ github.sha }}-ubuntu name: gf-${{ github.event.release.tag_name }}-${{ matrix.os }}.deb
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
@@ -92,19 +109,33 @@ jobs:
- name: Upload artifact - name: Upload artifact
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v2
with: with:
name: gf-${{ github.sha }}-macos name: gf-${{ github.event.release.tag_name }}-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
@@ -136,16 +167,18 @@ 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 PATH="${PATH}:/c/Program Files/Java/jdk8u275-b01/bin" export JDKPATH=/c/hostedtoolcache/windows/Java_Adopt_jdk/8.0.292-10/x64
export PATH="${PATH}:${JDKPATH}/bin"
cd src/runtime/java cd src/runtime/java
make \ make \
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" \ JNI_INCLUDES="-I \"${JDKPATH}/include\" -I \"${JDKPATH}/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
@@ -157,7 +190,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.8/site-packages/pgf* /c/tmp-dist/python cp /usr/lib/python3.9/site-packages/pgf* /c/tmp-dist/python
- name: Setup Haskell - name: Setup Haskell
uses: actions/setup-haskell@v1 uses: actions/setup-haskell@v1
@@ -180,6 +213,18 @@ jobs:
- name: Upload artifact - name: Upload artifact
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v2
with: with:
name: gf-${{ github.sha }}-windows name: gf-${{ github.event.release.tag_name }}-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

View File

@@ -1,31 +1,48 @@
.PHONY: all build install doc clean gf html deb pkg bintar sdist .PHONY: all build install doc clean 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
cabal configure ifneq ($(STACK),1)
cabal ${CMD_PFX}configure
endif
build: dist/setup-config build: dist/setup-config
cabal build ${CMD} ${CMD_PFX}build
install: install:
cabal copy ifeq ($(STACK),1)
cabal register stack install
else
cabal ${CMD_PFX}copy
cabal ${CMD_PFX}register
endif
doc: doc:
cabal haddock ${CMD} ${CMD_PFX}haddock
clean: clean:
cabal clean ${CMD} ${CMD_PFX}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
@@ -35,7 +52,7 @@ html::
deb: deb:
dpkg-buildpackage -b -uc dpkg-buildpackage -b -uc
# Make an OS X Installer package # Make a macOS installer package
pkg: pkg:
FMT=pkg bash bin/build-binary-dist.sh FMT=pkg bash bin/build-binary-dist.sh

6
debian/changelog vendored
View File

@@ -1,3 +1,9 @@
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
View File

@@ -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 update cabal v1-update
cabal install --only-dependencies cabal v1-install --only-dependencies
cabal configure --prefix=/usr -fserver -fc-runtime --extra-lib-dirs=$(CURDIR)/src/runtime/c/.libs --extra-include-dirs=$(CURDIR)/src/runtime/c cabal v1-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 build -$(SET_LDL) cabal v1-build
override_dh_auto_install: override_dh_auto_install:
$(SET_LDL) cabal copy --destdir=$(CURDIR)/debian/gf $(SET_LDL) cabal v1-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

View File

@@ -0,0 +1,201 @@
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
```

View File

@@ -1,6 +1,6 @@
GF Developers Guide GF Developers Guide
2018-07-26 2021-07-15
%!options(html): --toc %!options(html): --toc
@@ -15,388 +15,287 @@ 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 Platform//, //Git// and the //Haskeline library//. system: the Haskell build tool //Stack//, the version control software //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 Ubuntu: ``sudo apt-get install haskell-platform git libghc6-haskeline-dev`` %**On Mac OS and Windows**, the tools can be downloaded from their respective
- On Fedora: ``sudo dnf install haskell-platform git ghc-haskeline-devel`` %web sites, as described below.
=== 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 Mac OS and Windows**, the tools can be downloaded from their respective - **On other operating systems**, see the [installation guide https://docs.haskellstack.org/en/stable/install_and_upgrade].
web sites, as described below.
=== The Haskell Platform ===
GF is written in Haskell, so first of all you need %If you already have Stack installed, upgrade it to the latest version by running: ``stack upgrade``
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//. To get the GF source code, you also need //Git//, a distributed version control system.
//Git// is a distributed version control system, see
https://git-scm.com/downloads for more information.
=== The haskeline library === - **On Linux**, the best option is to install the tools via the standard
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 Ubuntu: ``sudo apt-get install libghc-haskeline-dev`` - **On Mac OS and Windows**, this should work automatically.
- 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 the source ==[getting-source]
Once you have all tools in place you can get the GF source code. If you Once you have all tools in place you can get the GF source code from
just want to compile and use GF then it is enough to have read-only [GitHub https://github.com/GrammaticalFramework/]:
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.
=== Read-only access === - https://github.com/GrammaticalFramework/gf-core for the GF compiler
- https://github.com/GrammaticalFramework/gf-rgl for the Resource Grammar Library
==== Getting a fresh copy for read-only access ====
Anyone can get the latest development version of GF by running: === Read-only access: clone the main repository ===
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
``` ```
This will create directories ``gf-core`` and ``gf-rgl`` in the current directory. To get new updates, run the following anywhere in your local copy of the repository:
==== 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 add file1 file2 ... $ git pull
``` ```
To record changes, use: === Contribute your changes: fork the main repository ===
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 commit file1 file2 ... $ git clone https://github.com/<YOUR_USERNAME>/gf-core.git
``` ```
This creates a patch against the previous version and stores it in your + **Updating your copy —**
local repository. You can record any number of changes before Once you have cloned your fork, you need to set up the main repository as a remote:
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 push $ git remote add upstream https://github.com/GrammaticalFramework/gf-core.git
``` ```
It is also possible for anyone else to contribute by Then you can get the latest updates by running the following:
- creating a fork of the GF repository on GitHub, ```
- working with local clone of the fork (obtained with ``git clone``), $ git pull upstream master
- 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.
== Compilation from source with Cabal == If you want to contribute to the RGL as well, do the same process for the RGL repository.
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 == Compilation from source ==
case, all you need to do to compile and install GF, after downloading the
source code as described above, is By now you should have installed Stack and Haskeline, and cloned the Git repository on your own computer, in a directory called ``gf-core``.
=== 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
``` ```
This will automatically download any additional Haskell libraries needed to //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.//
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 == Compiling GF with C runtime system support ==
//configure//, //build// and //install// steps.
=== Configure === The C runtime system is a separate implementation of the PGF runtime services.
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 run-time system might probabilistic models to obtain probable parses. The C runtime system might
also be easier to use than the Haskell run-time system on certain platforms, also be easier to use than the Haskell runtime system on certain platforms,
e.g. Android and iOS. e.g. Android and iOS.
To install the C run-time system, go to the ``src/runtime/c`` directory To install the C runtime 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``.
When the C run-time system is installed, you can install GF with C run-time - **On Linux and Mac OS —**
support by doing You should have autoconf, automake, libtool and make.
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 -fserver -fc-runtime cabal install -fc-runtime
``` ```
from the top directory. This give you three new things:
- ``PGF2``: a module to import in Haskell programs, providing a binding to from the top directory (``gf-core``).
the C run-time system.
- The GF shell can be started with ``gf -cshell`` or ``gf -crun`` to use If you use stack, uncomment the following lines in the ``stack.yaml`` file:
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 ```
system, e.g. ``c-parse``, ``c-linearize`` and ``c-translate``. flags:
gf:
c-runtime: true
extra-lib-dirs:
- /usr/local/lib
```
and then run ``stack install`` from the top directory (``gf-core``).
=== Python and Java bindings === //If you get an "``error while loading shared libraries``" when trying to run GF with C runtime, remember to declare your ``LD_LIBRARY_PATH``.//
//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:
``` ```
@@ -418,103 +317,68 @@ If you do not have Haskell installed, you can use the simple build script ``Setu
== Creating binary distribution packages == == Creating binary distribution packages ==
=== Creating .deb packages for Ubuntu === The binaries are generated with Github Actions. More details can be viewed here:
This was tested on Ubuntu 14.04 for the release of GF 3.6, and the https://github.com/GrammaticalFramework/gf-core/actions/workflows/build-binary-packages.yml
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.
==== Preparations ==== == Running the test suite ==
The GF test suite is run with one of the following commands from the top directory:
``` ```
sudo apt-get install dpkg-dev debhelper $ cabal test
``` ```
==== Creating the package ==== or
Make sure the ``debian/changelog`` starts with an entry that describes the
version you are building. Then run
``` ```
make deb $ stack test
``` ```
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 which testsuite is the ``testsuite/`` directory. It contains subdirectories
themself contain GF batch files (with extension .gfs). The above command which themselves contain GF batch files (with extension ``.gfs``).
searches the subdirectories of the testsuite/ directory for files with extension The above command searches the subdirectories of the ``testsuite/`` directory
.gfs and when it finds one it is executed with the GF interpreter. for files with extension ``.gfs`` and when it finds one, it is executed with
The output of the script is stored in file with extension .out and is compared the GF interpreter. The output of the script is stored in file with extension ``.out``
with the content of the corresponding file with extension .gold, if there is one. and is compared 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, instead of Every time when you make some changes to GF that have to be tested,
writing the commands by hand in the GF shell, add them to one .gfs file in the testsuite instead of writing the commands by hand in the GF shell, add them to one ``.gfs``
and run the test. In this way you can use the same test later and we will be sure file in the testsuite subdirectory where its ``.gf`` file resides and run the test.
that we will not incidentaly break your code later. In this way you can use the same test later and we will be sure that we will not
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:
``` ```
$ cabal test testsuite/compiler Running 1 test suites...
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.

View File

@@ -15,6 +15,12 @@ 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

View File

@@ -1,8 +1,9 @@
--- ---
title: Grammatical Framework Download and Installation title: Grammatical Framework Download and Installation
... date: 25 July 2021
---
**GF 3.11** was released on ... December 2020. **GF 3.11** was released on 25 July 2021.
What's new? See the [release notes](release-3.11.html). What's new? See the [release notes](release-3.11.html).
@@ -24,22 +25,25 @@ 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/RELEASE-3.11) [Binary packages on GitHub](https://github.com/GrammaticalFramework/gf-core/releases/tag/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 dpkg -i gf_3.11.deb sudo apt-get install ./gf-3.11-ubuntu-*.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 10.13 (High Sierra) and 10.14 (Mojave). The packages should work on at least Catalina and Big Sur.
#### Windows #### Windows
@@ -49,7 +53,7 @@ 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 Hackage release (macOS, Linux, and WSL2 on Windows)
[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:
@@ -89,7 +93,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:
@@ -116,7 +120,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).

View File

@@ -1,8 +1,8 @@
<html> <html>
<head> <head>
<meta http-equiv="refresh" content="0; URL=/download/index-3.10.html" /> <meta http-equiv="refresh" content="0; URL=/download/index-3.11.html" />
</head> </head>
<body> <body>
You are being redirected to <a href="index-3.10.html">the current version</a> of this page. You are being redirected to <a href="index-3.11.html">the current version</a> of this page.
</body> </body>
</html> </html>

View File

@@ -1,7 +1,7 @@
--- ---
title: GF 3.11 Release Notes title: GF 3.11 Release Notes
date: ... December 2020 date: 25 July 2021
... ---
## Installation ## Installation
@@ -12,24 +12,27 @@ 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 400 changes have been pushed to GF core Over 500 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.
- Updates to build scripts and CI. - Support for newer version of Ubuntu 20.04 in the precompiled binaries.
- Bug fixes. - Updates to build scripts and CI workflows.
- 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.

218
gf.cabal
View File

@@ -1,17 +1,16 @@
name: gf name: gf
version: 3.10.4-git version: 3.11.0-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: http://www.grammaticalframework.org/ homepage: https://www.grammaticalframework.org/
bug-reports: https://github.com/GrammaticalFramework/gf-core/issues bug-reports: https://github.com/GrammaticalFramework/gf-core/issues
maintainer: Thomas Hallgren tested-with: GHC==7.10.3, GHC==8.0.2, GHC==8.10.4
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 extra-source-files: WebSetup.hs
@@ -42,39 +41,34 @@ data-files:
custom-setup custom-setup
setup-depends: setup-depends:
base, base >= 4.9.1 && < 4.15,
Cabal >=1.22.0.0, Cabal >= 1.22.0.0,
directory, directory >= 1.3.0 && < 1.4,
filepath, filepath >= 1.4.1 && < 1.5,
process >=1.0.1.1 process >= 1.0.1.1 && < 1.7
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
--flag new-comp executable gf
-- Description: Make -new-comp the default hs-source-dirs: src/programs, src/compiler
-- Default: True main-is: gf-main.hs
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: base >= 4.6 && <5, build-depends: pgf2,
base >= 4.6 && <5,
array, array,
containers, containers,
bytestring, bytestring,
@@ -83,81 +77,18 @@ library
pretty, pretty,
mtl, mtl,
exceptions, exceptions,
fail, ghc-prim,
-- For compatability with ghc < 8 filepath, directory>=1.2, time,
-- We need transformers-compat >= 0.6.3, but that is only in newer snapshots where it is redundant.
transformers-compat,
ghc-prim
hs-source-dirs: src/runtime/haskell
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
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 process, haskeline, parallel>=3, json
ghc-options: -threaded
hs-source-dirs: src/compiler other-modules:
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
@@ -178,9 +109,9 @@ library
GF.Command.TreeOperations GF.Command.TreeOperations
GF.Compile.CFGtoPGF GF.Compile.CFGtoPGF
GF.Compile.CheckGrammar GF.Compile.CheckGrammar
GF.Compile.Compute.Concrete
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
@@ -188,16 +119,14 @@ library
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
@@ -264,93 +193,38 @@ library
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.Clitics
GF.Text.Coding GF.Text.Coding
GF.Text.Lexing
GF.Text.Transliterations GF.Text.Transliterations
Paths_gf Paths_gf
if flag(c-runtime) -- not really part of GF but I have changed the original binary library
cpp-options: -DC_RUNTIME -- and we have to keep the copy for now.
Data.Binary
if flag(server) Data.Binary.Put
build-depends: httpd-shed>=0.4.0.3, network>=2.3 && <2.7, Data.Binary.Get
cgi>=3001.2.2.0 Data.Binary.Builder
if flag(network-uri) Data.Binary.IEEE754
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) if os(windows)
build-depends: Win32 build-depends:
Win32 >= 2.3.1.1 && < 2.7
else else
build-depends: unix, terminfo>=0.4 build-depends:
terminfo >=0.4.0 && < 0.5,
if impl(ghc>=8.2) unix >= 2.7.2 && < 2.8
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 test-suite gf-tests
type: exitcode-stdio-1.0 type: exitcode-stdio-1.0
main-is: run.hs main-is: run.hs
hs-source-dirs: testsuite hs-source-dirs: testsuite
build-depends: base>=4.3 && <5, Cabal>=1.8, directory, filepath, process build-depends:
base >= 4.9.1 && < 4.15,
Cabal >= 1.8,
directory >= 1.3.0 && < 1.4,
filepath >= 1.4.1 && < 1.5,
process >= 1.4.3 && < 1.7
build-tool-depends: gf:gf build-tool-depends: gf:gf
default-language: Haskell2010 default-language: Haskell2010

View File

@@ -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 Freenode 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 Libera network, where you are welcome to look for help with small questions or just start a general discussion.
You can <a href="https://webchat.freenode.net/?channels=gf">open a web chat</a> You can <a href="https://web.libera.chat/?channels=#gf">open a web chat</a>
or <a href="/irc/">browse the channel logs</a>. or <a href="https://www.grammaticalframework.org/irc/?C=M;O=D">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,7 +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> <dt class="col-sm-3 text-center text-nowrap">2021-05-05</dt>
<dd class="col-sm-9"> <dd class="col-sm-9">
@@ -234,7 +238,7 @@ least one, it may help you to get a first idea of what GF is.
</dd> </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 &ndash; 8 August 2021. <a href="//school.grammaticalframework.org/2020/">Seventh GF Summer School</a>, in Singapore and online, 26 July &ndash; 6 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">

View File

@@ -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 PGF(CId,mkCId,Expr,showExpr) import PGF2(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 (Eq,Ord,Show) deriving Show
data Option data Option
= OOpt Ident = OOpt Ident
@@ -29,13 +29,7 @@ data Argument
| ATerm Term | ATerm Term
| ANoArg | ANoArg
| AMacro Ident | AMacro Ident
deriving (Eq,Ord,Show) deriving 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 =
@@ -49,6 +43,18 @@ 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 =

View File

@@ -3,8 +3,7 @@ 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 qualified PGF as H(showExpr) import PGF2(mkStr,unStr,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,
@@ -38,21 +37,19 @@ class Monad m => TypeCheckArg m where typeCheckArg :: Expr -> m Expr
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
data CommandArguments = Exprs [Expr] | Strings [String] | Term Term data CommandArguments = Exprs [(Expr,Float)] | 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 es = Piped (Exprs es,unlines (map (H.showExpr []) es)) fromExprs show_p es = Piped (Exprs es,unlines (map (\(e,p) -> (if show_p then (++) ("["++show p++"] ") else id) (showExpr [] e)) 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 =
@@ -61,23 +58,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 t = showAsString first (e,p) =
case t of case unStr e of
H.ELit (H.LStr s) -> s Just s -> s
_ -> ['\n'|not first] ++ Nothing -> ['\n'|not first] ++
H.showExpr [] t ---newline needed in other cases than the first showExpr [] e ---newline needed in other cases than the first
toExprs args = toExprs args =
case args of case args of
Exprs es -> es Exprs es -> map fst es
Strings ss -> map stringAsExpr ss Strings ss -> map mkStr ss
Term t -> [stringAsExpr (render t)] Term t -> [mkStr (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 (H.showExpr []) es -- hmm Exprs es -> string2term $ unwords $ map (showExpr [] . fst) es -- hmm
-- ** Creating documentation -- ** Creating documentation

View File

@@ -1,16 +1,12 @@
{-# LANGUAGE FlexibleInstances, UndecidableInstances, CPP #-} {-# LANGUAGE FlexibleInstances, UndecidableInstances, CPP #-}
module GF.Command.Commands ( module GF.Command.Commands (
PGFEnv,HasPGFEnv(..),pgf,mos,pgfEnv,pgfCommands, HasPGF(..),pgfCommands,
options,flags, options,flags,
) where ) where
import Prelude hiding (putStrLn,(<>)) -- GHC 8.4.1 clash with Text.PrettyPrint import Prelude hiding (putStrLn,(<>))
import PGF import PGF2
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
@@ -28,28 +24,28 @@ import GF.Command.TreeOperations ---- temporary place for typecheck and compute
import GF.Data.Operations import GF.Data.Operations
import PGF.Internal (encodeFile) import Data.Char
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
data PGFEnv = Env {pgf::PGF,mos::Map.Map Language Morpho} class (Functor m,Monad m,MonadSIO m) => HasPGF m where getPGF :: m (Maybe PGF)
pgfEnv pgf = Env pgf mos instance (Monad m,HasPGF m,Fail.MonadFail m) => TypeCheckArg m where
where mos = Map.fromList [(la,buildMorpho pgf la) | la <- languages pgf] typeCheckArg e = do mb_pgf <- getPGF
case mb_pgf of
Just pgf -> either fail
(return . fst)
(inferExpr pgf e)
Nothing -> fail "Import a grammar before using this command"
class (Functor m,Monad m,MonadSIO m) => HasPGFEnv m where getPGFEnv :: m PGFEnv pgfCommands :: HasPGF m => Map.Map String (CommandInfo m)
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",
@@ -62,7 +58,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 = getEnv $ \ opts arg (Env pgf mos) -> do exec = needPGF $ \ opts arg pgf -> 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
@@ -74,7 +70,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 (graphvizAlignment pgf langs) es let grphs = map (graphvizWordAlignment langs graphvizDefaults) 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
@@ -96,6 +92,7 @@ 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",
@@ -106,16 +103,17 @@ 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 = getEnv $ \opts ts env -> case opts of exec = needPGF $ \opts ts pgf -> do
_ | isOpt "raw" opts -> concr <- optLang pgf opts
return . fromString . case opts of
unlines . map (unwords . map (concat . intersperse "+")) . _ | isOpt "raw" opts ->
map (getClitics (isInMorpho (optMorpho env opts)) (optClitics opts)) . return . fromString .
concatMap words $ toStrings ts unlines . map (unwords . map (concat . intersperse "+")) .
_ -> map (getClitics (not . null . lookupMorpho concr) (optClitics opts)) .
return . fromStrings . concatMap words $ toStrings ts
getCliticsText (isInMorpho (optMorpho env opts)) (optClitics opts) . _ -> return . fromStrings .
concatMap words $ toStrings ts, getCliticsText (not . null . lookupMorpho concr) (optClitics opts) .
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")
@@ -147,19 +145,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 = getEnv $ \ opts _ env@(Env pgf mos) -> do exec = needPGF $ \opts _ pgf -> 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 [])
let conf = configureExBased pgf (optMorpho env opts) (optLang pgf opts) printer concr <- optLang pgf opts
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",
@@ -174,54 +172,53 @@ 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",
"given in a file in the -probs flag." "if the grammar was compiled with option -probs"
],
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 = getEnv $ \ opts arg (Env pgf mos) -> do exec = needPGF $ \opts arg pgf -> 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 -> generateRandomFromDepth gen pgf ex (Just dp) Just ex -> generateRandomFrom gen pgf ex
Nothing -> generateRandomDepth gen pgf (optType pgf opts) (Just dp) Nothing -> generateRandom gen pgf (optType pgf opts)
returnFromExprs $ take (optNum opts) ts returnFromExprs (isOpt "show_probs" opts) $ 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. By default, ", "Generates all trees of a given category.",
"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, to depth 4", mkEx "gt -- all trees in the startcat",
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 = getEnv $ \ opts arg (Env pgf mos) -> do exec = needPGF $ \opts arg pgf -> do
let pgfr = optRestricted opts pgf let es = case mexp (toExprs arg) of
let dp = valIntOpts "depth" 4 opts Just ex -> generateAllFrom pgf ex
let ts = case mexp (toExprs arg) of Nothing -> generateAll pgf (optType pgf opts)
Just ex -> generateFromDepth pgfr ex (Just dp) returnFromExprs (isOpt "show_probs" opts) $ takeOptNum opts es
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",
@@ -242,33 +239,28 @@ 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 = getEnv $ \ opts ts (Env pgf mos) -> return . fromStrings . optLins pgf opts $ toExprs ts, exec = needPGF $ \ opts ts pgf -> 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"),
@@ -276,33 +268,13 @@ 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",
@@ -310,18 +282,20 @@ 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 = getEnv $ \opts ts env -> case opts of exec = needPGF $ \opts ts pgf -> do
_ | isOpt "missing" opts -> concr <- optLang pgf opts
return . fromString . unwords . case opts of
morphoMissing (optMorpho env opts) . _ | isOpt "missing" opts ->
concatMap words $ toStrings ts return . fromString . unwords .
_ | isOpt "known" opts -> morphoMissing concr .
return . fromString . unwords . concatMap words $ toStrings ts
morphoKnown (optMorpho env opts) . _ | isOpt "known" opts ->
concatMap words $ toStrings ts return . fromString . unwords .
_ -> return . fromString . unlines . morphoKnown concr .
map prMorphoAnalysis . concatMap (morphos env opts) . concatMap words $ toStrings ts
concatMap words $ toStrings ts, _ -> return . fromString . unlines .
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)")
], ],
@@ -335,18 +309,16 @@ 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 = getEnv $ \ opts arg (Env pgf mos) -> do exec = needPGF $ \ opts arg pgf -> do
let lang = optLang pgf opts 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")
] ]
}), }),
@@ -357,24 +329,25 @@ 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."
"", ],
"The -openclass flag is experimental and allows some robustness in ", exec = needPGF $ \opts ts pgf ->
"the parser. For example if -openclass=\"A,N,V\" is given, the parser", return $
"will accept unknown adjectives, nouns and verbs with the resource grammar." foldr (joinPiped . fromParse1 opts) void
(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)"),
("openclass","list of open-class categories for robust parsing"), ("number","limit the results to the top N trees")
("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",
@@ -394,9 +367,8 @@ pgfCommands = Map.fromList [
" " ++ opt ++ "\t\t" ++ expl | " " ++ opt ++ "\t\t" ++ expl |
((opt,_),expl) <- outputFormatsExpl, take 1 expl /= "*" ((opt,_),expl) <- outputFormatsExpl, take 1 expl /= "*"
]), ]),
exec = getEnv $ \opts _ env -> prGrammar env opts, exec = needPGF $ \opts _ pgf -> prGrammar pgf 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)")
@@ -416,6 +388,7 @@ 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",
@@ -429,11 +402,12 @@ pgfCommands = Map.fromList [
examples = [ examples = [
mkEx "pt -compute (plus one two) -- compute value" mkEx "pt -compute (plus one two) -- compute value"
], ],
exec = getEnv $ \ opts arg (Env pgf mos) -> exec = needPGF $ \opts arg pgf ->
returnFromExprs . takeOptNum opts . treeOps pgf opts $ toExprs arg, returnFromExprs False . takeOptNum opts . map (flip (,) 0) . 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",
@@ -446,10 +420,9 @@ 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 = getEnv $ \ opts _ (Env pgf mos) -> do exec = needPGF $ \ opts _ pgf -> 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
@@ -458,12 +431,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 tcerr -> (es,"on line" <+> n <> ':' $$ nest 2 (ppTcError tcerr) $$ err) Left err -> (es,"on line" <+> n <> ':' $$ nest 2 err $$ 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 es (render err) | otherwise -> return $ pipeWithMessage (map (flip (,) 0) es) (render err)
s <- restricted $ readFile file s <- restricted $ readFile file
case opts of case opts of
@@ -472,56 +445,26 @@ 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 = getEnv $ \ opts arg (Env pgf mos) -> do exec = needPGF $ \ opts arg pgf -> do
let from = optLangFlag "from" pgf opts from <- optLangFlag "from" pgf opts
let to = optLangFlag "to" pgf opts 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"),
@@ -529,7 +472,6 @@ 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",
@@ -547,7 +489,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 = getEnv $ \ opts arg (Env pgf mos) -> do exec = needPGF $ \ opts arg pgf -> 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
@@ -560,8 +502,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)
let lang = optLang pgf opts concr <- optLang pgf opts
let grphs = map (graphvizDependencyTree outp debug mlab mclab pgf lang) es let grphs = map (graphvizDependencyTree outp debug mlab mclab concr) 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"
@@ -596,7 +538,6 @@ pgfCommands = Map.fromList [
] ]
}), }),
("vp", emptyCommandInfo { ("vp", emptyCommandInfo {
longname = "visualize_parse", longname = "visualize_parse",
synopsis = "show parse tree graphically", synopsis = "show parse tree graphically",
@@ -608,9 +549,8 @@ 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 = getEnv $ \ opts arg (Env pgf mos) -> do exec = needPGF $ \opts arg pgf -> 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),
@@ -623,10 +563,11 @@ 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 (graphvizParseTreeDep mlab pgf lang gvOptions) es let grphs = map (graphvizDependencyTree "dot" False mlab Nothing concr) 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
@@ -661,7 +602,6 @@ 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",
@@ -674,7 +614,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 = getEnv $ \ opts arg (Env pgf mos) -> exec = needPGF $ \opts arg pgf ->
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
@@ -686,7 +626,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 (funs,cats)) es let grphs = map (graphvizAbstractTree pgf (graphvizDefaults{noFun=funs,noCat=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
@@ -708,6 +648,7 @@ 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",
@@ -720,205 +661,150 @@ 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 = getEnv $ \ opts arg (Env pgf mos) -> do exec = needPGF $ \opts arg pgf -> do
case toExprs arg of case toExprs arg of
[EFun id] -> case Map.lookup id (funs (abstract pgf)) of [e] -> case unApp e of
Just fd -> do putStrLn $ render (ppFun id fd) Just (id, []) -> case functionType pgf id of
let (_,_,_,prob) = fd Just ty -> do putStrLn (showFun pgf id ty)
putStrLn ("Probability: "++show prob) putStrLn ("Probability: "++show (treeProbability pgf e))
return void return void
Nothing -> case Map.lookup id (cats (abstract pgf)) of Nothing -> case categoryContext pgf id of
Just cd -> do putStrLn $ Just hypos -> do putStrLn ("cat "++id++if null hypos then "" else ' ':showContext [] hypos)
render (ppCat id cd $$ let ls = [showFun pgf fn ty | fn <- functionsByCat pgf id, Just ty <- [functionType pgf fn]]
if null (functionsToCat pgf id) if null ls
then empty then return ()
else ' ' $$ else putStrLn (unlines ("":ls))
vcat [ppFun fid (ty,0,Just ([],[]),0) | (fid,ty) <- functionsToCat pgf id] $$ putStrLn ("Probability: "++show (categoryProbability pgf id))
' ') return void
let (_,_,prob) = cd Nothing -> do putStrLn ("unknown category of function identifier "++show id)
putStrLn ("Probability: "++show prob) return void
return void _ -> case inferExpr pgf e of
Nothing -> do putStrLn ("unknown category of function identifier "++show id) Left err -> error err
return void Right (e,ty) -> do putStrLn ("Expression: "++showExpr [] e)
[e] -> case inferExpr pgf e of putStrLn ("Type: "++showType [] ty)
Left tcErr -> errorWithoutStackTrace $ render (ppTcError tcErr) putStrLn ("Probability: "++show (treeProbability pgf e))
Right (e,ty) -> do putStrLn ("Expression: "++showExpr [] e) return void
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
getEnv exec opts ts = liftSIO . exec opts ts =<< getPGFEnv needPGF exec opts ts = do
mb_pgf <- getPGF
par pgf opts s = case optOpenTypes opts of case mb_pgf of
[] -> [parse_ pgf lang (optType pgf opts) (Just dp) s | lang <- optLangs pgf opts] Just pgf -> liftSIO $ exec opts ts pgf
open_typs -> [parseWithRecovery pgf lang (optType pgf opts) open_typs (Just dp) s | lang <- optLangs pgf opts] _ -> fail "Import a grammar before using this command"
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,bs)) fromParse1 opts (s,po) =
| isOpt "bracket" opts = pipeMessage (showBracketedString bs) case po of
| otherwise = ParseOk ts -> fromExprs (isOpt "show_probs" opts) (takeOptNum opts ts)
case po of ParseFailed i t -> pipeMessage $ "The parser failed at token "
ParseOk ts -> fromExprs ts ++ show i ++": "
ParseFailed i -> pipeMessage $ "The parser failed at token " ++ show t
++ show i ++": " ParseIncomplete -> pipeMessage "The sentence is not complete"
++ 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 = case opts of optLins pgf opts ts = concatMap (optLin pgf opts) ts
_ | 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 ->
(showCId (abstractName pgf) ++ ": " ++ showExpr [] t) : (abstractName pgf ++ ": " ++ showExpr [] t) :
[showCId lang ++ ": " ++ s | lang <- optLangs pgf opts, s<-linear pgf opts lang t] [concreteName concr ++ ": " ++ s | concr <- optLangs pgf opts, s<-linear opts concr t]
_ | isOpt "tabtreebank" opts -> _ -> [s | concr <- optLangs pgf opts, s <- linear opts concr t]
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 :: PGF -> [Option] -> CId -> Expr -> [String] linear :: [Option] -> Concr -> Expr -> [String]
linear pgf opts lang = let unl = unlex opts lang in case opts of linear opts concr = case opts of
_ | isOpt "all" opts -> concat . -- intersperse [[]] . _ | isOpt "all" opts -> concat .
map (map (unl . snd)) . tabularLinearizes pgf lang map (map snd) . tabularLinearizeAll concr
_ | isOpt "list" opts -> (:[]) . commaList . concat . _ | isOpt "list" opts -> (:[]) . commaList . concat .
map (map (unl . snd)) . tabularLinearizes pgf lang map (map snd) . tabularLinearizeAll concr
_ | isOpt "table" opts -> concat . -- intersperse [[]] . _ | isOpt "table" opts -> concat .
map (map (\(p,v) -> p+++":"+++unl v)) . tabularLinearizes pgf lang map (map (\(p,v) -> p+++":"+++v)) . tabularLinearizeAll concr
_ | isOpt "bracket" opts -> (:[]) . unwords . map showBracketedString . bracketedLinearize pgf lang _ | isOpt "bracket" opts -> (:[]) . unwords . map showBracketedString . bracketedLinearize concr
_ -> (:[]) . unl . linearize pgf lang _ -> (:[]) . linearize concr
-- 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 = mkCId . ("mk" ++) . showCId . lookValCat (abstract pgf) mk f = case functionType pgf f of
Just ty -> let (_,cat,_) = unType ty
unlex opts lang = stringOps Nothing (getUnlex opts lang ++ map prOpt opts) ---- in "mk" ++ cat
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"
optLangsFlag f pgf opts = case valStrOpts f "" opts of optLangFlag flag pgf opts =
"" -> languages pgf case optLangsFlag flag pgf opts of
lang -> map (completeLang pgf) (chunks ',' lang) [] -> fail "no language specified"
completeLang pgf la = let cla = (mkCId la) in (l:ls) -> return l
if elem cla (languages pgf)
then cla
else (mkCId (showCId (abstractName pgf) ++ la))
optLangFlag f pgf opts = head $ optLangsFlag f pgf opts ++ [wildCId] optLangsFlag flag pgf opts =
case valStrOpts flag "" opts of
"" -> Map.elems langs
str -> mapMaybe (completeLang pgf) (chunks ',' str)
where
langs = languages pgf
optOpenTypes opts = case valStrOpts "openclass" "" opts of completeLang pgf la =
"" -> [] mplus (Map.lookup la langs)
cats -> mapMaybe readType (chunks ',' cats) (Map.lookup (abstractName pgf ++ la) langs)
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 str = valStrOpts "cat" (showCId $ lookStartCat pgf) opts let readOpt str = case readType str of
in case readType str of Just ty -> case checkType pgf ty of
Just ty -> case checkType pgf ty of Left err -> error err
Left tcErr -> error $ render (ppTcError tcErr) Right ty -> ty
Right ty -> ty Nothing -> error ("Can't parse '"++str++"' as a type")
Nothing -> error ("Can't parse '"++str++"' as a type") in maybeStrOpts "cat" (startCat pgf) readOpt opts
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 es = return $ case es of returnFromExprs show_p es =
[] -> pipeMessage "no trees found" return $
_ -> fromExprs es case es of
[] -> pipeMessage "no trees found"
_ -> fromExprs show_p es
prGrammar (Env pgf mos) opts prGrammar pgf opts
| isOpt "pgf" opts = do | isOpt "pgf" opts = do
let pgf1 = if isOpt "opt" opts then optimizePGF pgf else pgf let outfile = valStrOpts "file" (abstractName pgf ++ ".pgf") opts
let outfile = valStrOpts "file" (showCId (abstractName pgf) ++ ".pgf") opts restricted $ writePGF outfile pgf
restricted $ encodeFile outfile pgf1
putStrLn $ "wrote file " ++ outfile putStrLn $ "wrote file " ++ outfile
return void return void
| isOpt "cats" opts = return $ fromString $ unwords $ map showCId $ categories pgf | isOpt "cats" opts = return $ fromString $ unwords $ categories pgf
| isOpt "funs" opts = return $ fromString $ unlines $ map showFun $ funsigs pgf | isOpt "funs" opts = return $ fromString $ unlines [showFun pgf f ty | f <- functions pgf, Just ty <- [functionType pgf f]]
| isOpt "fullform" opts = return $ fromString $ concatMap (morpho mos "" prFullFormLexicon) $ optLangs pgf opts | isOpt "fullform" opts = return $ fromString $ concatMap prFullFormLexicon $ optLangs pgf opts
| isOpt "langs" opts = return $ fromString $ unwords $ map showCId $ languages pgf | isOpt "langs" opts = return $ fromString $ unwords $ Map.keys $ languages pgf
| isOpt "lexc" opts = return $ fromString $ concatMap (morpho mos "" prLexcLexicon) $ optLangs pgf opts | isOpt "lexc" opts = return $ fromString $ concatMap prLexcLexicon $ optLangs pgf opts
| isOpt "missing" opts = return $ fromString $ unlines $ [unwords (showCId la:":": map showCId cs) | | isOpt "missing" opts = return $ fromString $ unlines $ [unwords (concreteName concr:":":[f | f <- functions pgf, not (hasLinearization concr f)]) |
la <- optLangs pgf opts, let cs = missingLins pgf la] concr <- optLangs pgf opts]
| isOpt "words" opts = return $ fromString $ concatMap (morpho mos "" prAllWords) $ optLangs pgf opts | isOpt "words" opts = return $ fromString $ concatMap 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
funsigs pgf = [(f,ty) | (f,(ty,_,_,_)) <- Map.assocs (funs (abstract pgf))] showFun pgf id ty = kwd++" "++ id ++ " : " ++ showType [] ty
showFun (f,ty) = showCId f ++ " : " ++ showType [] ty ++ " ;" where
kwd | functionIsDataCon pgf id = "data"
| otherwise = "fun"
morphos (Env pgf mos) opts s = morphos pgf opts s =
[(s,morpho mos [] (\mo -> lookupMorpho mo s) la) | la <- optLangs pgf opts] [(s,lookupMorpho concr s) | concr <- 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
"" -> [] "" -> []
@@ -931,18 +817,28 @@ 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 (mkCId x) app (OFlag op (VId x)) | Just (Right f) <- treeOp pgf op = f 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 -> Language -> Language -> Type -> IO () translationQuiz :: Maybe Expr -> PGF -> Concr -> Concr -> 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 -> Language -> Type -> IO () morphologyQuiz :: Maybe Expr -> PGF -> Concr -> 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
@@ -951,30 +847,28 @@ morphologyQuiz mex pgf ig typ = do
infinity :: Int infinity :: Int
infinity = 256 infinity = 256
prLexcLexicon :: Morpho -> String prLexcLexicon :: Concr -> String
prLexcLexicon mo = prLexcLexicon concr =
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 mo morpho = fullFormLexicon concr
prLexc l p = showCId l ++ concat (mkTags (words p)) prLexc l p = 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 :: Morpho -> String prFullFormLexicon :: Concr -> String
prFullFormLexicon mo = prFullFormLexicon concr =
unlines (map prMorphoAnalysis (fullFormLexicon mo)) unlines (map prMorphoAnalysis (fullFormLexicon concr))
prAllWords :: Morpho -> String prAllWords :: Concr -> String
prAllWords mo = prAllWords concr =
unwords [w | (w,_) <- fullFormLexicon mo] unwords [w | (w,_) <- fullFormLexicon concr]
prMorphoAnalysis :: (String,[(Lemma,Analysis)]) -> String
prMorphoAnalysis (w,lps) = prMorphoAnalysis (w,lps) =
unlines (w:[showCId l ++ " : " ++ p | (l,p) <- lps]) unlines (w:[l ++ " : " ++ p ++ show prob | (l,p,prob) <- 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

View File

@@ -1,831 +0,0 @@
{-# 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"

View File

@@ -3,7 +3,6 @@
-- 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
@@ -17,7 +16,7 @@ import GF.Text.Transliterations
import GF.Text.Lexing(stringOp,opInEnv) import GF.Text.Lexing(stringOp,opInEnv)
import Data.Char (isSpace) import Data.Char (isSpace)
import qualified PGF as H(showCId,showExpr,toATree,toTrie,Trie(..)) import PGF2(showExpr)
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
@@ -103,9 +102,7 @@ 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",
@@ -118,13 +115,11 @@ commonCommands = fmap (mapCommandExec liftSIO) $ Map.fromList [
let (os,fs) = optsAndFlags opts let (os,fs) = optsAndFlags opts
trans <- optTranslit opts trans <- optTranslit opts
case opts of if isOpt "lines" opts
_ | isOpt "lines" opts -> return $ fromStrings $ map (trans . stringOps (envFlag fs) (map prOpt os)) $ toStrings x then return $ fromStrings $ map (trans . stringOps (envFlag fs) (map prOpt os)) $ toStrings x
_ | isOpt "paragraphs" opts -> return $ fromStrings $ map (trans . stringOps (envFlag fs) (map prOpt os)) $ toParagraphs $ toStrings x else return ((fromString . trans . stringOps (envFlag fs) (map prOpt os) . toString) 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 = [
@@ -180,12 +175,6 @@ 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",
@@ -233,7 +222,6 @@ 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)"),
@@ -258,27 +246,6 @@ 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

View File

@@ -1,7 +1,7 @@
module GF.Command.Importing (importGrammar, importSource) where module GF.Command.Importing (importGrammar, importSource) where
import PGF import PGF2
import PGF.Internal(optimizePGF,unionPGF,msgUnionPGF) import PGF2.Internal(unionPGF)
import GF.Compile import GF.Compile
import GF.Compile.Multi (readMulti) import GF.Compile.Multi (readMulti)
@@ -17,14 +17,16 @@ 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 :: PGF -> Options -> [FilePath] -> IO PGF importGrammar :: Maybe PGF -> Options -> [FilePath] -> IO (Maybe 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" -> importCF opts files getBNFCRules bnfc2cf ".cf" -> fmap Just $ importCF opts files getBNFCRules bnfc2cf
".ebnf" -> importCF opts files getEBNFRules ebnf2cf ".ebnf" -> fmap Just $ 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
@@ -36,14 +38,15 @@ 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
pgf2 <- mapM readPGF files >>= return . foldl1 unionPGF mapM readPGF files >>= foldM ioUnionPGF pgf0
ioUnionPGF pgf0 pgf2
ext -> die $ "Unknown filename extension: " ++ show ext ext -> die $ "Unknown filename extension: " ++ show ext
ioUnionPGF :: PGF -> PGF -> IO PGF ioUnionPGF :: Maybe PGF -> PGF -> IO (Maybe PGF)
ioUnionPGF one two = case msgUnionPGF one two of ioUnionPGF Nothing two = return (Just two)
(pgf, Just msg) -> putStrLn msg >> return pgf ioUnionPGF (Just one) two =
(pgf,_) -> return pgf case unionPGF one two of
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)
@@ -56,7 +59,6 @@ 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"
let pgf = cf2pgf (last files) (mkCFG startCat Set.empty rules) probs <- maybe (return Map.empty) readProbabilitiesFromFile (flag optProbsFile opts)
probs <- maybe (return . defaultProbabilities) readProbabilitiesFromFile (flag optProbsFile opts) pgf let pgf = cf2pgf opts (last files) (mkCFG startCat Set.empty rules) probs
return $ setProbabilities probs return pgf
$ if flag optOptimizePGF opts then optimizePGF pgf else pgf

View File

@@ -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,17 +56,8 @@ 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 (app e)) AExpr e -> Command i os (AExpr (exprSubstitute e (toExprs args)))
_ -> 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
@@ -113,4 +104,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]) -- ignore piped one e = return (Exprs [(e,0)]) -- ignore piped

View File

@@ -1,6 +1,6 @@
module GF.Command.Parse(readCommandLine, pCommand) where module GF.Command.Parse(readCommandLine, pCommand) where
import PGF(pExpr,pIdent) import PGF2(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 <- pIdent <++ (char '%' >> fmap ('%':) pIdent) cmd <- readS_to_P pIdent <++ (char '%' >> fmap ('%':) (readS_to_P 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 <- pIdent flg <- readS_to_P 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 pExpr (fmap AExpr (readS_to_P pExpr)
<++ <++
(skipSpaces >> char '%' >> fmap AMacro pIdent)) (skipSpaces >> char '%' >> fmap AMacro (readS_to_P pIdent)))
pArgTerm = ATerm `fmap` readS_to_P sTerm pArgTerm = ATerm `fmap` readS_to_P sTerm
where where

View File

@@ -1,18 +1,17 @@
module GF.Command.TreeOperations ( module GF.Command.TreeOperations (
treeOp, treeOp,
allTreeOps, allTreeOps,
treeChunks
) where ) where
import PGF(Expr,PGF,CId,compute,mkApp,unApp,unapply,unMeta,exprSize,exprFunctions) import PGF2(Expr,PGF,Fun,compute,mkApp,unApp,unMeta,exprSize,exprFunctions)
import Data.List import Data.List
type TreeOp = [Expr] -> [Expr] type TreeOp = [Expr] -> [Expr]
treeOp :: PGF -> String -> Maybe (Either TreeOp (CId -> TreeOp)) treeOp :: PGF -> String -> Maybe (Either TreeOp (Fun -> 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 (CId -> TreeOp)))] allTreeOps :: PGF -> [(String,(String,Either TreeOp (Fun -> 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))),
@@ -34,16 +33,6 @@ 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

View File

@@ -1,6 +1,6 @@
module GF.Compile (compileToPGF, link, batchCompile, srcAbsName) where module GF.Compile (compileToPGF, link, batchCompile, srcAbsName) where
import GF.Compile.GrammarToPGF(mkCanon2pgf) import GF.Compile.GrammarToPGF(grammar2PGF)
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 +14,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,(<=<),filterM,liftM) import Control.Monad(foldM,when,(<=<))
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,8 +22,7 @@ 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 PGF.Internal(optimizePGF) import PGF2(PGF,readProbabilitiesFromFile)
import PGF(PGF,defaultProbabilities,setProbabilities,readProbabilitiesFromFile)
-- | 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'.
@@ -36,11 +35,10 @@ 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
pgf <- mkCanon2pgf opts gr abs probs <- liftIO (maybe (return Map.empty) readProbabilitiesFromFile (flag optProbsFile opts))
probs <- liftIO (maybe (return . defaultProbabilities) readProbabilitiesFromFile (flag optProbsFile opts) pgf) pgf <- grammar2PGF opts gr abs probs
when (verbAtLeast opts Normal) $ putStrE "OK" when (verbAtLeast opts Normal) $ putStrE "OK"
return $ setProbabilities probs return pgf
$ if flag optOptimizePGF opts then optimizePGF pgf else pgf
-- | 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
@@ -78,14 +76,10 @@ 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_dirs <- getLibraryDirectory (addOptions opts0 opts1) lib_dir <- getLibraryDirectory (addOptions opts0 opts1)
let opts = addOptions (fixRelativeLibPaths curr_dir lib_dirs opts0) opts1 let opts = addOptions (fixRelativeLibPaths curr_dir lib_dir 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 ----
@@ -98,17 +92,13 @@ 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 then do lib_dir <- getLibraryDirectory opts1
lib_dirs <- getLibraryDirectory opts1 let file1 = lib_dir </> file
let candidates = [ lib_dir </> file | lib_dir <- lib_dirs ] exists <- doesFileExist file1
putIfVerb opts1 (render ("looking for: " $$ nest 2 candidates)) if exists
file1s <- filterM doesFileExist candidates then return file1
case length file1s of else raise (render ("None of these files exists:" $$ nest 2 (file $$ file1)))
0 -> raise (render ("Unable to find: " $$ nest 2 candidates)) else raise (render ("File" <+> file <+> "does not exist."))
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

View File

@@ -1,99 +1,110 @@
{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleContexts, ImplicitParams #-}
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 PGF import PGF2
import PGF.Internal import PGF2.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 :: FilePath -> ParamCFG -> PGF cf2pgf :: Options -> FilePath -> ParamCFG -> Map.Map Fun Double -> PGF
cf2pgf fpath cf = cf2pgf opts fpath cf probs =
let pgf = PGF Map.empty aname (cf2abstr cf) (Map.singleton cname (cf2concr cf)) build (let abstr = cf2abstr cf probs
in updateProductionIndices pgf in newPGF [] aname abstr [(cname, cf2concr opts abstr cf)])
where where
name = justModuleName fpath name = justModuleName fpath
aname = mkCId (name ++ "Abs") aname = name ++ "Abs"
cname = mkCId name cname = name
cf2abstr :: ParamCFG -> Abstr cf2abstr :: (?builder :: Builder s) => ParamCFG -> Map.Map Fun Double -> B s AbstrInfo
cf2abstr cfg = Abstr aflags afuns acats cf2abstr cfg probs = newAbstr aflags acats afuns
where where
aflags = Map.singleton (mkCId "startcat") (LStr (fst (cfgStartCat cfg))) aflags = [("startcat", LStr (fst (cfgStartCat cfg)))]
acats = Map.fromList [(cat, ([], [(0,mkRuleName rule) | rule <- rules], 0)) acats = [(c', [], toLogProb (fromMaybe 0 (Map.lookup c' probs))) | cat <- allCats' cfg, let c' = cat2id cat]
| (cat,rules) <- (Map.toList . Map.fromListWith (++)) afuns = [(f', dTyp [hypo Explicit "_" (dTyp [] (cat2id c) []) | NonTerminal c <- ruleRhs rule] (cat2id (ruleLhs rule)) [], 0, [], toLogProb (fromMaybe 0 (Map.lookup f' funs_probs)))
[(cat2id cat, catRules cfg cat) | | rule <- allRules cfg
cat <- allCats' cfg]] , let f' = mkRuleName rule]
afuns = Map.fromList [(mkRuleName rule, (cftype [cat2id c | NonTerminal c <- ruleRhs rule] (cat2id (ruleLhs rule)), 0, Nothing, 0))
| rule <- allRules cfg]
cat2id = mkCId . fst funs_probs = (Map.fromList . concat . Map.elems . fmap pad . Map.fromListWith (++))
[(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)
cf2concr :: ParamCFG -> Concr toLogProb = realToFrac . negate . log
cf2concr cfg = Concr Map.empty Map.empty
cncfuns lindefsrefs lindefsrefs cat2id = fst
sequences productions
IntMap.empty Map.empty cf2concr :: (?builder :: Builder s) => Options -> B s AbstrInfo -> ParamCFG -> B s ConcrInfo
cnccats cf2concr opts abstr cfg =
IntMap.empty let (lindefs',linrefs',productions',cncfuns',sequences',cnccats') =
totalCats (if flag optOptimizePGF opts then optimizePGF (fst (cfgStartCat cfg)) else id)
(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
sequences0 = Set.fromList (listArray (0,0) [SymCat 0 0] : idSeq = [SymCat 0 0]
map mkSequence rules)
sequences = listArray (0,Set.size sequences0-1) (Set.toList sequences0)
idFun = CncFun wildCId (listArray (0,0) [seqid]) sequences0 = Set.fromList (idSeq :
where map mkSequence rules)
seq = listArray (0,0) [SymCat 0 0] sequences = Set.toList sequences0
seqid = binSearch seq sequences (bounds sequences)
idFun = ("_",[Set.findIndex idSeq sequences0])
((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 = listArray (0,fun_cnt-1) (reverse cncfuns0) cncfuns = reverse cncfuns0
lbls = listArray (0,0) ["s"] lbls = ["s"]
(fid,cnccats0) = (mapAccumL mkCncCat 0 . Map.toList . Map.fromListWith max) (fid,cnccats) = (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 = lindefsrefs = map mkLinDefRef cats
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 = binSearch (mkSequence rule) sequences (bounds sequences) seqid = Set.findIndex (mkSequence rule) sequences0
fun = CncFun (mkRuleName rule) (listArray (0,0) [seqid]) fun = (mkRuleName rule, [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 = listArray (0,length syms-1) syms mkSequence rule = snd $ mapAccumL convertSymbol 0 (ruleRhs rule)
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, (mkCId cat, CncCat fidInt fidInt lbls)) | cat == "Int" = (fid, (cat, fidInt, fidInt, lbls))
| cat == "Float" = (fid, (mkCId cat, CncCat fidFloat fidFloat lbls)) | cat == "Float" = (fid, (cat, fidFloat, fidFloat, lbls))
| cat == "String" = (fid, (mkCId cat, CncCat fidString fidString lbls)) | cat == "String" = (fid, (cat, fidString, fidString, lbls))
| otherwise = let fid' = fid+n+1 | otherwise = let fid' = fid+n+1
in fid' `seq` (fid', (mkCId cat,CncCat fid (fid+n) lbls)) in fid' `seq` (fid', (cat, 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 ) =
@@ -105,22 +116,13 @@ cf2concr cfg = Concr Map.empty Map.empty
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 (Set.insert prod set) prods Just set -> IntMap.insert fid (prod:set) prods
Nothing -> IntMap.insert fid (Set.singleton prod) prods Nothing -> IntMap.insert fid [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 Map.lookup (mkCId cat) cnccats of case [start | (cat',start,_,_) <- cnccats, cat == cat'] of
Just (CncCat fid _ _) -> fid+p (start:_) -> 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 ) =
@@ -131,4 +133,4 @@ cf2concr cfg = Concr Map.empty Map.empty
mkRuleName rule = mkRuleName rule =
case ruleName rule of case ruleName rule of
CFObj n _ -> n CFObj n _ -> n
_ -> wildCId _ -> "_"

View File

@@ -21,8 +21,8 @@
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
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
@@ -175,7 +175,7 @@ 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)
@@ -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 $$

View File

@@ -30,11 +30,12 @@ import Debug.Trace(trace)
normalForm :: GlobalEnv -> L Ident -> Term -> Term normalForm :: GlobalEnv -> L Ident -> Term -> Term
normalForm (GE gr rv opts _) loc = err (bugloc loc) id . nfx (GE gr rv opts loc) 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 nfx env@(GE _ _ _ loc) t = do
v <- eval env [] t v <- eval env [] t
case value2term loc [] v of return (value2term loc [] v)
Left i -> fail ("variable #"++show i++" is out of scope") -- Old value2term error message:
Right t -> return t -- Left i -> fail ("variable #"++show i++" is out of scope")
eval :: GlobalEnv -> Env -> Term -> Err Value eval :: GlobalEnv -> Env -> Term -> Err Value
eval (GE gr rvs opts loc) env t = ($ (map snd env)) # value cenv t eval (GE gr rvs opts loc) env t = ($ (map snd env)) # value cenv t
@@ -288,9 +289,9 @@ glue env (v1,v2) = glu v1 v2
(v1,v2) -> if flag optPlusAsBind (opts env) (v1,v2) -> if flag optPlusAsBind (opts env)
then VC v1 (VC (VApp BIND []) v2) then VC v1 (VC (VApp BIND []) v2)
else let loc = gloc env else let loc = gloc env
vt v = case value2term loc (local env) v of vt v = value2term loc (local env) v
Left i -> Error ('#':show i) -- Old value2term error message:
Right t -> t -- Left i -> Error ('#':show i)
originalMsg = render $ ppL loc (hang "unsupported token gluing" 4 originalMsg = render $ ppL loc (hang "unsupported token gluing" 4
(Glue (vt v1) (vt v2))) (Glue (vt v1) (vt v2)))
term = render $ pp $ Glue (vt v1) (vt v2) term = render $ pp $ Glue (vt v1) (vt v2)
@@ -355,9 +356,9 @@ select env vv =
(v1,v2) -> ok2 VS v1 v2 (v1,v2) -> ok2 VS v1 v2
match loc cs v = match loc cs v =
case value2term loc [] v of err bad return (matchPattern cs (value2term loc [] v))
Left i -> bad ("variable #"++show i++" is out of scope") -- Old value2term error message:
Right t -> err bad return (matchPattern cs t) -- Left i -> bad ("variable #"++show i++" is out of scope")
where where
bad = fail . ("In pattern matching: "++) bad = fail . ("In pattern matching: "++)
@@ -383,9 +384,8 @@ valueTable env i cs =
wild = case i of TWild _ -> True; _ -> False wild = case i of TWild _ -> True; _ -> False
convertv cs' vty = convertv cs' vty =
case value2term (gloc env) [] vty of convert' cs' =<< paramValues'' env (value2term (gloc env) [] vty)
Left i -> fail ("variable #"++show i++" is out of scope") -- Old value2term error message: 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' ty = convert' cs' =<< paramValues' env ty
@@ -492,58 +492,60 @@ vtrace loc arg res = trace (render (hang (pv arg) 4 ("->"<+>pv res))) res
pf (_,VString n) = pp n pf (_,VString n) = pp n
pf (_,v) = ppV v pf (_,v) = ppV v
pa (_,v) = ppV v pa (_,v) = ppV v
ppV v = case value2term' True loc [] v of ppV v = ppTerm Unqualified 10 (value2term' True loc [] v)
Left i -> "variable #" <> pp i <+> "is out of scope" -- Old value2term error message:
Right t -> ppTerm Unqualified 10 t -- Left i -> "variable #" <> pp i <+> "is out of scope"
-- | Convert a value back to a term -- | Convert a value back to a term
value2term :: GLocation -> [Ident] -> Value -> Either Int Term value2term :: GLocation -> [Ident] -> Value -> Term
value2term = value2term' False value2term = value2term' False
value2term' :: Bool -> p -> [Ident] -> Value -> Term
value2term' stop loc xs v0 = value2term' stop loc xs v0 =
case v0 of case v0 of
VApp pre vs -> liftM (foldl App (Q (cPredef,predefName pre))) (mapM v2t vs) VApp pre vs -> applyMany (Q (cPredef,predefName pre)) vs
VCApp f vs -> liftM (foldl App (QC f)) (mapM v2t vs) VCApp f vs -> applyMany (QC f) vs
VGen j vs -> liftM2 (foldl App) (var j) (mapM v2t vs) VGen j vs -> applyMany (var j) vs
VMeta j env vs -> liftM (foldl App (Meta j)) (mapM v2t vs) VMeta j env vs -> applyMany (Meta j) vs
VProd bt v x f -> liftM2 (Prod bt x) (v2t v) (v2t' x f) VProd bt v x f -> Prod bt x (v2t v) (v2t' x f)
VAbs bt x f -> liftM (Abs bt x) (v2t' x f) VAbs bt x f -> Abs bt x (v2t' x f)
VInt n -> return (EInt n) VInt n -> EInt n
VFloat f -> return (EFloat f) VFloat f -> EFloat f
VString s -> return (if null s then Empty else K s) VString s -> if null s then Empty else K s
VSort s -> return (Sort s) VSort s -> Sort s
VImplArg v -> liftM ImplArg (v2t v) VImplArg v -> ImplArg (v2t v)
VTblType p res -> liftM2 Table (v2t p) (v2t res) VTblType p res -> Table (v2t p) (v2t res)
VRecType rs -> liftM RecType (mapM (\(l,v) -> fmap ((,) l) (v2t v)) rs) VRecType rs -> RecType [(l, v2t v) | (l,v) <- rs]
VRec as -> liftM R (mapM (\(l,v) -> v2t v >>= \t -> return (l,(Nothing,t))) as) VRec as -> R [(l, (Nothing, v2t v)) | (l,v) <- as]
VV t _ vs -> liftM (V t) (mapM v2t vs) VV t _ vs -> V t (map v2t vs)
VT wild v cs -> v2t v >>= \t -> liftM (T ((if wild then TWild else TTyped) t)) (mapM nfcase cs) VT wild v cs -> T ((if wild then TWild else TTyped) (v2t v)) (map nfcase cs)
VFV vs -> liftM FV (mapM v2t vs) VFV vs -> FV (map v2t vs)
VC v1 v2 -> liftM2 C (v2t v1) (v2t v2) VC v1 v2 -> C (v2t v1) (v2t v2)
VS v1 v2 -> liftM2 S (v2t v1) (v2t v2) VS v1 v2 -> S (v2t v1) (v2t v2)
VP v l -> v2t v >>= \t -> return (P t l) VP v l -> P (v2t v) l
VPatt p -> return (EPatt p) VPatt p -> EPatt p
VPattType v -> v2t v >>= return . EPattType VPattType v -> EPattType $ v2t v
VAlts v vvs -> liftM2 Alts (v2t v) (mapM (\(x,y) -> liftM2 (,) (v2t x) (v2t y)) vvs) VAlts v vvs -> Alts (v2t v) [(v2t x, v2t y) | (x,y) <- vvs]
VStrs vs -> liftM Strs (mapM v2t vs) VStrs vs -> Strs (map v2t vs)
-- VGlue v1 v2 -> Glue (v2t v1) (v2t v2) -- VGlue v1 v2 -> Glue (v2t v1) (v2t v2)
-- VExtR v1 v2 -> ExtR (v2t v1) (v2t v2) -- VExtR v1 v2 -> ExtR (v2t v1) (v2t v2)
VError err -> return (Error err) VError err -> Error err
where where
applyMany f vs = foldl App f (map v2t vs)
v2t = v2txs xs v2t = v2txs xs
v2txs = value2term' stop loc v2txs = value2term' stop loc
v2t' x f = v2txs (x:xs) (bind f (gen xs)) v2t' x f = v2txs (x:xs) (bind f (gen xs))
var j var j
| j<length xs = Right (Vr (reverse xs !! j)) | j<length xs = Vr (reverse xs !! j)
| otherwise = Left j | otherwise = error ("variable #"++show j++" is out of scope")
pushs xs e = foldr push e xs pushs xs e = foldr push e xs
push x (env,xs) = ((x,gen xs):env,x:xs) push x (env,xs) = ((x,gen xs):env,x:xs)
gen xs = VGen (length xs) [] gen xs = VGen (length xs) []
nfcase (p,f) = liftM ((,) p) (v2txs xs' (bind f env')) nfcase (p,f) = (,) p (v2txs xs' (bind f env'))
where (env',xs') = pushs (pattVars p) ([],xs) where (env',xs') = pushs (pattVars p) ([],xs)
bind (Bind f) x = if stop bind (Bind f) x = if stop

View File

@@ -27,6 +27,10 @@ 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

View File

@@ -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 PGF.Internal(BindType) import PGF2(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)

View File

@@ -3,11 +3,7 @@ module GF.Compile.ExampleBased (
configureExBased configureExBased
) where ) where
import PGF import PGF2
--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])
@@ -37,47 +33,38 @@ 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 fst (parse_ pgf lang typ (Just 4) ex) of ws <- case parse lang typ 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 rank ts of case 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 t appn (printExp conf (fst t))
mapM_ (appn . (" --- " ++)) tt mapM_ (appn . (" --- " ++) . printExp conf . fst) 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 :: Language, language :: Concr,
printExp :: Tree -> String printExp :: Expr -> String
} }
configureExBased :: PGF -> Morpho -> Language -> (Tree -> String) -> ExConfiguration configureExBased :: PGF -> Concr -> (Expr -> String) -> ExConfiguration
configureExBased pgf morpho lang pr = ExConf pgf morpho False lang pr configureExBased pgf concr pr = ExConf pgf False concr pr

View File

@@ -1,14 +1,10 @@
module GF.Compile.Export where module GF.Compile.Export where
import PGF import PGF2
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
@@ -22,6 +18,7 @@ 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
@@ -35,15 +32,12 @@ 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" (render . ppPGF) FmtPGFPretty -> multi "txt" (showPGF)
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)
@@ -57,20 +51,13 @@ exportPGF opts fmt pgf =
FmtRegExp -> single "rexp" regexpPrinter FmtRegExp -> single "rexp" regexpPrinter
FmtFA -> single "dot" slfGraphvizPrinter FmtFA -> single "dot" slfGraphvizPrinter
where where
name = fromMaybe (showCId (abstractName pgf)) (flag optName opts) name = fromMaybe (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 -> CId -> String) -> [(FilePath,String)] single :: String -> (PGF -> Concr -> String) -> [(FilePath,String)]
single ext pr = [(showCId cnc <.> ext, pr pgf cnc) | cnc <- languages pgf] single ext pr = [(concreteName cnc <.> ext, pr pgf cnc) | cnc <- Map.elems (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

View File

@@ -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 PGF(CId,utf8CId) import PGF2.Internal(CodeLabel,Instr(..),IVal(..),TailInfo(..),Literal(..))
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 (i2i id) (Q (_,id)) -> CASE (showIdent 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 (i2i id)) args) -> (h0,bs,eval st (GLOBAL (showIdent 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 (i2i id)) []) then (h0,bs,eval st (GLOBAL (showIdent id)) [])
else let h1 = h0 + 2 + n_args else let h1 = h0 + 2 + n_args
in (h1,bs,PUT_CONSTR (i2i id):is1++eval st (HEAP h0) []) in (h1,bs,PUT_CONSTR (showIdent 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 (i2i id) : PUT_CONSTR (showIdent 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 (i2i id),[]) Ok (_,Just _) -> (h0,bs,GLOBAL (showIdent 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 (i2i id),[]) then (h0,bs,GLOBAL (showIdent 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 (i2i id) : PUT_CONSTR (showIdent 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 (i2i id) : is2)) in (h2,bs1,HEAP h1,is1 ++ (PUT_CONSTR (showIdent 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 (i2i id) : PUT_CONSTR (showIdent id) :
is2 ++ is2 ++
TUCK (ARG_VAR 0) diff : TUCK (ARG_VAR 0) diff :
EVAL (HEAP h0) (TailCall diff) : EVAL (HEAP h0) (TailCall diff) :
@@ -298,9 +298,6 @@ 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

View File

@@ -13,8 +13,9 @@ module GF.Compile.GeneratePMCFG
(generatePMCFG, pgfCncCat, addPMCFG, resourceValues (generatePMCFG, pgfCncCat, addPMCFG, resourceValues
) where ) where
--import PGF.CId import qualified PGF2 as PGF2
import PGF.Internal as PGF(CncCat(..),Symbol(..),fidVar) import qualified PGF2.Internal as PGF2
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)
@@ -69,7 +70,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 (GF.Grammar.CncFun mty@(Just (cat,cont,val)) mlin@(Just (L loc term)) mprn Nothing) = do addPMCFG opts gr cenv opath am cm seqs id (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]
@@ -93,7 +94,7 @@ addPMCFG opts gr cenv opath am cm seqs id (GF.Grammar.CncFun mty@(Just (cat,cont
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,GF.Grammar.CncFun mty mlin mprn (Just pmcfg)) return (seqs1,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)
@@ -103,11 +104,11 @@ addPMCFG opts gr cenv opath am cm seqs id (GF.Grammar.CncFun mty@(Just (cat,cont
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 (GF.Grammar.CncCat mty@(Just (L _ lincat)) addPMCFG opts gr cenv opath am cm seqs id (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
@@ -132,7 +133,7 @@ addPMCFG opts gr cenv opath am cm seqs id (GF.Grammar.CncCat mty@(Just (L _ linc
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,GF.Grammar.CncCat mty mdef mref mprn (Just pmcfg)) seqs2 `seq` pmcfg `seq` return (seqs2,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'
@@ -158,12 +159,15 @@ 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 -> Type -> Int -> CncCat pgfCncCat :: SourceGrammar -> PGF2.Cat -> Type -> Int -> (PGF2.Cat,Int,Int,[String])
pgfCncCat gr lincat index = pgfCncCat gr id lincat index =
let ((_,size),schema) = computeCatRange gr lincat let ((_,size),schema) = computeCatRange gr lincat
in PGF.CncCat index (index+size-1) in ( id
(mkArray (map (renderStyle style{mode=OneLineMode} . ppPath) , index
(getStrPaths schema))) , index+size-1
, 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 []
@@ -475,7 +479,7 @@ goV (CPar t) rpath ss = restrictHead (reversePath rpath) t >> return ss
---------------------------------------------------------------------- ----------------------------------------------------------------------
-- SeqSet -- SeqSet
type SeqSet = Map.Map Sequence SeqId type SeqSet = Map.Map [Symbol] 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
@@ -504,13 +508,11 @@ 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 lst = addSequence seqs seq =
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
------------------------------------------------------------ ------------------------------------------------------------

View File

@@ -50,20 +50,13 @@ 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}
optCoding' = renameEncoding `fmap` flag optEncoding (mflags mi0) case renameEncoding `fmap` flag optEncoding (mflags mi0) of
case (optCoding,optCoding') of Just coding' ->
{- 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 ()
--liftIO $ transcodeModule' (i,mi) -- old lexer return (i,mi)
return (i,mi) -- new lexer
getBNFCRules :: Options -> FilePath -> IOE [BNFCRule] getBNFCRules :: Options -> FilePath -> IOE [BNFCRule]
getBNFCRules opts fpath = do getBNFCRules opts fpath = do

View File

@@ -19,7 +19,7 @@ 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,ident2raw,rawIdentS,showIdent,isWildIdent)
import GF.Infra.Option(Options,optionsPGF) import GF.Infra.Option(Options,optionsPGF)
import PGF.Internal(Literal(..)) import PGF2.Internal(Literal(..))
import GF.Compile.Compute.Concrete(GlobalEnv,normalForm,resourceValues) import GF.Compile.Compute.Concrete(GlobalEnv,normalForm,resourceValues)
import GF.Grammar.Canonical as C import GF.Grammar.Canonical as C
import System.FilePath ((</>), (<.>)) import System.FilePath ((</>), (<.>))
@@ -92,7 +92,7 @@ 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 :: 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 _ ->

View File

@@ -1,17 +1,14 @@
{-# LANGUAGE BangPatterns, FlexibleContexts #-} {-# LANGUAGE ImplicitParams, BangPatterns, FlexibleContexts, MagicHash #-}
module GF.Compile.GrammarToPGF (mkCanon2pgf) where module GF.Compile.GrammarToPGF (grammar2PGF) 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 PGF(CId,mkCId,utf8CId) import PGF2 hiding (mkType)
import PGF.Internal(fidInt,fidFloat,fidString,fidVar) import PGF2.Internal
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 import GF.Grammar.Grammar hiding (Production)
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
@@ -22,111 +19,141 @@ 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)
mkCanon2pgf :: Options -> SourceGrammar -> ModuleName -> IOE D.PGF grammar2PGF :: Options -> SourceGrammar -> ModuleName -> Map.Map PGF2.Fun Double -> IO PGF
mkCanon2pgf opts gr am = do grammar2PGF opts gr am probs = do
(an,abs) <- mkAbstr am cnc_infos <- getConcreteInfos gr am
cncs <- mapM mkConcr (allConcretes gr am) return $
return $ updateProductionIndices (D.PGF Map.empty an abs (Map.fromList cncs)) build (let gflags = if flag optSplitPGF opts
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 am = return (mi2i am, D.Abstr flags funs cats) mkAbstr :: (?builder :: Builder s) => ModuleName -> Map.Map PGF2.Fun Double -> (AbsName, B s AbstrInfo)
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 = Map.fromList [(mkCId f,x) | (f,x) <- optionsPGF aflags] flags = optionsPGF aflags
funs = Map.fromList [(i2i f, (mkType [] ty, arity, mkDef gr arity mdef, 0)) | toLogProb = realToFrac . negate . log
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]
cats = Map.fromList [(i2i c, (snd (mkContext [] cont),catfuns c, 0)) | funs_probs = (Map.fromList . concat . Map.elems . fmap pad . Map.fromListWith (++))
((m,c),AbsCat (Just (L _ cont))) <- adefs] [(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)
catfuns cat = mkConcr opts abs (cm,ex_seqs,cdefs) =
[(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 = C.compareCaseInsensitve | otherwise = compareCaseInsensitive
(ex_seqs,cdefs) <- addMissingPMCFGs flags = optionsPGF aflags
Map.empty
([((cPredefAbs,c), CncCat (Just (L NoLoc GM.defLinType)) Nothing Nothing Nothing Nothing) | c <- [cInt,cFloat,cString]] ++
Look.allOrigInfos gr cm)
let flags = Map.fromList [(mkCId f,x) | (f,x) <- optionsPGF cflags] seqs = (mkSetArray . Set.fromList . concat) $
(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_arr ciCmp seqs cdefs fid_cnt1 cnccats = genCncFuns gr am cm ex_seqs ciCmp seqs cdefs fid_cnt1 cnccat_ranges
printnames = genPrintNames cdefs printnames = genPrintNames cdefs
return (mi2i cm, D.Concr flags
printnames startCat = (fromMaybe "S" (flag optStartCat aflags))
cncfuns
lindefs (lindefs',linrefs',productions',cncfuns',sequences',cnccats') =
linrefs (if flag optOptimizePGF opts then optimizePGF startCat else id)
seqs (lindefs,linrefs,productions,cncfuns,elems seqs,cnccats)
productions
IntMap.empty in (mi2i cm, newConcr abs
Map.empty flags
cnccats printnames
IntMap.empty lindefs'
fid_cnt2) linrefs'
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 seqs [] = return (seqs,[]) addMissingPMCFGs cm seqs [] = return (seqs,[])
addMissingPMCFGs seqs (((m,id), info):is) = do addMissingPMCFGs cm 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,is ) <- addMissingPMCFGs seqs is (seqs,infos) <- addMissingPMCFGs cm seqs is
return (seqs, ((m,id), info) : is) return (seqs, ((m,id), info) : infos)
i2i :: Ident -> CId i2i :: Ident -> String
i2i = utf8CId . ident2utf8 i2i = showIdent
mi2i :: ModuleName -> CId mi2i :: ModuleName -> String
mi2i (MN i) = i2i i mi2i (MN i) = i2i i
mkType :: [Ident] -> A.Type -> C.Type mkType :: (?builder :: Builder s) => [Ident] -> A.Type -> B s PGF2.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 C.DTyp hyps' (i2i cat) (map (mkExp scope') args) in dTyp hyps' (i2i cat) (map (mkExp scope') args)
mkExp :: [Ident] -> A.Term -> C.Expr mkExp :: (?builder :: Builder s) => [Ident] -> A.Term -> B s Expr
mkExp scope t = mkExp scope t =
case t of case t of
Q (_,c) -> C.EFun (i2i c) Q (_,c) -> eFun (i2i c)
QC (_,c) -> C.EFun (i2i c) QC (_,c) -> eFun (i2i c)
Vr x -> case lookup x (zip scope [0..]) of Vr x -> case lookup x (zip scope [0..]) of
Just i -> C.EVar i Just i -> eVar i
Nothing -> C.EMeta 0 Nothing -> eMeta 0
Abs b x t-> C.EAbs b (i2i x) (mkExp (x:scope) t) Abs b x t-> eAbs b (i2i x) (mkExp (x:scope) t)
App t1 t2-> C.EApp (mkExp scope t1) (mkExp scope t2) App t1 t2-> eApp (mkExp scope t1) (mkExp scope t2)
EInt i -> C.ELit (C.LInt (fromIntegral i)) EInt i -> eLit (LInt (fromIntegral i))
EFloat f -> C.ELit (C.LFlt f) EFloat f -> eLit (LFlt f)
K s -> C.ELit (C.LStr s) K s -> eLit (LStr s)
Meta i -> C.EMeta i Meta i -> eMeta i
_ -> C.EMeta 0 _ -> 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
@@ -141,67 +168,64 @@ 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 :: [Ident] -> A.Context -> ([Ident],[C.Hypo]) mkContext :: (?builder :: Builder s) => [Ident] -> A.Context -> ([Ident],[B s PGF2.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,(bt,i2i x,ty')) then ( scope,hypo bt (i2i x) ty')
else (x:scope,(bt,i2i x,ty'))) scope hyps else (x:scope,hypo bt (i2i x) ty')) scope hyps
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 (Just eqs) = generateByteCode gr arity eqs
,generateByteCode gr arity eqs mkDef gr arity Nothing = []
)
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 = genCncCats gr am cm cdefs = mkCncCats 0 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 lincat fidInt let cc = pgfCncCat gr (i2i id) lincat fidInt
(index',cats) = mkCncCats index cdefs (index',cats) = mkCncCats index cdefs
in (index', (i2i id,cc) : cats) in (index', cc : cats)
| id == cFloat = | id == cFloat =
let cc = pgfCncCat gr lincat fidFloat let cc = pgfCncCat gr (i2i id) lincat fidFloat
(index',cats) = mkCncCats index cdefs (index',cats) = mkCncCats index cdefs
in (index', (i2i id,cc) : cats) in (index', cc : cats)
| id == cString = | id == cString =
let cc = pgfCncCat gr lincat fidString let cc = pgfCncCat gr (i2i id) lincat fidString
(index',cats) = mkCncCats index cdefs (index',cats) = mkCncCats index cdefs
in (index', (i2i id,cc) : cats) in (index', cc : cats)
| otherwise = | otherwise =
let cc@(C.CncCat _s e _) = pgfCncCat gr lincat index let cc@(_, _s, e, _) = pgfCncCat gr (i2i id) lincat index
(index',cats) = mkCncCats (e+1) cdefs (index',cats) = mkCncCats (e+1) cdefs
in (index', (i2i id,cc) : cats) in (index', cc : cats)
mkCncCats index (_ :cdefs) = mkCncCats index cdefs mkCncCats index (_ :cdefs) = mkCncCats index cdefs
genCncFuns :: Grammar genCncFuns :: Grammar
-> ModuleName -> ModuleName
-> ModuleName -> ModuleName
-> Array SeqId Sequence -> Array SeqId [Symbol]
-> (Sequence -> Sequence -> Ordering) -> ([Symbol] -> [Symbol] -> Ordering)
-> Array SeqId Sequence -> Array SeqId [Symbol]
-> [(QIdent, Info)] -> [(QIdent, Info)]
-> FId -> FId
-> Map.Map CId D.CncCat -> Map.Map PGF2.Cat (Int,Int)
-> (FId, -> (FId,
IntMap.IntMap (Set.Set D.Production), [(FId, [Production])],
IntMap.IntMap [FunId], [(FId, [FunId])],
IntMap.IntMap [FunId], [(FId, [FunId])],
Array FunId D.CncFun) [(PGF2.Fun,[SeqId])])
genCncFuns gr am cm ex_seqs ciCmp seqs cdefs fid_cnt cnccats = genCncFuns gr am cm ex_seqs ciCmp seqs cdefs fid_cnt cnccat_ranges =
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,prods) = mkCncFuns cdefs fid_cnt1 funs_cnt1 funs1 lindefs Map.empty IntMap.empty (fid_cnt2,funs_cnt2,funs2,prods0) = mkCncFuns cdefs fid_cnt1 funs_cnt1 funs1 lindefs Map.empty IntMap.empty
in (fid_cnt2,prods,lindefs,linrefs,array (0,funs_cnt2-1) funs2) prods = [(fid,Set.toList prodSet) | (fid,prodSet) <- IntMap.toList prods0]
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
@@ -210,14 +234,13 @@ genCncFuns gr am cm ex_seqs ciCmp seqs cdefs fid_cnt cnccats =
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 ---Ok ty_C = fmap GM.typeForm (Look.lookupFunType gr am id) let ty_C = err error (\x -> x) $ 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')
@@ -228,23 +251,23 @@ genCncFuns gr am cm ex_seqs ciCmp seqs cdefs fid_cnt cnccats =
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 (Production fid0 funid0 args0) = toProd lindefs (ctxt_C,res_C,_) offs st (A.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 (C.PApply (offs+funid0)) (sequence args)) set0 = Set.fromList (map (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 C.PArg (mkFId arg_C fid0)) ctxt) [fid0] -> (st,map (flip 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 C.PArg fid) ctxt) Just fid -> (st,map (flip 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 C.PCoerce fids)) prods !prods' = IntMap.insert fid_cnt (Set.fromList (map PCoerce fids)) prods
in ((fid_cnt+1,crc',prods'),map (flip C.PArg fid_cnt) ctxt) in ((fid_cnt+1,crc',prods'),map (flip 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
@@ -252,14 +275,14 @@ genCncFuns gr am cm ex_seqs ciCmp seqs cdefs fid_cnt cnccats =
mkLinDefId id = prefixIdent "lindef " id mkLinDefId id = prefixIdent "lindef " id
toLinDef res offs lindefs (Production fid0 funid0 args) = toLinDef res offs lindefs (A.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 (Production fid0 funid0 [fargs]) = toLinRef res offs linrefs (A.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
@@ -267,20 +290,20 @@ genCncFuns gr am cm ex_seqs ciCmp seqs cdefs fid_cnt cnccats =
fids = map (mkFId res) fargs fids = map (mkFId res) fargs
mkFId (_,cat) fid0 = mkFId (_,cat) fid0 =
case Map.lookup (i2i cat) cnccats of case Map.lookup (i2i cat) cnccat_ranges of
Just (C.CncCat s e _) -> s+fid0 Just (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) cnccats of case Map.lookup (i2i cat) cnccat_ranges of
Just (C.CncCat s e _) -> [(C.fidVar,fid) | fid <- [s..e], Just _ <- [IntMap.lookup fid lindefs]] Just (s,e) -> [(fid,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 (offs+funid0,C.CncFun (i2i id) (amap (newIndex mseqs) lins0)):funs in (i2i id, map (newIndex mseqs) (elems lins0)):funs
where where
newIndex mseqs i = binSearch (mseqs ! i) seqs (bounds seqs) newIndex mseqs i = binSearch (mseqs ! i) seqs (bounds seqs)
@@ -293,8 +316,9 @@ genCncFuns gr am cm ex_seqs ciCmp seqs cdefs fid_cnt cnccats =
where where
k = (i+j) `div` 2 k = (i+j) `div` 2
genPrintNames cdefs = genPrintNames cdefs =
Map.fromAscList [(i2i id, name) | ((m,id),info) <- cdefs, name <- prn info] [(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]
@@ -306,3 +330,118 @@ 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

View File

@@ -0,0 +1,189 @@
{-# 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

View File

@@ -16,13 +16,14 @@
module GF.Compile.PGFtoHaskell (grammar2haskell) where module GF.Compile.PGFtoHaskell (grammar2haskell) where
import PGF(showCId) import PGF2
import PGF.Internal import PGF2.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,intercalate,intersperse,groupBy,sortBy)
import Data.Maybe(mapMaybe)
import qualified Data.Map as Map import qualified Data.Map as Map
type Prefix = String -> String type Prefix = String -> String
@@ -258,7 +259,7 @@ fInstance gId lexical m (cat,rules) =
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 +++ "(showCId i)" else "") ++++ (if lexical cat then " Just (i,[]) -> " ++ lexicalConstructor cat +++ "i" else "") ++++
" _ -> error (\"no" +++ cat ++ " \" ++ show t)" " _ -> error (\"no" +++ cat ++ " \" ++ show t)"
where where
isList = isListCat (cat,rules) isList = isListCat (cat,rules)
@@ -280,18 +281,21 @@ fInstance gId lexical m (cat,rules) =
--type HSkeleton = [(OIdent, [(OIdent, [OIdent])])] --type HSkeleton = [(OIdent, [(OIdent, [OIdent])])]
hSkeleton :: PGF -> (String,HSkeleton) hSkeleton :: PGF -> (String,HSkeleton)
hSkeleton gr = hSkeleton gr =
(showCId (absname gr), (abstractName gr,
let fs = let fs =
[(showCId c, [(showCId f, map showCId cs) | (f, (cs,_)) <- fs]) | [(c, [(f, cs) | (f, cs,_) <- fs]) |
fs@((_, (_,c)):_) <- fns] fs@((_, _,c):_) <- fns]
in fs ++ [(sc, []) | c <- cts, let sc = showCId c, sc `notElem` (["Int", "Float", "String"] ++ map fst fs)] in fs ++ [(c, []) | c <- cts, notElem c (["Int", "Float", "String"] ++ map fst fs)]
) )
where where
cts = Map.keys (cats (abstract gr)) cts = categories gr
fns = groupBy valtypg (sortBy valtyps (map jty (Map.assocs (funs (abstract gr))))) fns = groupBy valtypg (sortBy valtyps (mapMaybe jty (functions 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,(ty,_,_,_)) = (f,catSkeleton ty) jty f = case functionType gr f of
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 =

View File

@@ -1,105 +0,0 @@
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 ]

View File

@@ -1,156 +1,110 @@
module GF.Compile.PGFtoJSON (pgf2json) where module GF.Compile.PGFtoJSON (pgf2json) where
import PGF (showCId) import PGF2
import qualified PGF.Internal as M import PGF2.Internal
import PGF.Internal ( import Text.JSON
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 =
JSON.encode $ JSON.makeObj encode $ makeObj
[ ("abstract", json_abstract) [ ("abstract", abstract2json pgf)
, ("concretes", json_concretes) , ("concretes", makeObj $ map concrete2json
] (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)))
] ]
absdef2json :: (CId,(Type,Int,Maybe ([Equation],[[M.Instr]]),Double)) -> (String,JSValue) abstract2json :: PGF -> JSValue
absdef2json (f,(typ,_,_,_)) = (showCId f,sig) abstract2json pgf =
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
(args,cat) = M.catSkeleton typ Just (hypos,cat,_) = fmap unType (functionType pgf f)
sig = JSON.makeObj sig = makeObj
[ ("args", JSArray $ map (mkJSStr.showCId) args) [ ("args", showJSON $ map (\(_,_,ty) -> showType [] ty) hypos)
, ("cat", mkJSStr $ showCId cat) , ("cat", showJSON cat)
] ]
lit2json :: Literal -> JSValue lit2json :: Literal -> JSValue
lit2json (LStr s) = mkJSStr s lit2json (LStr s) = showJSON s
lit2json (LInt n) = mkJSInt n lit2json (LInt n) = showJSON n
lit2json (LFlt d) = JSRational True (toRational d) lit2json (LFlt d) = showJSON d
concrete2json :: (CId,Concr) -> (String,JSValue) concrete2json :: (ConcName,Concr) -> (String,JSValue)
concrete2json (c,cnc) = (showCId c,obj) concrete2json (c,cnc) = (c,obj)
where where
obj = JSON.makeObj obj = makeObj
[ ("flags", JSON.makeObj [ (showCId k, lit2json v) | (k,v) <- Map.toList (cflags cnc) ]) [ ("flags", makeObj [(k, lit2json v) | (k,v) <- concrFlags cnc])
, ("productions", JSON.makeObj [ (show cat, JSArray (map frule2json (Set.toList set))) | (cat,set) <- IntMap.toList (productions cnc)]) , ("productions", makeObj [(show fid, showJSON (map frule2json (concrProductions cnc fid))) | (_,start,end,_) <- concrCategories cnc, fid <- [start..end]])
, ("functions", JSArray (map ffun2json (Array.elems (cncfuns cnc)))) , ("functions", showJSON [ffun2json funid (concrFunction cnc funid) | funid <- [0..concrTotalFuns cnc-1]])
, ("sequences", JSArray (map seq2json (Array.elems (sequences cnc)))) , ("sequences", showJSON [seq2json seqid (concrSequence cnc seqid) | seqid <- [0..concrTotalSeqs cnc-1]])
, ("categories", JSON.makeObj $ map cats2json (Map.assocs (cnccats cnc))) , ("categories", makeObj $ map cat2json (concrCategories cnc))
, ("totalfids", mkJSInt (totalCats cnc)) , ("totalfids", showJSON (concrTotalCats cnc))
] ]
cats2json :: (CId, CncCat) -> (String,JSValue) cat2json :: (Cat,FId,FId,[String]) -> (String,JSValue)
cats2json (c,CncCat start end _) = (showCId c, ixs) cat2json (cat,start,end,_) = (cat, ixs)
where where
ixs = JSON.makeObj ixs = makeObj
[ ("start", mkJSInt start) [ ("start", showJSON start)
, ("end", mkJSInt end) , ("end", showJSON end)
] ]
frule2json :: Production -> JSValue frule2json :: Production -> JSValue
frule2json (PApply fid args) = frule2json (PApply fid args) =
JSON.makeObj makeObj
[ ("type", mkJSStr "Apply") [ ("type", showJSON "Apply")
, ("fid", mkJSInt fid) , ("fid", showJSON fid)
, ("args", JSArray (map farg2json args)) , ("args", showJSON (map farg2json args))
] ]
frule2json (PCoerce arg) = frule2json (PCoerce arg) =
JSON.makeObj makeObj
[ ("type", mkJSStr "Coerce") [ ("type", showJSON "Coerce")
, ("arg", mkJSInt arg) , ("arg", showJSON arg)
] ]
farg2json :: PArg -> JSValue farg2json :: PArg -> JSValue
farg2json (PArg hypos fid) = farg2json (PArg hypos fid) =
JSON.makeObj makeObj
[ ("type", mkJSStr "PArg") [ ("type", showJSON "PArg")
, ("hypos", JSArray $ map (mkJSInt . snd) hypos) , ("hypos", JSArray $ map (showJSON . snd) hypos)
, ("fid", mkJSInt fid) , ("fid", showJSON fid)
] ]
ffun2json :: CncFun -> JSValue ffun2json :: FunId -> (Fun,[SeqId]) -> JSValue
ffun2json (CncFun f lins) = ffun2json funid (fun,seqids) =
JSON.makeObj makeObj
[ ("name", mkJSStr $ showCId f) [ ("name", showJSON fun)
, ("lins", JSArray (map mkJSInt (Array.elems lins))) , ("lins", showJSON seqids)
] ]
seq2json :: Array.Array DotPos Symbol -> JSValue seq2json :: SeqId -> [Symbol] -> JSValue
seq2json seq = JSArray [sym2json s | s <- Array.elems seq] seq2json seqid seq = showJSON [sym2json sym | sym <- seq]
sym2json :: Symbol -> JSValue sym2json :: Symbol -> JSValue
sym2json (SymCat n l) = new "SymCat" [mkJSInt n, mkJSInt l] sym2json (SymCat n l) = new "SymCat" [showJSON n, showJSON l]
sym2json (SymLit n l) = new "SymLit" [mkJSInt n, mkJSInt l] sym2json (SymLit n l) = new "SymLit" [showJSON n, showJSON l]
sym2json (SymVar n l) = new "SymVar" [mkJSInt n, mkJSInt l] sym2json (SymVar n l) = new "SymVar" [showJSON n, showJSON l]
sym2json (SymKS t) = new "SymKS" [mkJSStr t] sym2json (SymKS t) = new "SymKS" [showJSON 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" [mkJSStr "&+"] sym2json SymBIND = new "SymKS" [showJSON "&+"]
sym2json SymSOFT_BIND = new "SymKS" [mkJSStr "&+"] sym2json SymSOFT_BIND = new "SymKS" [showJSON "&+"]
sym2json SymSOFT_SPACE = new "SymKS" [mkJSStr "&+"] sym2json SymSOFT_SPACE = new "SymKS" [showJSON "&+"]
sym2json SymCAPIT = new "SymKS" [mkJSStr "&|"] sym2json SymCAPIT = new "SymKS" [showJSON "&|"]
sym2json SymALL_CAPIT = new "SymKS" [mkJSStr "&|"] sym2json SymALL_CAPIT = new "SymKS" [showJSON "&|"]
sym2json SymNE = new "SymNE" [] sym2json SymNE = new "SymNE" []
alt2json :: ([Symbol],[String]) -> JSValue alt2json :: ([Symbol],[String]) -> JSValue
alt2json (ps,ts) = new "Alt" [JSArray (map sym2json ps), JSArray (map mkJSStr ts)] alt2json (ps,ts) = new "Alt" [showJSON (map sym2json ps), showJSON ts]
new :: String -> [JSValue] -> JSValue new :: String -> [JSValue] -> JSValue
new f xs = new f xs =
JSON.makeObj makeObj
[ ("type", mkJSStr f) [ ("type", showJSON f)
, ("args", JSArray xs) , ("args", showJSON 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

View File

@@ -1,6 +1,6 @@
module GF.Compile.PGFtoJava (grammar2java) where module GF.Compile.PGFtoJava (grammar2java) where
import PGF import PGF2
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,9 +24,8 @@ javaPreamble name =
] ]
javaMethod gr fun = javaMethod gr fun =
" public static Expr "++name++"("++arg_decls++") { return new Expr("++show name++args++"); }" " public static Expr "++fun++"("++arg_decls++") { return new Expr("++show fun++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]]

View File

@@ -1,262 +0,0 @@
----------------------------------------------------------------------
-- |
-- 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

View File

@@ -1,122 +0,0 @@
----------------------------------------------------------------------
-- |
-- 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 = ""

View File

@@ -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

View File

@@ -2,8 +2,7 @@ module GF.Compile.ToAPI
(stringToAPI,exprToAPI) (stringToAPI,exprToAPI)
where where
import PGF.Internal import PGF2
import PGF(showCId)
import Data.Maybe import Data.Maybe
--import System.IO --import System.IO
--import Control.Monad --import Control.Monad
@@ -47,12 +46,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 (showCId cid) syntaxFuncs of case Map.lookup cid syntaxFuncs of
Just sig -> mkAPI True (fst sig,expr) Just sig -> mkAPI True (fst sig,expr)
_ -> case l of _ -> case l of
[] -> BasicFunc (showCId cid) [] -> BasicFunc cid
_ -> let es = map exprToFunc l _ -> let es = map exprToFunc l
in AppFunc (showCId cid) es in AppFunc cid es
_ -> BasicFunc (showExpr [] expr) _ -> BasicFunc (showExpr [] expr)
@@ -69,8 +68,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" (showCId cid) then Just (cid,es) -> if isPrefixOf "Use" cid then
let newCat = drop 3 (showCId cid) let newCat = drop 3 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)
@@ -98,9 +97,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 (showCId cid) ty Just (cid,[]) -> getSimpCat cid ty
Just (cid,es) -> Just (cid,es) ->
let p = specFunction (showCId cid) es let p = specFunction 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
@@ -147,23 +146,23 @@ optimize expr = optimizeNP expr
optimizeNP expr = optimizeNP expr =
case unApp expr of case unApp expr of
Just (cid,es) -> Just (cid,es) ->
if showCId cid == "MassNP" then let afs = nounAsCN (head es) if cid == "MassNP" then let afs = nounAsCN (head es)
in AppFunc "mkNP" [afs] in AppFunc "mkNP" [afs]
else if showCId cid == "DetCN" then let quants = quantAsDet (head es) else if 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 showCId cid == "UseN" then (mkAPI False) ("N",head es) Just (cid,es) -> if 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 showCId cid == "DetQuant" then map (mkAPI False) [("Quant", head es),("Num",head $ tail es)] Just (cid,es) -> if 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)

View File

@@ -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

View File

@@ -69,7 +69,6 @@ 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

View File

@@ -396,7 +396,7 @@ tcRecTypeFields ge scope ((l,ty):rs) mb_ty = do
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
@@ -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")
Right ty2' -> do ms2 <- getMetaVars (geLoc ge) [(scope,ty2)] 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'))
@@ -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
@@ -724,8 +724,8 @@ getMetaVars loc sc_tys = do
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
@@ -742,9 +742,9 @@ getFreeVars loc sc_tys = do
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,9 +765,9 @@ zonkTerm (Meta i) = do
zonkTerm t = composOp zonkTerm t zonkTerm t = composOp zonkTerm t
tc_value2term loc xs v = tc_value2term loc xs v =
case value2term loc xs v of return $ value2term loc xs v
Left i -> tcError ("Variable #" <+> pp i <+> "has escaped") -- Old value2term error message:
Right t -> return t -- Left i -> tcError ("Variable #" <+> pp i <+> "has escaped")

View File

@@ -12,14 +12,15 @@
-- 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 (AExp(..), module GF.Compile.TypeCheck.TC (
Theory, AExp(..),
checkExp, Theory,
inferExp, checkExp,
checkBranch, inferExp,
eqVal, checkBranch,
whnf eqVal,
) where whnf
) where
import GF.Data.Operations import GF.Data.Operations
import GF.Grammar import GF.Grammar
@@ -127,10 +128,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
@@ -205,8 +206,8 @@ inferExp th tenv@(k,rho,gamma) e = case e of
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))
@@ -245,11 +246,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
@@ -307,8 +308,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))
@@ -321,4 +322,3 @@ 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)

View File

@@ -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) = do go map ((c,j):is) =
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
@@ -147,18 +147,18 @@ extendMod gr isCompl ((name,mi),cond) base new = foldM try new $ Map.toList (jme
| 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

View File

@@ -1,6 +1,6 @@
-- | Parallel grammar compilation -- | Parallel grammar compilation
module GF.CompileInParallel(parallelBatchCompile) where module GF.CompileInParallel(parallelBatchCompile) where
import Prelude hiding (catch,(<>)) -- GHC 8.4.1 clash with Text.PrettyPrint import Prelude hiding (catch,(<>))
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,11 +36,8 @@ 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_dirs1 <- getLibraryDirectory opts lib_dir <- canonical =<< getLibraryDirectory opts
lib_dirs2 <- mapM canonical lib_dirs1 filepaths <- mapM (getPathFromFile lib_dir opts) rootfiles
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"

View File

@@ -1,8 +1,7 @@
module GF.Compiler (mainGFC, linkGrammars, writePGF, writeOutputs) where module GF.Compiler (mainGFC, linkGrammars, writeGrammar, writeOutputs) where
import PGF import PGF2
import PGF.Internal(concretes,optimizePGF,unionPGF) import PGF2.Internal(unionPGF,writePGF,writeConcr)
import PGF.Internal(putSplitAbs,encodeFile,runPut)
import GF.Compile as S(batchCompile,link,srcAbsName) import GF.Compile as S(batchCompile,link,srcAbsName)
import GF.CompileInParallel as P(parallelBatchCompile) import GF.CompileInParallel as P(parallelBatchCompile)
import GF.Compile.Export import GF.Compile.Export
@@ -92,7 +91,7 @@ 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 'writePGF' and 'writeOutputs'. -- recreated. Calls 'writeGrammar' and 'writeOutputs'.
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")
@@ -102,10 +101,8 @@ 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 pgf0 = foldl1 unionPGF pgfs let pgf = foldl1 (\one two -> fromMaybe two (unionPGF one two)) pgfs
probs <- maybe (return . defaultProbabilities) readProbabilitiesFromFile (flag optProbsFile opts) pgf0 writeGrammar opts pgf
let pgf = setProbabilities probs pgf0
writePGF opts pgf
writeOutputs opts pgf writeOutputs opts pgf
compileCFFiles :: Options -> [FilePath] -> IOE () compileCFFiles :: Options -> [FilePath] -> IOE ()
@@ -115,12 +112,11 @@ 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"
let pgf = cf2pgf (last fs) (mkCFG startCat Set.empty rules) probs <- liftIO (maybe (return Map.empty) readProbabilitiesFromFile (flag optProbsFile opts))
let pgf = cf2pgf opts (last fs) (mkCFG startCat Set.empty rules) probs
unless (flag optStopAfterPhase opts == Compile) $ unless (flag optStopAfterPhase opts == Compile) $
do probs <- liftIO (maybe (return . defaultProbabilities) readProbabilitiesFromFile (flag optProbsFile opts) pgf) do writeGrammar opts pgf
let pgf' = setProbabilities probs $ if flag optOptimizePGF opts then optimizePGF pgf else pgf writeOutputs opts pgf
writePGF opts pgf'
writeOutputs opts pgf'
unionPGFFiles :: Options -> [FilePath] -> IOE () unionPGFFiles :: Options -> [FilePath] -> IOE ()
unionPGFFiles opts fs = unionPGFFiles opts fs =
@@ -138,14 +134,11 @@ unionPGFFiles opts fs =
doIt = doIt =
do pgfs <- mapM readPGFVerbose fs do pgfs <- mapM readPGFVerbose fs
let pgf0 = foldl1 unionPGF pgfs let pgf = foldl1 (\one two -> fromMaybe two (unionPGF one two)) pgfs
pgf1 = if flag optOptimizePGF opts then optimizePGF pgf0 else pgf0 let pgfFile = outputPath opts (grammarName opts pgf <.> "pgf")
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 writePGF opts pgf else writeGrammar opts pgf
writeOutputs opts pgf writeOutputs opts pgf
readPGFVerbose f = readPGFVerbose f =
@@ -162,21 +155,20 @@ writeOutputs opts pgf = do
-- | 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.
writePGF :: Options -> PGF -> IOE () writeGrammar :: Options -> PGF -> IOE ()
writePGF opts pgf = writeGrammar 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 $ encodeFile outfile pgf writing opts outfile (writePGF outfile pgf)
writeSplitPGF = writeSplitPGF =
do let outfile = outputPath opts (grammarName opts pgf <.> "pgf") do let outfile = outputPath opts (grammarName opts pgf <.> "pgf")
writing opts outfile $ BSL.writeFile outfile (runPut (putSplitAbs pgf)) writing opts outfile $ writePGF outfile pgf
--encodeFile_ outfile (putSplitAbs pgf) forM_ (Map.toList (languages pgf)) $ \(concrname,concr) -> do
forM_ (Map.toList (concretes pgf)) $ \cnc -> do let outfile = outputPath opts (concrname <.> "pgf_c")
let outfile = outputPath opts (showCId (fst cnc) <.> "pgf_c") writing opts outfile (writeConcr outfile concr)
writing opts outfile $ encodeFile outfile cnc
writeOutput :: Options -> FilePath-> String -> IOE () writeOutput :: Options -> FilePath-> String -> IOE ()
@@ -186,7 +178,7 @@ writeOutput opts file str = writing opts path $ writeUTF8File path str
-- * Useful helper functions -- * Useful helper functions
grammarName :: Options -> PGF -> String grammarName :: Options -> PGF -> String
grammarName opts pgf = grammarName' opts (showCId (abstractName pgf)) grammarName opts pgf = grammarName' opts (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)

View File

@@ -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

View File

@@ -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)
@@ -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]

View File

@@ -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
@@ -76,8 +76,8 @@ prSubGraph g@(Graph _ i _ _ _ _) =
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

View File

@@ -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 -- ** Checking
checkUnique, unifyMaybeBy, unifyMaybe, checkUnique, unifyMaybeBy, unifyMaybe,
-- ** Monadic operations on lists and pairs -- ** Monadic operations on lists and pairs
mapPairsM, pairM, mapPairsM, pairM,
-- ** Printing -- ** Printing
indent, (+++), (++-), (++++), (+++-), (+++++), indent, (+++), (++-), (++++), (+++-), (+++++),
prUpper, prReplicate, prTList, prQuotedString, prParenth, prCurly, prUpper, prReplicate, prTList, prQuotedString, prParenth, prCurly,
prBracket, prArgList, prSemicList, prCurlyList, restoreEscapes, prBracket, prArgList, prSemicList, prCurlyList, restoreEscapes,
numberedParagraphs, prConjList, prIfEmpty, wrapLines, numberedParagraphs, prConjList, prIfEmpty, wrapLines,
-- ** Topological sorting -- ** Topological sorting
topoTest, topoTest2, topoTest, topoTest2,
-- ** Misc -- ** Misc
readIntArg, readIntArg,
iterFix, chunks, iterFix, chunks,
) where ) 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, (\\))
@@ -204,7 +204,7 @@ 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)

View File

@@ -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'
@@ -117,8 +117,8 @@ 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,

View File

@@ -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 [] = []

View File

@@ -15,7 +15,6 @@
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
@@ -64,12 +63,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 (mkCId $ "coercion_" ++ c) [] rn = CFObj ("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 (mkCId $ "coercion_" ++ c') [] rn = CFObj ("coercion_" ++ c') []
transformSymb :: SepMap -> BNFCSymbol -> (String, ParamCFSymbol) transformSymb :: SepMap -> BNFCSymbol -> (String, ParamCFSymbol)
transformSymb sepMap s = case s of transformSymb sepMap s = case s of
@@ -94,7 +93,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 (mkCId $ "Base" ++ c) [] rn = CFObj ("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]
@@ -107,4 +106,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 (mkCId $ "Cons" ++ c) [] rn = CFObj ("Cons" ++ c) []

View File

@@ -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,8 +22,7 @@ import GF.Infra.Option
import GF.Infra.UseIO(MonadIO(..)) import GF.Infra.UseIO(MonadIO(..))
import GF.Grammar.Grammar import GF.Grammar.Grammar
import PGF() -- Binary instances import PGF2.Internal(Literal(..),Symbol(..))
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"
@@ -298,6 +297,53 @@ 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

View File

@@ -4,10 +4,11 @@
-- --
-- Context-free grammar representation and manipulation. -- Context-free grammar representation and manipulation.
---------------------------------------------------------------------- ----------------------------------------------------------------------
module GF.Grammar.CFG where module GF.Grammar.CFG(Cat,Token, module GF.Grammar.CFG) where
import GF.Data.Utilities import GF.Data.Utilities
import PGF import PGF2(Fun,Cat)
import PGF2.Internal(Token)
import GF.Data.Relation import GF.Data.Relation
import Data.Map (Map) import Data.Map (Map)
@@ -20,8 +21,6 @@ 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)
@@ -39,12 +38,12 @@ data Grammar c t = Grammar {
deriving (Eq, Ord, Show) deriving (Eq, Ord, Show)
data CFTerm data CFTerm
= CFObj CId [CFTerm] -- ^ an abstract syntax function with arguments = CFObj Fun [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 CId -- ^ A metavariable | CFMeta Fun -- ^ A metavariable
deriving (Eq, Ord, Show) deriving (Eq, Ord, Show)
type CFSymbol = Symbol Cat Token type CFSymbol = Symbol Cat Token
@@ -232,7 +231,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'=mkCId (showCId fun++suffix), let fun'=fun++suffix,
not (fun' `Set.member` funs)] not (fun' `Set.member` funs)]
-- | Gets all rules in a CFG. -- | Gets all rules in a CFG.
@@ -310,12 +309,12 @@ prProductions prods =
prCFTerm :: CFTerm -> String prCFTerm :: CFTerm -> String
prCFTerm = pr 0 prCFTerm = pr 0
where where
pr p (CFObj f args) = paren p (showCId f ++ " (" ++ concat (intersperse "," (map (pr 0) args)) ++ ")") pr p (CFObj f args) = paren p (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) = "?" ++ showCId c pr _ (CFMeta c) = "?" ++ c
paren 0 x = x paren 0 x = x
paren 1 x = "(" ++ x ++ ")" paren 1 x = "(" ++ x ++ ")"
@@ -323,12 +322,12 @@ prCFTerm = pr 0
-- * CFRule Utilities -- * CFRule Utilities
-- --
ruleFun :: Rule c t -> CId ruleFun :: Rule c t -> Fun
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 _ = mkCId "" f _ = ""
-- | 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.
@@ -336,7 +335,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 (mkCId n) [] mkCFTerm n = CFObj 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

View File

@@ -16,7 +16,6 @@ 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)
@@ -40,7 +39,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 (mkCId ("Mk" ++ c ++ "_" ++ show i)) [] mkCFF i (c,_) = CFObj ("Mk" ++ c ++ "_" ++ show i) []
normEBNF :: EBNF -> [CFJustRule] normEBNF :: EBNF -> [CFJustRule]
normEBNF erules = let normEBNF erules = let

View File

@@ -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, Sequence PMCFG(..), Production(..), FId, FunId, SeqId, LIndex
) where ) where
import GF.Infra.Ident import GF.Infra.Ident
@@ -73,7 +73,8 @@ import GF.Infra.Location
import GF.Data.Operations import GF.Data.Operations
import PGF.Internal (FId, FunId, SeqId, LIndex, Sequence, BindType(..)) import PGF2(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)
@@ -99,7 +100,7 @@ data ModuleInfo = ModInfo {
mopens :: [OpenSpec], mopens :: [OpenSpec],
mexdeps :: [ModuleName], mexdeps :: [ModuleName],
msrc :: FilePath, msrc :: FilePath,
mseqs :: Maybe (Array SeqId Sequence), mseqs :: Maybe (Array SeqId [Symbol]),
jments :: Map.Map Ident Info jments :: Map.Map Ident Info
} }

View File

@@ -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 }

View File

@@ -30,7 +30,7 @@ module GF.Grammar.Lookup (
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

View File

@@ -25,7 +25,6 @@ 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)
} }
@@ -625,7 +624,7 @@ ListCFRule
CFRule :: { [BNFCRule] } CFRule :: { [BNFCRule] }
CFRule CFRule
: Ident '.' Ident '::=' ListCFSymbol ';' { [BNFCRule (showIdent $3) $5 (CFObj (mkCId (showIdent $1)) [])] : Ident '.' Ident '::=' ListCFSymbol ';' { [BNFCRule (showIdent $3) $5 (CFObj (showIdent $1) [])]
} }
| Ident '::=' ListCFRHS ';' { let { cat = showIdent $1; | Ident '::=' ListCFRHS ';' { let { cat = showIdent $1;
mkFun cat its = mkFun cat its =
@@ -638,7 +637,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 (mkCId (mkFun cat rhs)) [])) $3 } in map (\rhs -> BNFCRule cat rhs (CFObj (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] }

View File

@@ -12,11 +12,12 @@
-- 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 (matchPattern, module GF.Grammar.PatternMatch (
testOvershadow, matchPattern,
findMatch, testOvershadow,
measurePatt findMatch,
) where measurePatt
) where
import GF.Data.Operations import GF.Data.Operations
import GF.Grammar.Grammar import GF.Grammar.Grammar

View File

@@ -24,13 +24,13 @@ module GF.Grammar.Printer
) 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 PGF2.Internal as PGF2
import GF.Infra.Ident import GF.Infra.Ident
import GF.Infra.Option import GF.Infra.Option
import GF.Grammar.Values import GF.Grammar.Values
import GF.Grammar.Grammar 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)
@@ -175,18 +175,18 @@ 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)
@@ -198,14 +198,14 @@ ppTerm q d (C e1 e2) =prec d 1 (hang (ppTerm q 2 e1) 2 ("++" <+> ppTerm q 1 e
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)))])
@@ -363,3 +363,39 @@ 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)

View File

@@ -12,15 +12,16 @@
-- (Description of the module) -- (Description of the module)
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
module GF.Grammar.Values (-- ** Values used in TC type checking module GF.Grammar.Values (
Val(..), Env, -- ** Values used in TC type checking
-- ** Annotated tree used in editing Val(..), Env,
-- ** 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

View File

@@ -14,9 +14,3 @@ buildInfo =
#ifdef SERVER_MODE #ifdef SERVER_MODE
++" server" ++" server"
#endif #endif
#ifdef NEW_COMP
++" new-comp"
#endif
#ifdef C_RUNTIME
++" c-runtime"
#endif

View File

@@ -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

View File

@@ -31,7 +31,7 @@ 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 PGF.Internal(Binary(..)) import Data.Binary(Binary(..))
import GF.Text.Pretty import GF.Text.Pretty

View File

@@ -1,6 +1,6 @@
-- | Source locations -- | Source locations
module GF.Infra.Location where module GF.Infra.Location where
import Prelude hiding ((<>)) -- GHC 8.4.1 clash with Text.PrettyPrint import Prelude hiding ((<>))
import GF.Text.Pretty import GF.Text.Pretty
-- ** Source locations -- ** Source locations

View File

@@ -34,16 +34,14 @@ 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 System.IO import PGF2.Internal(Literal(..))
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
@@ -76,7 +74,6 @@ 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)
@@ -95,7 +92,6 @@ data OutputFormat = FmtPGFPretty
| FmtPython | FmtPython
| FmtHaskell | FmtHaskell
| FmtJava | FmtJava
| FmtProlog
| FmtBNF | FmtBNF
| FmtEBNF | FmtEBNF
| FmtRegular | FmtRegular
@@ -162,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,
@@ -217,10 +213,9 @@ 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_dirs (Options o) = Options (fixPathFlags . o) fixRelativeLibPaths curr_dir lib_dir (Options o) = Options (fixPathFlags . o)
where where
fixPathFlags f@(Flags{optLibraryPath=path}) = f{optLibraryPath=concatMap (\dir -> [parent </> dir fixPathFlags f@(Flags{optLibraryPath=path}) = f{optLibraryPath=concatMap (\dir -> [curr_dir </> dir, lib_dir </> dir]) path}
| parent <- curr_dir : lib_dirs]) path}
-- Showing options -- Showing options
@@ -316,8 +311,6 @@ 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")
@@ -432,7 +425,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 $ splitInModuleSearchPath x } gfLibPath x = set $ \o -> o { optGFLibPath = Just 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 }
@@ -480,12 +473,9 @@ outputFormatsExpl =
[(("pgf_pretty", FmtPGFPretty),"human-readable 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"),

View File

@@ -12,9 +12,6 @@ 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
@@ -39,9 +36,6 @@ 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
@@ -127,7 +121,3 @@ 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

View File

@@ -38,7 +38,6 @@ 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
@@ -52,32 +51,28 @@ 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 -> liftM splitSearchPath $ liftIO (catch (getEnv gfLibraryPath) Nothing -> 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_dirs = liftIO $ do getGrammarPath lib_dir = liftIO $ do
catch (fmap splitSearchPath $ getEnv gfGrammarPathVar) catch (fmap splitSearchPath $ getEnv gfGrammarPathVar)
(\_ -> return $ concat [[lib_dir </> "alltenses", lib_dir </> "prelude"] (\_ -> return [lib_dir </> "alltenses",lib_dir </> "prelude"]) -- e.g. GF_GRAMMAR_PATH
| 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 = nub $ flag optLibraryPath opts -- e.g. paths given as options let opt_path = flag optLibraryPath opts -- e.g. paths given as options
lib_dirs <- getLibraryDirectory opts -- e.g. GF_LIB_PATH lib_dir <- getLibraryDirectory opts -- e.g. GF_LIB_PATH
grm_path <- getGrammarPath lib_dirs -- e.g. GF_GRAMMAR_PATH grm_path <- getGrammarPath lib_dir -- e.g. GF_GRAMMAR_PATH
let paths = opt_path ++ lib_dirs ++ grm_path let paths = opt_path ++ [lib_dir] ++ grm_path
when (verbAtLeast opts Verbose) $ putStrLn ("extendPathEnv: opt_path is "++ show opt_path) ps <- liftM concat $ mapM allSubdirs paths
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]
@@ -85,15 +80,11 @@ 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
let starpaths = [path </> f | f <- fs] return [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 do then return [p]
when (verbAtLeast opts Verbose) $ putStrLn ("extendPathEnv: allSubdirs: found path "++show p) else do when (verbAtLeast opts Verbose) $ putStrLn ("ignore path "++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]

View File

@@ -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(PGFEnv,HasPGFEnv(..),pgf,pgfEnv,pgfCommands) import GF.Command.Commands(HasPGF(..),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,15 +20,12 @@ 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 PGF import PGF2
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)
@@ -38,9 +35,6 @@ 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 ()
@@ -56,6 +50,7 @@ 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
@@ -280,17 +275,18 @@ 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,pgfEnv pgf)} modify $ \ gfenv -> gfenv {retain=True, pgfenv = (src,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,pgfEnv pgf1) } pgfenv = (emptyGrammar,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 putStrLnFlush $ then case pgf1 of
unwords $ "\nLanguages:" : map showCId (languages pgf1) Just pgf -> putStrLnFlush $ unwords $ "\nLanguages:" : Map.keys (languages pgf)
Nothing -> return ()
else return () else return ()
return pgf1 return pgf1
@@ -301,12 +297,12 @@ tryGetLine = do
Right l -> return l Right l -> return l
prompt env prompt env
| retain env || abs == wildCId = "> " | retain env = "> "
| otherwise = showCId abs ++ "> " | otherwise = case multigrammar env of
where Just pgf -> abstractName pgf ++ "> "
abs = abstractName (multigrammar env) Nothing -> "> "
type CmdEnv = (Grammar,PGFEnv) type CmdEnv = (Grammar,Maybe PGF)
data GFEnv = GFEnv { data GFEnv = GFEnv {
startOpts :: Options, startOpts :: Options,
@@ -318,10 +314,10 @@ data GFEnv = GFEnv {
emptyGFEnv opts = GFEnv opts False emptyCmdEnv emptyCommandEnv [] emptyGFEnv opts = GFEnv opts False emptyCmdEnv emptyCommandEnv []
emptyCmdEnv = (emptyGrammar,pgfEnv emptyPGF) emptyCmdEnv = (emptyGrammar,Nothing)
emptyCommandEnv = mkCommandEnv allCommands emptyCommandEnv = mkCommandEnv allCommands
multigrammar = pgf . snd . pgfenv multigrammar = snd . pgfenv
allCommands = allCommands =
extend pgfCommands (helpCommand allCommands:moreCommands) extend pgfCommands (helpCommand allCommands:moreCommands)
@@ -329,24 +325,35 @@ allCommands =
`Map.union` commonCommands `Map.union` commonCommands
instance HasGrammar ShellM where getGrammar = gets (fst . pgfenv) instance HasGrammar ShellM where getGrammar = gets (fst . pgfenv)
instance HasPGFEnv ShellM where getPGFEnv = gets (snd . pgfenv) instance HasPGF ShellM where getPGF = 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
-> do mb_state0 <- try (evaluate (initState pgf (optLang opts) (optType opts))) -> case multigrammar gfenv of
case mb_state0 of Just pgf -> let langs = languages pgf
Right state0 -> let (rprefix,rs) = break isSpace (reverse s0) optLang opts = case valStrOpts "lang" "" opts of
s = reverse rs "" -> case Map.minView langs of
prefix = reverse rprefix Nothing -> Nothing
ws = words s Just (concr,_) -> Just concr
in case loop state0 ws of lang -> mplus (Map.lookup lang langs)
Nothing -> ret 0 [] (Map.lookup (abstractName pgf ++ lang) langs)
Just state -> let compls = getCompletions state prefix optType opts = let readOpt str = case readType str of
in ret (length prefix) (map (\x -> Haskeline.simpleCompletion x) (Map.keys compls)) Just ty -> case checkType pgf ty of
Left (_ :: SomeException) -> ret 0 [] Left _ -> Nothing
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]
@@ -357,23 +364,15 @@ 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
-> do mb_abs <- try (evaluate (abstract pgf)) -> case multigrammar gfenv of
case mb_abs of Just pgf -> ret (length pref) [Haskeline.simpleCompletion name | name <- functions pgf, isPrefixOf pref name]
Right abs -> ret (length pref) [Haskeline.simpleCompletion name | cid <- Map.keys (funs abs), let name = showCId cid, isPrefixOf pref name] Nothing -> ret (length pref) []
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 nextState ps (simpleParseInput t) of loop ps (t:ts) = case error "nextState ps (simpleParseInput t)" of
Left es -> Nothing Left es -> Nothing
Right ps -> loop ps ts Right ps -> loop ps ts
@@ -433,7 +432,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

View File

@@ -1,442 +0,0 @@
{-# 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

View File

@@ -2,10 +2,7 @@
{-# LANGUAGE CPP #-} {-# LANGUAGE CPP #-}
module GF.Main where module GF.Main where
import GF.Compiler import GF.Compiler
import qualified GF.Interactive as GFI1 import GF.Interactive
#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
@@ -16,18 +13,19 @@ 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
@@ -47,17 +45,7 @@ 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 -> GFI1.mainServerGFI opts port files ModeServer port -> mainServerGFI opts port files
ModeCompiler -> mainGFC opts files ModeCompiler -> mainGFC opts files
ModeInteractive -> GFI1.mainGFI opts files ModeInteractive -> mainGFI opts files
ModeRun -> GFI1.mainRunGFI opts files ModeRun -> 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

View File

@@ -18,13 +18,8 @@ module GF.Quiz (
morphologyList morphologyList
) where ) where
import PGF import PGF2
--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)
@@ -38,7 +33,7 @@ mkQuiz msg tts = do
teachDialogue qas msg teachDialogue qas msg
translationList :: translationList ::
Maybe Expr -> PGF -> Language -> Language -> Type -> Int -> IO [(String,[String])] Maybe Expr -> PGF -> Concr -> Concr -> 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
@@ -46,19 +41,22 @@ 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 pgf ig t), mkOne t = (norml (linearize ig t),
map norml (concatMap lins (homonyms t))) map norml (concatMap lins (homonyms t)))
homonyms = parse pgf ig typ . linearize pgf ig homonyms t =
lins = nub . concatMap (map snd) . tabularLinearizes pgf og case (parse ig typ . linearize ig) t of
ParseOk res -> map fst res
_ -> []
lins = nub . concatMap (map snd) . tabularLinearizeAll og
morphologyList :: morphologyList ::
Maybe Expr -> PGF -> Language -> Type -> Int -> IO [(String,[String])] Maybe Expr -> PGF -> Concr -> 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 (tabularLinearizes pgf ig) ts let ss = map (tabularLinearizeAll 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) |

View File

@@ -3,7 +3,6 @@
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.Except(ExceptT(..),runExceptT)
@@ -34,7 +33,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(JSValue(..),Result(..),valFromObj,encode,decode,showJSON,makeObj) import Text.JSON(encode,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(..))
@@ -43,7 +42,6 @@ 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)
@@ -171,7 +169,6 @@ 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
@@ -180,7 +177,7 @@ handle logLn documentroot state0 cache execute1 stateVar
translatePath rpath = root</>rpath -- hmm, check for ".." translatePath rpath = root</>rpath -- hmm, check for ".."
versionInfo (c1,c2) = versionInfo c =
html200 . unlines $ html200 . unlines $
"<!DOCTYPE html>": "<!DOCTYPE html>":
"<meta name = \"viewport\" content = \"width = device-width\">": "<meta name = \"viewport\" content = \"width = device-width\">":
@@ -188,8 +185,7 @@ handle logLn documentroot state0 cache execute1 stateVar
"": "":
("<h2>"++hdr++"</h2>"): ("<h2>"++hdr++"</h2>"):
(zipWith (++) ("<p>":repeat "<br>") buildinfo)++ (zipWith (++) ("<p>":repeat "<br>") buildinfo)++
sh "Haskell run-time system" c1++ sh "Run-time system" c
sh "C run-time system" c2
where where
hdr:buildinfo = lines gf_version hdr:buildinfo = lines gf_version
rel = makeRelative documentroot rel = makeRelative documentroot
@@ -284,17 +280,13 @@ 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 ext = jsonList' (mapM (addTime ext)) ext jsonListLong = jsonList' (mapM addTime)
jsonList' details ext = fmap (json200) (details =<< ls_ext "." ext) jsonList' details ext = fmap (json200) (details =<< ls_ext "." ext)
addTime ext path = addTime path =
do t <- getModificationTime path do t <- getModificationTime path
if ext==".json" return $ makeObj ["path".=path,"time".=format t]
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 =
@@ -336,11 +328,6 @@ 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 =

View File

@@ -14,7 +14,6 @@ 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

View File

@@ -12,15 +12,15 @@
-- 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,
@@ -28,11 +28,11 @@ module GF.Speech.FiniteState (FA(..), State, NFA, DFA,
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
@@ -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
@@ -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
@@ -234,17 +234,17 @@ fixIncoming :: (Ord n, Eq a) => [n]
-- 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,18 +254,18 @@ 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)
@@ -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
@@ -316,10 +316,10 @@ 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

View File

@@ -7,15 +7,13 @@
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
module GF.Speech.GSL (gslPrinter) where module GF.Speech.GSL (gslPrinter) where
import Prelude hiding ((<>)) -- GHC 8.4.1 clash with Text.PrettyPrint
--import GF.Data.Utilities import Prelude hiding ((<>))
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 GF.Infra.Ident import PGF2
import PGF
import Data.Char (toUpper,toLower) import Data.Char (toUpper,toLower)
import Data.List (partition) import Data.List (partition)
@@ -24,7 +22,7 @@ import GF.Text.Pretty
width :: Int width :: Int
width = 75 width = 75
gslPrinter :: Options -> PGF -> CId -> String gslPrinter :: Options -> PGF -> Concr -> 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 }
@@ -32,7 +30,7 @@ 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)

View File

@@ -11,15 +11,14 @@
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
module GF.Speech.JSGF (jsgfPrinter) where module GF.Speech.JSGF (jsgfPrinter) where
import Prelude hiding ((<>)) -- GHC 8.4.1 clash with Text.PrettyPrint
--import GF.Data.Utilities import Prelude hiding ((<>))
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 PGF import PGF2
import Data.Char import Data.Char
import Data.List import Data.List
@@ -31,8 +30,8 @@ width :: Int
width = 75 width = 75
jsgfPrinter :: Options jsgfPrinter :: Options
-> PGF -> PGF
-> CId -> String -> Concr -> 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
@@ -44,7 +43,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)
@@ -110,4 +109,3 @@ prepunctuate p (x:xs) = x : map (p <>) xs
($++$) :: Doc -> Doc -> Doc ($++$) :: Doc -> Doc -> Doc
x $++$ y = x $$ emptyLine $$ y x $++$ y = x $$ emptyLine $$ y

View File

@@ -6,60 +6,54 @@
---------------------------------------------------------------------- ----------------------------------------------------------------------
module GF.Speech.PGFToCFG (bnfPrinter, pgfToCFG) where module GF.Speech.PGFToCFG (bnfPrinter, pgfToCFG) where
import PGF(showCId) import PGF2
import PGF.Internal as PGF import PGF2.Internal
--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 -> CId -> String bnfPrinter :: PGF -> Concr -> String
bnfPrinter = toBNF id bnfPrinter = toBNF id
toBNF :: (CFG -> CFG) -> PGF -> CId -> String toBNF :: (CFG -> CFG) -> PGF -> Concr -> 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 pgfToCFG :: PGF -> Concr -> CFG
-> CId -- ^ Concrete syntax name pgfToCFG pgf cnc = mkCFG start_cat extCats (startRules ++ concatMap ruleToCFRule rules)
-> CFG
pgfToCFG pgf lang = mkCFG (showCId (lookStartCat pgf)) extCats (startRules ++ concatMap ruleToCFRule rules)
where where
cnc = lookConcr pgf lang (_,start_cat,_) = unType (startCat pgf)
rules :: [(FId,Production)] rules :: [(FId,Production)]
rules = [(fcat,prod) | (fcat,set) <- IntMap.toList (PGF.productions cnc) rules = [(fcat,prod) | fcat <- [0..concrTotalCats cnc],
, prod <- Set.toList set] prod <- concrProductions cnc fcat]
fcatCats :: Map FId Cat fcatCats :: Map FId Cat
fcatCats = Map.fromList [(fc, showCId c ++ "_" ++ show i) fcatCats = Map.fromList [(fc, c ++ "_" ++ show i)
| (c,CncCat s e lbls) <- Map.toList (cnccats cnc), | (c,s,e,lbls) <- concrCategories cnc,
(fc,i) <- zip (range (s,e)) [1..]] (fc,i) <- zip [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 -> LIndex -> Cat fcatToCat :: FId -> Int -> 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:[rangeSize (bounds rhs) | (CncFun _ rhs, _) <- topdownRules c]) catLinArity c = maximum (1:[length rhs | ((_,rhs), _) <- topdownRules c])
topdownRules cat = f cat [] topdownRules cat = f cat []
where where
f cat rules = maybe rules (Set.foldr g rules) (IntMap.lookup cat (productions cnc)) f cat rules = foldr g rules (concrProductions cnc cat)
g (PApply funid args) rules = (cncfuns cnc ! funid,args) : rules g (PApply funid args) rules = (concrFunction cnc funid,args) : rules
g (PCoerce cat) rules = f cat rules g (PCoerce cat) rules = f cat rules
@@ -67,26 +61,26 @@ pgfToCFG pgf lang = mkCFG (showCId (lookStartCat pgf)) extCats (startRules ++ co
extCats = Set.fromList $ map ruleLhs startRules extCats = Set.fromList $ map ruleLhs startRules
startRules :: [CFRule] startRules :: [CFRule]
startRules = [Rule (showCId c) [NonTerminal (fcatToCat fc r)] (CFRes 0) startRules = [Rule c [NonTerminal (fcatToCat fc r)] (CFRes 0)
| (c,CncCat s e lbls) <- Map.toList (cnccats cnc), | (c,s,e,lbls) <- concrCategories cnc,
fc <- range (s,e), not (isPredefFId fc), fc <- [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) <- Array.assocs rhs | (l,seqid) <- zip [0..] rhs
, let row = sequences cnc ! seqid , let row = concrSequence cnc seqid
, not (containsLiterals row)] , not (containsLiterals row)]
where where
CncFun f rhs = cncfuns cnc ! funid (f, rhs) = concrFunction cnc funid
mkRhs :: Array DotPos Symbol -> [CFSymbol] mkRhs :: [Symbol] -> [CFSymbol]
mkRhs = concatMap symbolToCFSymbol . Array.elems mkRhs = concatMap symbolToCFSymbol
containsLiterals :: Array DotPos Symbol -> Bool containsLiterals :: [Symbol] -> Bool
containsLiterals row = not (null ([n | SymLit n _ <- Array.elems row] ++ containsLiterals row = not (null ([n | SymLit n _ <- row] ++
[n | SymVar n _ <- Array.elems row])) [n | SymVar n _ <- 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)]
@@ -102,10 +96,10 @@ pgfToCFG pgf lang = mkCFG (showCId (lookStartCat pgf)) extCats (startRules ++ co
symbolToCFSymbol SymALL_CAPIT = [Terminal "&|"] symbolToCFSymbol SymALL_CAPIT = [Terminal "&|"]
symbolToCFSymbol SymNE = [] symbolToCFSymbol SymNE = []
fixProfile :: Array DotPos Symbol -> Int -> Profile fixProfile :: [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 <- Array.elems row, j <- getPos nt] nts = zip [0..] [j | nt <- row, j <- getPos nt]
getPos (SymCat j _) = [j] getPos (SymCat j _) = [j]
getPos (SymLit j _) = [j] getPos (SymLit j _) = [j]
@@ -113,9 +107,10 @@ pgfToCFG pgf lang = mkCFG (showCId (lookStartCat pgf)) extCats (startRules ++ co
profilesToTerm :: [Profile] -> CFTerm profilesToTerm :: [Profile] -> CFTerm
profilesToTerm ps = CFObj f (zipWith profileToTerm argTypes ps) profilesToTerm ps = CFObj f (zipWith profileToTerm argTypes ps)
where (argTypes,_) = catSkeleton $ lookType (abstract pgf) f where Just (hypos,_,_) = fmap unType (functionType pgf f)
argTypes = [cat | (_,_,ty) <- hypos, let (_,cat,_) = unType ty]
profileToTerm :: CId -> Profile -> CFTerm profileToTerm :: Fun -> 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') =

View File

@@ -11,12 +11,12 @@ import GF.Grammar.CFG
import GF.Speech.CFGToFA import GF.Speech.CFGToFA
import GF.Speech.PGFToCFG import GF.Speech.PGFToCFG
import GF.Speech.RegExp import GF.Speech.RegExp
import PGF import PGF2
regexpPrinter :: PGF -> CId -> String regexpPrinter :: PGF -> Concr -> String
regexpPrinter pgf cnc = (++"\n") $ prRE id $ dfa2re $ cfgToFA $ pgfToCFG pgf cnc regexpPrinter pgf cnc = (++"\n") $ prRE id $ dfa2re $ cfgToFA $ pgfToCFG pgf cnc
multiRegexpPrinter :: PGF -> CId -> String multiRegexpPrinter :: PGF -> Concr -> String
multiRegexpPrinter pgf cnc = prREs $ mfa2res $ cfgToMFA $ pgfToCFG pgf cnc multiRegexpPrinter pgf cnc = prREs $ mfa2res $ cfgToMFA $ pgfToCFG pgf cnc
prREs :: [(String,RE CFSymbol)] -> String prREs :: [(String,RE CFSymbol)] -> String

View File

@@ -10,13 +10,9 @@ module GF.Speech.SISR (SISRFormat(..), SISRTag, prSISR,
import Data.List import Data.List
--import GF.Data.Utilities
--import GF.Infra.Ident
import GF.Infra.Option (SISRFormat(..)) import GF.Infra.Option (SISRFormat(..))
import GF.Grammar.CFG import GF.Grammar.CFG
import GF.Speech.SRG (SRGNT) import GF.Speech.SRG (SRGNT)
import PGF(showCId)
import qualified GF.JavaScript.AbsJS as JS import qualified GF.JavaScript.AbsJS as JS
import qualified GF.JavaScript.PrintJS as JS import qualified GF.JavaScript.PrintJS as JS
@@ -50,12 +46,12 @@ catSISR t (c,i) fmt
profileFinalSISR :: CFTerm -> SISRFormat -> SISRTag profileFinalSISR :: CFTerm -> SISRFormat -> SISRTag
profileFinalSISR term fmt = [JS.DExpr $ fmtOut fmt `ass` f term] profileFinalSISR term fmt = [JS.DExpr $ fmtOut fmt `ass` f term]
where where
f (CFObj n ts) = tree (showCId n) (map f ts) f (CFObj n ts) = tree n (map f ts)
f (CFAbs v x) = JS.EFun [var v] [JS.SReturn (f x)] f (CFAbs v x) = JS.EFun [var v] [JS.SReturn (f x)]
f (CFApp x y) = JS.ECall (f x) [f y] f (CFApp x y) = JS.ECall (f x) [f y]
f (CFRes i) = JS.EIndex (JS.EVar args) (JS.EInt (fromIntegral i)) f (CFRes i) = JS.EIndex (JS.EVar args) (JS.EInt (fromIntegral i))
f (CFVar v) = JS.EVar (var v) f (CFVar v) = JS.EVar (var v)
f (CFMeta typ) = obj [("name",JS.EStr "?"), ("type",JS.EStr (showCId typ))] f (CFMeta typ) = obj [("name",JS.EStr "?"), ("type",JS.EStr typ)]
fmtOut SISR_WD20030401 = JS.EVar (JS.Ident "$") fmtOut SISR_WD20030401 = JS.EVar (JS.Ident "$")
fmtOut SISR_1_0 = JS.EVar (JS.Ident "out") fmtOut SISR_1_0 = JS.EVar (JS.Ident "out")

View File

@@ -16,17 +16,14 @@ module GF.Speech.SLF (slfPrinter,slfGraphvizPrinter,
import GF.Data.Utilities import GF.Data.Utilities
import GF.Grammar.CFG import GF.Grammar.CFG
import GF.Speech.FiniteState import GF.Speech.FiniteState
--import GF.Speech.CFG
import GF.Speech.CFGToFA import GF.Speech.CFGToFA
import GF.Speech.PGFToCFG import GF.Speech.PGFToCFG
import qualified GF.Data.Graphviz as Dot import qualified GF.Data.Graphviz as Dot
import PGF import PGF2
--import PGF.CId
import Control.Monad import Control.Monad
import qualified Control.Monad.State as STM import qualified Control.Monad.State as STM
import Data.Char (toUpper) import Data.Char (toUpper)
--import Data.List
import Data.Maybe import Data.Maybe
data SLFs = SLFs [(String,SLF)] SLF data SLFs = SLFs [(String,SLF)] SLF
@@ -43,7 +40,7 @@ data SLFEdge = SLFEdge { eId :: Int, eStart :: Int, eEnd :: Int }
type SLF_FA = FA State (Maybe CFSymbol) () type SLF_FA = FA State (Maybe CFSymbol) ()
mkFAs :: PGF -> CId -> (SLF_FA, [(String,SLF_FA)]) mkFAs :: PGF -> Concr -> (SLF_FA, [(String,SLF_FA)])
mkFAs pgf cnc = (slfStyleFA main, [(c,slfStyleFA n) | (c,n) <- subs]) mkFAs pgf cnc = (slfStyleFA main, [(c,slfStyleFA n) | (c,n) <- subs])
where MFA start subs = {- renameSubs $ -} cfgToMFA $ pgfToCFG pgf cnc where MFA start subs = {- renameSubs $ -} cfgToMFA $ pgfToCFG pgf cnc
main = let (fa,s,f) = newFA_ in newTransition s f (NonTerminal start) fa main = let (fa,s,f) = newFA_ in newTransition s f (NonTerminal start) fa
@@ -64,7 +61,7 @@ renameSubs (MFA start subs) = MFA (newName start) subs'
-- * SLF graphviz printing (without sub-networks) -- * SLF graphviz printing (without sub-networks)
-- --
slfGraphvizPrinter :: PGF -> CId -> String slfGraphvizPrinter :: PGF -> Concr -> String
slfGraphvizPrinter pgf cnc slfGraphvizPrinter pgf cnc
= prFAGraphviz $ gvFA $ slfStyleFA $ cfgToFA' $ pgfToCFG pgf cnc = prFAGraphviz $ gvFA $ slfStyleFA $ cfgToFA' $ pgfToCFG pgf cnc
where where
@@ -74,7 +71,7 @@ slfGraphvizPrinter pgf cnc
-- * SLF graphviz printing (with sub-networks) -- * SLF graphviz printing (with sub-networks)
-- --
slfSubGraphvizPrinter :: PGF -> CId -> String slfSubGraphvizPrinter :: PGF -> Concr -> String
slfSubGraphvizPrinter pgf cnc = Dot.prGraphviz g slfSubGraphvizPrinter pgf cnc = Dot.prGraphviz g
where (main, subs) = mkFAs pgf cnc where (main, subs) = mkFAs pgf cnc
g = STM.evalState (liftM2 Dot.addSubGraphs ss m) [0..] g = STM.evalState (liftM2 Dot.addSubGraphs ss m) [0..]
@@ -100,7 +97,7 @@ gvSLFFA n fa =
-- * SLF printing (without sub-networks) -- * SLF printing (without sub-networks)
-- --
slfPrinter :: PGF -> CId -> String slfPrinter :: PGF -> Concr -> String
slfPrinter pgf cnc slfPrinter pgf cnc
= prSLF $ automatonToSLF mkSLFNode $ slfStyleFA $ cfgToFA' $ pgfToCFG pgf cnc = prSLF $ automatonToSLF mkSLFNode $ slfStyleFA $ cfgToFA' $ pgfToCFG pgf cnc
@@ -109,7 +106,7 @@ slfPrinter pgf cnc
-- --
-- | Make a network with subnetworks in SLF -- | Make a network with subnetworks in SLF
slfSubPrinter :: PGF -> CId -> String slfSubPrinter :: PGF -> Concr -> String
slfSubPrinter pgf cnc = prSLFs slfs slfSubPrinter pgf cnc = prSLFs slfs
where where
(main,subs) = mkFAs pgf cnc (main,subs) = mkFAs pgf cnc

View File

@@ -17,21 +17,15 @@ module GF.Speech.SRG (SRG(..), SRGRule(..), SRGAlt(..), SRGItem, SRGSymbol
, lookupFM_ , lookupFM_
) where ) where
--import GF.Data.Operations import PGF2
import GF.Data.Utilities import GF.Data.Utilities
--import GF.Infra.Ident
import GF.Infra.Option import GF.Infra.Option
import GF.Grammar.CFG import GF.Grammar.CFG
import GF.Speech.PGFToCFG import GF.Speech.PGFToCFG
--import GF.Data.Relation
--import GF.Speech.FiniteState
import GF.Speech.RegExp import GF.Speech.RegExp
import GF.Speech.CFGToFA import GF.Speech.CFGToFA
--import GF.Infra.Option
import PGF
import Data.List import Data.List
--import Data.Maybe (fromMaybe, maybeToList)
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)
@@ -40,20 +34,20 @@ import qualified Data.Set as Set
--import Debug.Trace --import Debug.Trace
data SRG = SRG { srgName :: String -- ^ grammar name data SRG = SRG { srgName :: String -- ^ grammar name
, srgStartCat :: Cat -- ^ start category name , srgStartCat :: Cat -- ^ start category name
, srgExternalCats :: Set Cat , srgExternalCats :: Set Cat
, srgLanguage :: Maybe String -- ^ The language for which the grammar , srgLanguage :: Maybe String -- ^ The language for which the grammar
-- is intended, e.g. en-UK -- is intended, e.g. en-UK
, srgRules :: [SRGRule] , srgRules :: [SRGRule]
} }
deriving (Eq,Show) deriving (Eq,Show)
data SRGRule = SRGRule Cat [SRGAlt] data SRGRule = SRGRule Cat [SRGAlt]
deriving (Eq,Show) deriving (Eq,Show)
-- | maybe a probability, a rule name and an EBNF right-hand side -- | maybe a probability, a rule name and an EBNF right-hand side
data SRGAlt = SRGAlt (Maybe Double) CFTerm SRGItem data SRGAlt = SRGAlt (Maybe Double) CFTerm SRGItem
deriving (Eq,Show) deriving (Eq,Show)
type SRGItem = RE SRGSymbol type SRGItem = RE SRGSymbol
@@ -62,16 +56,16 @@ type SRGSymbol = Symbol SRGNT Token
-- | An SRG non-terminal. Category name and its number in the profile. -- | An SRG non-terminal. Category name and its number in the profile.
type SRGNT = (Cat, Int) type SRGNT = (Cat, Int)
ebnfPrinter :: Options -> PGF -> CId -> String ebnfPrinter :: Options -> PGF -> Concr -> String
ebnfPrinter opts pgf cnc = prSRG opts $ makeSRG opts pgf cnc ebnfPrinter opts pgf cnc = prSRG opts $ makeSRG opts pgf cnc
-- | Create a compact filtered non-left-recursive SRG. -- | Create a compact filtered non-left-recursive SRG.
makeNonLeftRecursiveSRG :: Options -> PGF -> CId -> SRG makeNonLeftRecursiveSRG :: Options -> PGF -> Concr -> SRG
makeNonLeftRecursiveSRG opts = makeSRG opts' makeNonLeftRecursiveSRG opts = makeSRG opts'
where where
opts' = setDefaultCFGTransform opts CFGNoLR True opts' = setDefaultCFGTransform opts CFGNoLR True
makeSRG :: Options -> PGF -> CId -> SRG makeSRG :: Options -> PGF -> Concr -> SRG
makeSRG opts = mkSRG cfgToSRG preprocess makeSRG opts = mkSRG cfgToSRG preprocess
where where
cfgToSRG cfg = [cfRulesToSRGRule rs | (_,rs) <- allRulesGrouped cfg] cfgToSRG cfg = [cfRulesToSRGRule rs | (_,rs) <- allRulesGrouped cfg]
@@ -97,7 +91,7 @@ stats g = "Categories: " ++ show (countCats g)
-} -}
makeNonRecursiveSRG :: Options makeNonRecursiveSRG :: Options
-> PGF -> PGF
-> CId -- ^ Concrete syntax name. -> Concr
-> SRG -> SRG
makeNonRecursiveSRG opts = mkSRG cfgToSRG id makeNonRecursiveSRG opts = mkSRG cfgToSRG id
where where
@@ -105,17 +99,17 @@ makeNonRecursiveSRG opts = mkSRG cfgToSRG id
where where
MFA _ dfas = cfgToMFA cfg MFA _ dfas = cfgToMFA cfg
dfaToSRGItem = mapRE dummySRGNT . minimizeRE . dfa2re dfaToSRGItem = mapRE dummySRGNT . minimizeRE . dfa2re
dummyCFTerm = CFMeta (mkCId "dummy") dummyCFTerm = CFMeta "dummy"
dummySRGNT = mapSymbol (\c -> (c,0)) id dummySRGNT = mapSymbol (\c -> (c,0)) id
mkSRG :: (CFG -> [SRGRule]) -> (CFG -> CFG) -> PGF -> CId -> SRG mkSRG :: (CFG -> [SRGRule]) -> (CFG -> CFG) -> PGF -> Concr -> SRG
mkSRG mkRules preprocess pgf cnc = mkSRG mkRules preprocess pgf cnc =
SRG { srgName = showCId cnc, SRG { srgName = concreteName cnc,
srgStartCat = cfgStartCat cfg, srgStartCat = cfgStartCat cfg,
srgExternalCats = cfgExternalCats cfg, srgExternalCats = cfgExternalCats cfg,
srgLanguage = languageCode pgf cnc, srgLanguage = languageCode cnc,
srgRules = mkRules cfg } srgRules = mkRules cfg }
where cfg = renameCats (showCId cnc) $ preprocess $ pgfToCFG pgf cnc where cfg = renameCats (concreteName cnc) $ preprocess $ pgfToCFG pgf cnc
-- | Renames all external cats C to C_cat, and all internal cats C_X (where X is any string), -- | Renames all external cats C to C_cat, and all internal cats C_X (where X is any string),
-- to C_N where N is an integer. -- to C_N where N is an integer.

View File

@@ -18,31 +18,27 @@
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
module GF.Speech.SRGS_ABNF (srgsAbnfPrinter, srgsAbnfNonRecursivePrinter) where module GF.Speech.SRGS_ABNF (srgsAbnfPrinter, srgsAbnfNonRecursivePrinter) where
import Prelude hiding ((<>)) -- GHC 8.4.1 clash with Text.PrettyPrint
--import GF.Data.Utilities import Prelude hiding ((<>))
import GF.Infra.Option import GF.Infra.Option
import GF.Grammar.CFG import GF.Grammar.CFG
import GF.Speech.SISR as SISR import GF.Speech.SISR as SISR
import GF.Speech.SRG import GF.Speech.SRG
import GF.Speech.RegExp import GF.Speech.RegExp
import PGF (PGF, CId) import PGF2 (PGF,Concr)
--import Data.Char
import Data.List import Data.List
import Data.Maybe import Data.Maybe
import GF.Text.Pretty import GF.Text.Pretty
--import Debug.Trace
width :: Int width :: Int
width = 75 width = 75
srgsAbnfPrinter :: Options srgsAbnfPrinter :: Options -> PGF -> Concr -> String
-> PGF -> CId -> String
srgsAbnfPrinter opts pgf cnc = showDoc $ prABNF sisr $ makeNonLeftRecursiveSRG opts pgf cnc srgsAbnfPrinter opts pgf cnc = showDoc $ prABNF sisr $ makeNonLeftRecursiveSRG opts pgf cnc
where sisr = flag optSISR opts where sisr = flag optSISR opts
srgsAbnfNonRecursivePrinter :: Options -> PGF -> CId -> String srgsAbnfNonRecursivePrinter :: Options -> PGF -> Concr -> String
srgsAbnfNonRecursivePrinter opts pgf cnc = showDoc $ prABNF Nothing $ makeNonRecursiveSRG opts pgf cnc srgsAbnfNonRecursivePrinter opts pgf cnc = showDoc $ prABNF Nothing $ makeNonRecursiveSRG opts pgf cnc
showDoc = renderStyle (style { lineLength = width }) showDoc = renderStyle (style { lineLength = width })
@@ -125,4 +121,3 @@ prepunctuate p (x:xs) = x : map (p <>) xs
($++$) :: Doc -> Doc -> Doc ($++$) :: Doc -> Doc -> Doc
x $++$ y = x $$ emptyLine $$ y x $++$ y = x $$ emptyLine $$ y

View File

@@ -13,7 +13,7 @@ import GF.Grammar.CFG
import GF.Speech.RegExp import GF.Speech.RegExp
import GF.Speech.SISR as SISR import GF.Speech.SISR as SISR
import GF.Speech.SRG import GF.Speech.SRG
import PGF (PGF, CId, Token) import PGF2 (PGF, Concr)
--import Control.Monad --import Control.Monad
--import Data.Char (toUpper,toLower) --import Data.Char (toUpper,toLower)
@@ -22,11 +22,11 @@ import Data.Maybe
--import qualified Data.Map as Map --import qualified Data.Map as Map
srgsXmlPrinter :: Options srgsXmlPrinter :: Options
-> PGF -> CId -> String -> PGF -> Concr -> String
srgsXmlPrinter opts pgf cnc = prSrgsXml sisr $ makeNonLeftRecursiveSRG opts pgf cnc srgsXmlPrinter opts pgf cnc = prSrgsXml sisr $ makeNonLeftRecursiveSRG opts pgf cnc
where sisr = flag optSISR opts where sisr = flag optSISR opts
srgsXmlNonRecursivePrinter :: Options -> PGF -> CId -> String srgsXmlNonRecursivePrinter :: Options -> PGF -> Concr -> String
srgsXmlNonRecursivePrinter opts pgf cnc = prSrgsXml Nothing $ makeNonRecursiveSRG opts pgf cnc srgsXmlNonRecursivePrinter opts pgf cnc = prSrgsXml Nothing $ makeNonRecursiveSRG opts pgf cnc
@@ -37,7 +37,7 @@ prSrgsXml sisr srg = showXMLDoc (optimizeSRGS xmlGr)
[meta "description" [meta "description"
("SRGS XML speech recognition grammar for " ++ srgName srg ++ "."), ("SRGS XML speech recognition grammar for " ++ srgName srg ++ "."),
meta "generator" "Grammatical Framework"] meta "generator" "Grammatical Framework"]
++ map ruleToXML (srgRules srg) ++ map ruleToXML (srgRules srg)
ruleToXML (SRGRule cat alts) = Tag "rule" ([("id",cat)]++pub) (prRhs alts) ruleToXML (SRGRule cat alts) = Tag "rule" ([("id",cat)]++pub) (prRhs alts)
where pub = if isExternalCat srg cat then [("scope","public")] else [] where pub = if isExternalCat srg cat then [("scope","public")] else []
prRhs rhss = [oneOf (map (mkProd sisr) rhss)] prRhs rhss = [oneOf (map (mkProd sisr) rhss)]
@@ -81,12 +81,12 @@ oneOf = Tag "one-of" []
grammar :: Maybe SISRFormat grammar :: Maybe SISRFormat
-> String -- ^ root -> String -- ^ root
-> Maybe String -- ^language -> Maybe String -- ^language
-> [XML] -> XML -> [XML] -> XML
grammar sisr root ml = grammar sisr root ml =
Tag "grammar" $ [("xmlns","http://www.w3.org/2001/06/grammar"), Tag "grammar" $ [("xmlns","http://www.w3.org/2001/06/grammar"),
("version","1.0"), ("version","1.0"),
("mode","voice"), ("mode","voice"),
("root",root)] ("root",root)]
++ (if isJust sisr then [("tag-format","semantics/1.0")] else []) ++ (if isJust sisr then [("tag-format","semantics/1.0")] else [])
++ maybe [] (\l -> [("xml:lang", l)]) ml ++ maybe [] (\l -> [("xml:lang", l)]) ml

View File

@@ -6,15 +6,8 @@
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
module GF.Speech.VoiceXML (grammar2vxml) where module GF.Speech.VoiceXML (grammar2vxml) where
--import GF.Data.Operations
--import GF.Data.Str (sstrV)
--import GF.Data.Utilities
import GF.Data.XML import GF.Data.XML
--import GF.Infra.Ident import PGF2
import PGF
import PGF.Internal
--import Control.Monad (liftM)
import Data.List (intersperse) -- isPrefixOf, find import Data.List (intersperse) -- isPrefixOf, find
import qualified Data.Map as Map import qualified Data.Map as Map
import Data.Maybe (fromMaybe) import Data.Maybe (fromMaybe)
@@ -22,59 +15,45 @@ import Data.Maybe (fromMaybe)
--import Debug.Trace --import Debug.Trace
-- | the main function -- | the main function
grammar2vxml :: PGF -> CId -> String grammar2vxml :: PGF -> Concr -> String
grammar2vxml pgf cnc = showsXMLDoc (skel2vxml name language start skel qs) "" grammar2vxml pgf cnc = showsXMLDoc (skel2vxml name mb_language start skel qs) ""
where skel = pgfSkeleton pgf where skel = pgfSkeleton pgf
name = showCId cnc name = concreteName cnc
qs = catQuestions pgf cnc (map fst skel) qs = catQuestions cnc (map fst skel)
language = languageCode pgf cnc mb_language = languageCode cnc
start = lookStartCat pgf (_,start,_) = unType (startCat pgf)
-- --
-- * VSkeleton: a simple description of the abstract syntax. -- * VSkeleton: a simple description of the abstract syntax.
-- --
type Skeleton = [(CId, [(CId, [CId])])] type Skeleton = [(Cat, [(Fun, [Cat])])]
pgfSkeleton :: PGF -> Skeleton pgfSkeleton :: PGF -> Skeleton
pgfSkeleton pgf = [(c,[(f,fst (catSkeleton (lookType (abstract pgf) f))) | (_,f) <- fs]) pgfSkeleton pgf = [(c,[(f,[cat | (_,_,ty) <- hypos, let (_,cat,_) = unType ty]) | f <- functionsByCat pgf c, Just (hypos,_,_) <- [fmap unType (functionType pgf f)]])
| (c,(_,fs,_)) <- Map.toList (cats (abstract pgf))] | c <- categories pgf]
-- --
-- * Questions to ask -- * Questions to ask
-- --
type CatQuestions = [(CId,String)] type CatQuestions = [(Cat,String)]
catQuestions :: PGF -> CId -> [CId] -> CatQuestions catQuestions :: Concr -> [Cat] -> CatQuestions
catQuestions pgf cnc cats = [(c,catQuestion pgf cnc c) | c <- cats] catQuestions cnc cats = [(c,catQuestion cnc c) | c <- cats]
catQuestion :: PGF -> CId -> CId -> String catQuestion :: Concr -> Cat -> String
catQuestion pgf cnc cat = showPrintName pgf cnc cat catQuestion cnc cat = fromMaybe cat (printName cnc cat)
getCatQuestion :: Cat -> CatQuestions -> String
{-
lin :: StateGrammar -> String -> Err String
lin gr fun = do
tree <- string2treeErr gr fun
let ls = map unt $ linTree2strings noMark g c tree
case ls of
[] -> fail $ "No linearization of " ++ fun
l:_ -> return l
where c = cncId gr
g = stateGrammarST gr
unt = formatAsText
-}
getCatQuestion :: CId -> CatQuestions -> String
getCatQuestion c qs = getCatQuestion c qs =
fromMaybe (error "No question for category " ++ showCId c) (lookup c qs) fromMaybe (error "No question for category " ++ c) (lookup c qs)
-- --
-- * Generate VoiceXML -- * Generate VoiceXML
-- --
skel2vxml :: String -> Maybe String -> CId -> Skeleton -> CatQuestions -> XML skel2vxml :: String -> Maybe String -> Cat -> Skeleton -> CatQuestions -> XML
skel2vxml name language start skel qs = skel2vxml name language start skel qs =
vxml language ([startForm] ++ concatMap (uncurry (catForms gr qs)) skel) vxml language ([startForm] ++ concatMap (uncurry (catForms gr qs)) skel)
where where
@@ -86,12 +65,12 @@ grammarURI :: String -> String
grammarURI name = name ++ ".grxml" grammarURI name = name ++ ".grxml"
catForms :: String -> CatQuestions -> CId -> [(CId, [CId])] -> [XML] catForms :: String -> CatQuestions -> Cat -> [(Fun, [Cat])] -> [XML]
catForms gr qs cat fs = catForms gr qs cat fs =
comments [showCId cat ++ " category."] comments [cat ++ " category."]
++ [cat2form gr qs cat fs] ++ [cat2form gr qs cat fs]
cat2form :: String -> CatQuestions -> CId -> [(CId, [CId])] -> XML cat2form :: String -> CatQuestions -> Cat -> [(Fun, [Cat])] -> XML
cat2form gr qs cat fs = cat2form gr qs cat fs =
form (catFormId cat) $ form (catFormId cat) $
[var "old" Nothing, [var "old" Nothing,
@@ -104,22 +83,22 @@ cat2form gr qs cat fs =
++ concatMap (uncurry (fun2sub gr cat)) fs ++ concatMap (uncurry (fun2sub gr cat)) fs
++ [block [return_ ["term"]{-]-}]] ++ [block [return_ ["term"]{-]-}]]
fun2sub :: String -> CId -> CId -> [CId] -> [XML] fun2sub :: String -> Cat -> Fun -> [Cat] -> [XML]
fun2sub gr cat fun args = fun2sub gr cat fun args =
comments [showCId fun ++ " : (" comments [fun ++ " : ("
++ concat (intersperse ", " (map showCId args)) ++ concat (intersperse ", " args)
++ ") " ++ showCId cat] ++ ss ++ ") " ++ cat] ++ ss
where where
ss = zipWith mkSub [0..] args ss = zipWith mkSub [0..] args
mkSub n t = subdialog s [("src","#"++catFormId t), mkSub n t = subdialog s [("src","#"++catFormId t),
("cond","term.name == "++string (showCId fun))] ("cond","term.name == "++string fun)]
[param "old" v, [param "old" v,
filled [] [assign v (s++".term")]] filled [] [assign v (s++".term")]]
where s = showCId fun ++ "_" ++ show n where s = fun ++ "_" ++ show n
v = "term.args["++show n++"]" v = "term.args["++show n++"]"
catFormId :: CId -> String catFormId :: Cat -> String
catFormId c = showCId c ++ "_cat" catFormId c = c ++ "_cat"
-- --

View File

@@ -14,11 +14,11 @@
module GF.System.NoSignal where module GF.System.NoSignal where
import Control.Exception (Exception,catch) import Control.Exception (SomeException,catch)
import Prelude hiding (catch) import Prelude hiding (catch)
{-# NOINLINE runInterruptibly #-} {-# NOINLINE runInterruptibly #-}
runInterruptibly :: IO a -> IO (Either Exception a) runInterruptibly :: IO a -> IO (Either SomeException a)
--runInterruptibly = fmap Right --runInterruptibly = fmap Right
runInterruptibly a = runInterruptibly a =
p `catch` h p `catch` h

View File

@@ -15,7 +15,6 @@ stringOp good name = case name of
"lexgreek" -> Just $ appLexer lexAGreek "lexgreek" -> Just $ appLexer lexAGreek
"lexgreek2" -> Just $ appLexer lexAGreek2 "lexgreek2" -> Just $ appLexer lexAGreek2
"words" -> Just $ appLexer words "words" -> Just $ appLexer words
"bind" -> Just $ appUnlexer (unwords . bindTok)
"unchars" -> Just $ appUnlexer concat "unchars" -> Just $ appUnlexer concat
"unlextext" -> Just $ appUnlexer (unlexText . unquote . bindTok) "unlextext" -> Just $ appUnlexer (unlexText . unquote . bindTok)
"unlexcode" -> Just $ appUnlexer unlexCode "unlexcode" -> Just $ appUnlexer unlexCode

View File

@@ -39,7 +39,6 @@ allTransliterations = Map.fromList [
("amharic",transAmharic), ("amharic",transAmharic),
("ancientgreek", transAncientGreek), ("ancientgreek", transAncientGreek),
("arabic", transArabic), ("arabic", transArabic),
("arabic_unvocalized", transArabicUnvoc),
("devanagari", transDevanagari), ("devanagari", transDevanagari),
("greek", transGreek), ("greek", transGreek),
("hebrew", transHebrew), ("hebrew", transHebrew),
@@ -142,7 +141,7 @@ transUrdu =
(mkTransliteration "Urdu" allTrans allCodes) where (mkTransliteration "Urdu" allTrans allCodes) where
allCodes = [0x0622 .. 0x062f] ++ [0x0630 .. 0x063a] ++ [0x0641,0x0642] ++ [0x06A9] ++ [0x0644 .. 0x0648] ++ allCodes = [0x0622 .. 0x062f] ++ [0x0630 .. 0x063a] ++ [0x0641,0x0642] ++ [0x06A9] ++ [0x0644 .. 0x0648] ++
[0x0654,0x0658,0x0679,0x067e,0x0686,0x0688,0x0691,0x0698,0x06af,0x06c1,0x06c3,0x06cc,0x06ba,0x06be,0x06d2] ++ [0x0654,0x0658,0x0679,0x067e,0x0686,0x0688,0x0691,0x0698,0x06af,0x06c1,0x06c3,0x06cc,0x06ba,0x06be,0x06d2] ++
[0x06f0 .. 0x06f9] ++ [0x061f,0x06D4] [0x06f0 .. 0x06f9] ++ [0x061f,0x06D4]
allTrans = words $ allTrans = words $
"A - w^ - y^ a b - t C j H K d " ++ -- 0622 - 062f "A - w^ - y^ a b - t C j H K d " ++ -- 0622 - 062f
"Z r z s X S Z- t- z- e G " ++ -- 0630 - 063a "Z r z s X S Z- t- z- e G " ++ -- 0630 - 063a
@@ -156,7 +155,7 @@ transSindhi =
allCodes = [0x062e] ++ [0x0627 .. 0x062f] ++ [0x0630 .. 0x063a] ++ [0x0641 .. 0x0648] ++ allCodes = [0x062e] ++ [0x0627 .. 0x062f] ++ [0x0630 .. 0x063a] ++ [0x0641 .. 0x0648] ++
[0x067a,0x067b,0x067d,0x067e,0x067f] ++ [0x0680 .. 0x068f] ++ [0x067a,0x067b,0x067d,0x067e,0x067f] ++ [0x0680 .. 0x068f] ++
[0x0699,0x0918,0x06a6,0x061d,0x06a9,0x06af,0x06b3,0x06bb,0x06be,0x06f6,0x064a,0x06b1, 0x06aa, 0x06fd, 0x06fe] ++ [0x0699,0x0918,0x06a6,0x061d,0x06a9,0x06af,0x06b3,0x06bb,0x06be,0x06f6,0x064a,0x06b1, 0x06aa, 0x06fd, 0x06fe] ++
[0x06f0 .. 0x06f9] ++ [0x061f,0x06D4] [0x06f0 .. 0x06f9] ++ [0x061f,0x06D4]
allTrans = words $ allTrans = words $
"K a b - t C j H - d " ++ -- 0626 - 062f "K a b - t C j H - d " ++ -- 0626 - 062f
"Z r z s X S Z- t- z- e G " ++ -- 0630 - 063a "Z r z s X S Z- t- z- e G " ++ -- 0630 - 063a
@@ -179,13 +178,6 @@ transArabic = mkTransliteration "Arabic" allTrans allCodes where
allCodes = [0x0621..0x062f] ++ [0x0630..0x063a] ++ allCodes = [0x0621..0x062f] ++ [0x0630..0x063a] ++
[0x0641..0x064f] ++ [0x0650..0x0657] ++ [0x0671,0x061f] [0x0641..0x064f] ++ [0x0650..0x0657] ++ [0x0671,0x061f]
transArabicUnvoc :: Transliteration
transArabicUnvoc = transArabic{
invisible_chars = ["a","u","i","v2","o","V+","V-","a:"],
printname = "unvocalized Arabic"
}
transPersian :: Transliteration transPersian :: Transliteration
transPersian = (mkTransliteration "Persian/Farsi" allTrans allCodes) transPersian = (mkTransliteration "Persian/Farsi" allTrans allCodes)
{invisible_chars = ["a","u","i"]} where {invisible_chars = ["a","u","i"]} where
@@ -300,32 +292,30 @@ transAncientGreek = mkTransliteration "ancient Greek" allTrans allCodes where
transAmharic :: Transliteration transAmharic :: Transliteration
transAmharic = mkTransliteration "Amharic" allTrans allCodes where transAmharic = mkTransliteration "Amharic" allTrans allCodes where
allTrans = words $
allTrans = words $ " h. h- h' h( h) h h? h* l. l- l' l( l) l l? l* "++
" H. H- H' H( H) H H? H* m. m- m' m( m) m m? m* "++
" h. h- h' h( h) h h? h* l. l- l' l( l) l l? l* "++ " s. s- s' s( s) s s? s* r. r- r' r( r) r r? r* "++
" H. H- H' H( H) H H? H* m. m- m' m( m) m m? m* "++ " - - - - - - - - x. x- x' x( x) x x? x* "++
" s. s- s' s( s) s s? s* r. r- r' r( r) r r? r* "++ " q. q- q' q( q) q q? q* - - - - - - - - "++
" - - - - - - - - x. x- x' x( x) x x? x* "++ " - - - - - - - - - - - - - - - - "++
" q. q- q' q( q) q q? q* - - - - - - - - "++ " b. b- b' b( b) b b? b* v. v- v' v( v) v v? v* "++
" - - - - - - - - - - - - - - - - "++ " t. t- t' t( t) t t? t* c. c- c' c( c) c c? c* "++
" b. b- b' b( b) b b? b* v. v- v' v( v) v v? v* "++ " X. X- X' X( X) X X? - - - - X* - - - - "++
" t. t- t' t( t) t t? t* c. c- c' c( c) c c? c* "++ " n. n- n' n( n) n n? n* N. N- N' N( N) N N? N* "++
" X. X- X' X( X) X X? - - - - X* - - - - "++ " a u i A E e o e* k. k- k' k( k) k k? - "++
" n. n- n' n( n) n n? n* N. N- N' N( N) N N? N* "++ " - - - k* - - - - - - - - - - - - "++
" a u i A E e o e* k. k- k' k( k) k k? - "++ " - - - - - - - - w. w- w' w( w) w w? w* "++
" - - - k* - - - - - - - - - - - - "++ " - - - - - - - - z. z- z' z( z) z z? z* "++
" - - - - - - - - w. w- w' w( w) w w? w* "++ " Z. Z- Z' Z( Z) Z Z? Z* y. y- y' y( y) y y? y* "++
" - - - - - - - - z. z- z' z( z) z z? z* "++ " d. d- d' d( d) d d? d* - - - - - - - - "++
" Z. Z- Z' Z( Z) Z Z? Z* y. y- y' y( y) y y? y* "++ " j. j- j' j( j) j j? j* g. g- g' g( g) g g? - "++
" d. d- d' d( d) d d? d* - - - - - - - - "++ " - - - g* - - - - - - - - - - - - "++
" j. j- j' j( j) j j? j* g. g- g' g( g) g g? - "++ " T. T- T' T( T) T T? T* C. C- C' C( C) C C? C* "++
" - - - g* - - - - - - - - - - - - "++ " P. P- P' P( P) P P? P* S. S- S' S( S) S S? S* "++
" T. T- T' T( T) T T? T* C. C- C' C( C) C C? C* "++ " - - - - - - - - f. f- f' f( f) f f? f*"++
" P. P- P' P( P) P P? P* S. S- S' S( S) S S? S* "++ " p. p- p' p( p) p p? p*"
" - - - - - - - - f. f- f' f( f) f f? f*"++ allCodes = [0x1200..0x1357]
" p. p- p' p( p) p p? p*"
allCodes = [0x1200..0x1357]
-- by Prasad 31/5/2013 -- by Prasad 31/5/2013
transSanskrit :: Transliteration transSanskrit :: Transliteration

Some files were not shown because too many files have changed in this diff Show More