forked from GitHub/gf-core
Compare commits
395 Commits
compact-pg
...
v3.11-test
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8814fde817 | ||
|
|
375b3cf285 | ||
|
|
3c4f42db15 | ||
|
|
0474a37af6 | ||
|
|
e3498d5ead | ||
|
|
4c5927c98c | ||
|
|
bb51224e8e | ||
|
|
9533edc3ca | ||
|
|
4df8999ed5 | ||
|
|
7fdbf3f400 | ||
|
|
0d6c67f6b1 | ||
|
|
2610219f6a | ||
|
|
7674f078d6 | ||
|
|
c67fe05c08 | ||
|
|
7b9bb780a2 | ||
|
|
4f256447e2 | ||
|
|
dfa5b9276d | ||
|
|
667bfd30bd | ||
|
|
66ae31e99e | ||
|
|
a677f0373c | ||
|
|
13f845d127 | ||
|
|
aa530233fb | ||
|
|
45bc5595c0 | ||
|
|
6d12754e4f | ||
|
|
a09d9bd006 | ||
|
|
fffe3161d4 | ||
|
|
743f5e55d4 | ||
|
|
9e209bbaba | ||
|
|
a1594e6a69 | ||
|
|
06e0a986d1 | ||
|
|
6f2a4bcd2c | ||
|
|
f345f615f4 | ||
|
|
80d16fcf94 | ||
|
|
7faf8c9dad | ||
|
|
c2ffa6763b | ||
|
|
b3881570c7 | ||
|
|
bd270b05ff | ||
|
|
a1fd3ea142 | ||
|
|
cdbe73eb47 | ||
|
|
6077d5dd5b | ||
|
|
0954b4cbab | ||
|
|
f2e52d6f2c | ||
|
|
a2b23d5897 | ||
|
|
0886eb520d | ||
|
|
ef42216415 | ||
|
|
0c3ca3d79a | ||
|
|
e2e5033075 | ||
|
|
84b4b6fab9 | ||
|
|
5e052ff499 | ||
|
|
d2fb755fab | ||
|
|
1b66bf2773 | ||
|
|
1e3de38ac4 | ||
|
|
4e8859aa75 | ||
|
|
dff215504a | ||
|
|
173ab96839 | ||
|
|
dff1193f7b | ||
|
|
e1a40640cd | ||
|
|
be231584f6 | ||
|
|
12c564f97c | ||
|
|
09d772046e | ||
|
|
d53e1713c7 | ||
|
|
3df04295d9 | ||
|
|
b090e9b0ff | ||
|
|
5d7c687cb7 | ||
|
|
376b1234a2 | ||
|
|
71d99b9ecb | ||
|
|
a27b07542d | ||
|
|
78b73fba20 | ||
|
|
e5a2aed5b6 | ||
|
|
13575b093f | ||
|
|
32be75ca7d | ||
|
|
587004f985 | ||
|
|
4436cb101e | ||
|
|
0f5be0bbaa | ||
|
|
d5c6aec3ec | ||
|
|
0a70eca6e2 | ||
|
|
6efbd23c5c | ||
|
|
3a27fa0d39 | ||
|
|
1ba5449d21 | ||
|
|
cf9afa8f74 | ||
|
|
91d2ecf23c | ||
|
|
8206143328 | ||
|
|
5564a2f244 | ||
|
|
cf2eff3801 | ||
|
|
5a53a38247 | ||
|
|
02671cafd0 | ||
|
|
0a18688788 | ||
|
|
889be1ab8e | ||
|
|
65522a63c3 | ||
|
|
7065125e19 | ||
|
|
2c37e7dfad | ||
|
|
f505d88a8e | ||
|
|
b1ed63b089 | ||
|
|
f23031ea1d | ||
|
|
c3153134b7 | ||
|
|
fd4fb62b9e | ||
|
|
53c3afbd6f | ||
|
|
544b39a8a5 | ||
|
|
6179d79e72 | ||
|
|
ecb19013c0 | ||
|
|
c416571406 | ||
|
|
a1372040b4 | ||
|
|
67fcf21577 | ||
|
|
a7ab610f95 | ||
|
|
e5b8fa095b | ||
|
|
6beebbac2b | ||
|
|
95917a7715 | ||
|
|
de8b23c014 | ||
|
|
098541dda2 | ||
|
|
af87664d27 | ||
|
|
af1360d37e | ||
|
|
eeda03e9b0 | ||
|
|
7042768054 | ||
|
|
84fd431afd | ||
|
|
588cd6ddb1 | ||
|
|
437bd8e7f9 | ||
|
|
e56d1b2959 | ||
|
|
450368f9bb | ||
|
|
07fd41294a | ||
|
|
4729d22c36 | ||
|
|
60bc752a6f | ||
|
|
91278e2b4b | ||
|
|
9b4f2dd18b | ||
|
|
9dda5dfa8a | ||
|
|
2fd94f5f57 | ||
|
|
ba3e09cc38 | ||
|
|
8fbfc0b4a9 | ||
|
|
f9b8653ab2 | ||
|
|
173fca7f12 | ||
|
|
c6ff3e0c5e | ||
|
|
8a85dbc66f | ||
|
|
655173932e | ||
|
|
04f6f113f0 | ||
|
|
bac619f025 | ||
|
|
1a466c14c8 | ||
|
|
d77921005a | ||
|
|
2b6b315bd7 | ||
|
|
7f6bfa730b | ||
|
|
d6be4ec3b0 | ||
|
|
68ec61f44d | ||
|
|
491084e38e | ||
|
|
a7a6eb5581 | ||
|
|
4223935b12 | ||
|
|
8dc1ed83b6 | ||
|
|
8f3a7a3b6a | ||
|
|
921a8981fb | ||
|
|
169f2c786d | ||
|
|
629a574dfa | ||
|
|
6b7e9c8c7a | ||
|
|
78f42774da | ||
|
|
54c0949354 | ||
|
|
0632824b99 | ||
|
|
24bbeb31df | ||
|
|
70811d83be | ||
|
|
0ed6b726a2 | ||
|
|
88252cb107 | ||
|
|
cf6468a452 | ||
|
|
3e1c69da21 | ||
|
|
4bcde7d6a2 | ||
|
|
78c1c099df | ||
|
|
7501a7916e | ||
|
|
32f451f1d7 | ||
|
|
aad2ba61d4 | ||
|
|
9932b10bf1 | ||
|
|
f8da24c5ec | ||
|
|
951e439703 | ||
|
|
08e6aca83d | ||
|
|
301f23ac55 | ||
|
|
e36b7cb044 | ||
|
|
9131581f03 | ||
|
|
d79fa6d22b | ||
|
|
c8623e2be7 | ||
|
|
59dda75f16 | ||
|
|
cac65418ff | ||
|
|
e47ce2a28b | ||
|
|
9a697fbde4 | ||
|
|
43b06d5f53 | ||
|
|
ee6082d100 | ||
|
|
4d2218a0d1 | ||
|
|
af9c8ee553 | ||
|
|
3e20e735a3 | ||
|
|
0a0060373b | ||
|
|
12ece26409 | ||
|
|
424e6887b5 | ||
|
|
4987b70df7 | ||
|
|
a072b4688b | ||
|
|
0b3ae5aaa2 | ||
|
|
a48bbb3b13 | ||
|
|
131d196fad | ||
|
|
b0341ec42d | ||
|
|
293d05fde1 | ||
|
|
d39e4a22a8 | ||
|
|
8e9212d059 | ||
|
|
012541ff55 | ||
|
|
0d12c7101c | ||
|
|
6ee7c88f34 | ||
|
|
08af135653 | ||
|
|
37c63a0c22 | ||
|
|
d4ccd2848c | ||
|
|
6862098d8b | ||
|
|
40e5f90d56 | ||
|
|
3df552eb5d | ||
|
|
dbb0bcc5dd | ||
|
|
38facbc064 | ||
|
|
8cc901f334 | ||
|
|
8550f8deaf | ||
|
|
5a6acf1d47 | ||
|
|
a7ff2d0611 | ||
|
|
30bcafb76f | ||
|
|
ce9caa2726 | ||
|
|
b4ccca8c18 | ||
|
|
2dc11524fc | ||
|
|
76bec6d71e | ||
|
|
1740181daf | ||
|
|
2dc179239f | ||
|
|
9b02385e3e | ||
|
|
54e5fb6645 | ||
|
|
8ca4baf470 | ||
|
|
1f7584bf98 | ||
|
|
4364b1d9fb | ||
|
|
33aad1b8de | ||
|
|
dc6dd988bc | ||
|
|
ac81b418d6 | ||
|
|
feed61dd30 | ||
|
|
1c7c52da68 | ||
|
|
71b10672e8 | ||
|
|
687f56178e | ||
|
|
359f1509fa | ||
|
|
b1b3bc3360 | ||
|
|
9018eabb10 | ||
|
|
ed97a42fde | ||
|
|
f6eb94c33b | ||
|
|
6e2f34f4d0 | ||
|
|
13ec9ca888 | ||
|
|
24619bc3ee | ||
|
|
399974ebfb | ||
|
|
6836360e0c | ||
|
|
3844277a66 | ||
|
|
86729b3efc | ||
|
|
beb7599d33 | ||
|
|
7dc6717b5e | ||
|
|
1ff66006b8 | ||
|
|
db5ee0b66a | ||
|
|
7b4eeb368c | ||
|
|
f2e4b89a22 | ||
|
|
670a58e7e7 | ||
|
|
f3a8658cc1 | ||
|
|
bfb94d1e48 | ||
|
|
df77205c43 | ||
|
|
e41436eb14 | ||
|
|
2826061251 | ||
|
|
f56fbcf86e | ||
|
|
2c2bd158a6 | ||
|
|
d95b3efd6b | ||
|
|
db8b111e72 | ||
|
|
ab52572f44 | ||
|
|
6c54e5b63c | ||
|
|
8bcdeedba0 | ||
|
|
7d6a115cc1 | ||
|
|
127a1b2842 | ||
|
|
2fd1040724 | ||
|
|
340f8d9b93 | ||
|
|
9d8cd55cd5 | ||
|
|
150b592aa9 | ||
|
|
56f94da772 | ||
|
|
57ce76dbc1 | ||
|
|
2b23e0f27e | ||
|
|
57c1014e9f | ||
|
|
7268253f5a | ||
|
|
1234c715fc | ||
|
|
bca0691cb0 | ||
|
|
3de9c664fd | ||
|
|
f6560d309e | ||
|
|
254f03ecfe | ||
|
|
0bb02eeb51 | ||
|
|
bf21b4768c | ||
|
|
47dbf9ac27 | ||
|
|
90fc1d750e | ||
|
|
24beed9a95 | ||
|
|
23edeec5a9 | ||
|
|
542a41fb32 | ||
|
|
85ab6daaaa | ||
|
|
e351e7b79a | ||
|
|
05903b271c | ||
|
|
3bd1f01959 | ||
|
|
0581d6827e | ||
|
|
b8812b54b2 | ||
|
|
251845f83e | ||
|
|
7c478016d0 | ||
|
|
deddde953f | ||
|
|
e10bb790cb | ||
|
|
868566a319 | ||
|
|
aeabc955c8 | ||
|
|
030c3bfee9 | ||
|
|
c53353f087 | ||
|
|
f00f0cb0ef | ||
|
|
22d5f31d74 | ||
|
|
830dbe760d | ||
|
|
d7965d81b4 | ||
|
|
a2d7f1369c | ||
|
|
0cee82f715 | ||
|
|
7229033e42 | ||
|
|
8bc4cc7187 | ||
|
|
2b09e70b4a | ||
|
|
38f468eed3 | ||
|
|
88a73c1d9e | ||
|
|
77a2630ed9 | ||
|
|
f54e54123c | ||
|
|
2ac796dbbc | ||
|
|
33818076ff | ||
|
|
47d1da0845 | ||
|
|
8a052edca2 | ||
|
|
1360723137 | ||
|
|
4594c36cfb | ||
|
|
d8e88fd42a | ||
|
|
daa2145378 | ||
|
|
398c64734c | ||
|
|
eb185e5358 | ||
|
|
bb4ad9ec7f | ||
|
|
5777b85701 | ||
|
|
ab3c6ec4eb | ||
|
|
63a3a57620 | ||
|
|
aa9b4d06ba | ||
|
|
fff19f31af | ||
|
|
c47f2232c5 | ||
|
|
c802ec6022 | ||
|
|
b2e6d52509 | ||
|
|
383ff5e227 | ||
|
|
71a98cdf00 | ||
|
|
74f3f7a384 | ||
|
|
3fe8c3109f | ||
|
|
7abad1f4bf | ||
|
|
8d4eb9288a | ||
|
|
866e91c917 | ||
|
|
6f5e25d01d | ||
|
|
9ad7d25fb4 | ||
|
|
958da5e5e9 | ||
|
|
f31bccca1c | ||
|
|
bfcab16de6 | ||
|
|
de8cc02ba5 | ||
|
|
dbc7297d80 | ||
|
|
414c2a1a5f | ||
|
|
dca1fcd7fe | ||
|
|
c0714b7d33 | ||
|
|
a4e3bce6bb | ||
|
|
9a903c166f | ||
|
|
4414c3a9c8 | ||
|
|
11201d8645 | ||
|
|
5846622c4d | ||
|
|
d8e543a4e6 | ||
|
|
0a915199e8 | ||
|
|
165c5a6d9d | ||
|
|
0ad1c352fe | ||
|
|
48d3973daa | ||
|
|
9a1f982b14 | ||
|
|
e8653135d4 | ||
|
|
62bc78380e | ||
|
|
dda348776e | ||
|
|
65c810f085 | ||
|
|
b962bcd178 | ||
|
|
589c358389 | ||
|
|
57a1ea5b56 | ||
|
|
762d83c1f0 | ||
|
|
733fdac755 | ||
|
|
00e25d0ccb | ||
|
|
9806232532 | ||
|
|
88f76ef671 | ||
|
|
f22bd70585 | ||
|
|
3133900125 | ||
|
|
e15392e579 | ||
|
|
9604a6309c | ||
|
|
98a18843da | ||
|
|
61641e7a59 | ||
|
|
c50df37144 | ||
|
|
34fd18ea96 | ||
|
|
65024a0a55 | ||
|
|
4b67949d36 | ||
|
|
2ab9fee8e4 | ||
|
|
f4d9b534dc | ||
|
|
14f394c9e9 | ||
|
|
dbb09cc689 | ||
|
|
bb298fadbe | ||
|
|
f1f47f7281 | ||
|
|
fb1199c49c | ||
|
|
12e55c93c0 | ||
|
|
33aeb53f7a | ||
|
|
e6b33ac8b8 | ||
|
|
14e5528544 | ||
|
|
28f53e801a | ||
|
|
6f2b1a83b7 | ||
|
|
d3b501d35f | ||
|
|
95b3fb306f | ||
|
|
5b790b82c5 | ||
|
|
26361b3692 | ||
|
|
30eef61f0a |
96
.github/workflows/build-all-versions.yml
vendored
Normal file
96
.github/workflows/build-all-versions.yml
vendored
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
# Based on the template here: https://kodimensional.dev/github-actions
|
||||||
|
name: Build with stack and cabal
|
||||||
|
|
||||||
|
# Trigger the workflow on push or pull request, but only for the master branch
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
push:
|
||||||
|
branches: [master]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
cabal:
|
||||||
|
name: ${{ matrix.os }} / ghc ${{ matrix.ghc }}
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||||
|
cabal: ["latest"]
|
||||||
|
ghc:
|
||||||
|
- "8.6.5"
|
||||||
|
- "8.8.3"
|
||||||
|
- "8.10.1"
|
||||||
|
exclude:
|
||||||
|
- os: macos-latest
|
||||||
|
ghc: 8.8.3
|
||||||
|
- os: macos-latest
|
||||||
|
ghc: 8.6.5
|
||||||
|
- os: windows-latest
|
||||||
|
ghc: 8.8.3
|
||||||
|
- os: windows-latest
|
||||||
|
ghc: 8.6.5
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
if: github.event.action == 'opened' || github.event.action == 'synchronize' || github.event.ref == 'refs/heads/master'
|
||||||
|
|
||||||
|
- uses: haskell/actions/setup@v1
|
||||||
|
id: setup-haskell-cabal
|
||||||
|
name: Setup Haskell
|
||||||
|
with:
|
||||||
|
ghc-version: ${{ matrix.ghc }}
|
||||||
|
cabal-version: ${{ matrix.cabal }}
|
||||||
|
|
||||||
|
- name: Freeze
|
||||||
|
run: |
|
||||||
|
cabal freeze
|
||||||
|
|
||||||
|
- uses: actions/cache@v1
|
||||||
|
name: Cache ~/.cabal/store
|
||||||
|
with:
|
||||||
|
path: ${{ steps.setup-haskell-cabal.outputs.cabal-store }}
|
||||||
|
key: ${{ runner.os }}-${{ matrix.ghc }}
|
||||||
|
# key: ${{ runner.os }}-${{ matrix.ghc }}-${{ hashFiles('cabal.project.freeze') }}
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
cabal configure --enable-tests --enable-benchmarks --test-show-details=direct
|
||||||
|
cabal build all
|
||||||
|
|
||||||
|
# - name: Test
|
||||||
|
# run: |
|
||||||
|
# cabal test all
|
||||||
|
|
||||||
|
stack:
|
||||||
|
name: stack / ghc ${{ matrix.ghc }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
stack: ["latest"]
|
||||||
|
ghc: ["7.10.3","8.0.2", "8.2.2", "8.4.4", "8.6.5", "8.8.4"]
|
||||||
|
# ghc: ["8.8.3"]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
if: github.event.action == 'opened' || github.event.action == 'synchronize' || github.event.ref == 'refs/heads/master'
|
||||||
|
|
||||||
|
- uses: haskell/actions/setup@v1
|
||||||
|
name: Setup Haskell Stack
|
||||||
|
with:
|
||||||
|
ghc-version: ${{ matrix.ghc }}
|
||||||
|
stack-version: 'latest'
|
||||||
|
enable-stack: true
|
||||||
|
|
||||||
|
- uses: actions/cache@v1
|
||||||
|
name: Cache ~/.stack
|
||||||
|
with:
|
||||||
|
path: ~/.stack
|
||||||
|
key: ${{ runner.os }}-${{ matrix.ghc }}-stack
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
stack build --system-ghc --stack-yaml stack-ghc${{ matrix.ghc }}.yaml
|
||||||
|
# stack build --system-ghc --test --bench --no-run-tests --no-run-benchmarks
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
run: |
|
||||||
|
stack test --system-ghc --stack-yaml stack-ghc${{ matrix.ghc }}.yaml
|
||||||
190
.github/workflows/build-binary-packages.yml
vendored
Normal file
190
.github/workflows/build-binary-packages.yml
vendored
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
name: Build Binary Packages
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
release:
|
||||||
|
types: ["created"]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
# ---
|
||||||
|
|
||||||
|
ubuntu:
|
||||||
|
name: Build Ubuntu package
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os:
|
||||||
|
- ubuntu-18.04
|
||||||
|
- ubuntu-20.04
|
||||||
|
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
# Note: `haskell-platform` is listed as requirement in debian/control,
|
||||||
|
# which is why it's installed using apt instead of the Setup Haskell action.
|
||||||
|
|
||||||
|
# - name: Setup Haskell
|
||||||
|
# uses: actions/setup-haskell@v1
|
||||||
|
# id: setup-haskell-cabal
|
||||||
|
# with:
|
||||||
|
# ghc-version: ${{ matrix.ghc }}
|
||||||
|
# cabal-version: ${{ matrix.cabal }}
|
||||||
|
|
||||||
|
- name: Install build tools
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y \
|
||||||
|
make \
|
||||||
|
dpkg-dev \
|
||||||
|
debhelper \
|
||||||
|
haskell-platform \
|
||||||
|
libghc-json-dev \
|
||||||
|
python-dev \
|
||||||
|
default-jdk \
|
||||||
|
libtool-bin
|
||||||
|
|
||||||
|
- name: Build package
|
||||||
|
run: |
|
||||||
|
make deb
|
||||||
|
|
||||||
|
- name: Copy package
|
||||||
|
run: |
|
||||||
|
cp ../gf_*.deb dist/
|
||||||
|
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: gf-${{ github.sha }}-${{ matrix.os }}
|
||||||
|
path: dist/gf_*.deb
|
||||||
|
if-no-files-found: error
|
||||||
|
|
||||||
|
# ---
|
||||||
|
|
||||||
|
macos:
|
||||||
|
name: Build macOS package
|
||||||
|
runs-on: macos-10.15
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
ghc: ["8.6.5"]
|
||||||
|
cabal: ["2.4"]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Setup Haskell
|
||||||
|
uses: actions/setup-haskell@v1
|
||||||
|
id: setup-haskell-cabal
|
||||||
|
with:
|
||||||
|
ghc-version: ${{ matrix.ghc }}
|
||||||
|
cabal-version: ${{ matrix.cabal }}
|
||||||
|
|
||||||
|
- name: Install build tools
|
||||||
|
run: |
|
||||||
|
brew install \
|
||||||
|
automake
|
||||||
|
cabal v1-install alex happy
|
||||||
|
|
||||||
|
- name: Build package
|
||||||
|
run: |
|
||||||
|
sudo mkdir -p /Library/Java/Home
|
||||||
|
sudo ln -s /usr/local/opt/openjdk/include /Library/Java/Home/include
|
||||||
|
make pkg
|
||||||
|
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: gf-${{ github.sha }}-macos
|
||||||
|
path: dist/gf-*.pkg
|
||||||
|
if-no-files-found: error
|
||||||
|
|
||||||
|
# ---
|
||||||
|
|
||||||
|
windows:
|
||||||
|
name: Build Windows package
|
||||||
|
runs-on: windows-2019
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
ghc: ["8.6.5"]
|
||||||
|
cabal: ["2.4"]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Setup MSYS2
|
||||||
|
uses: msys2/setup-msys2@v2
|
||||||
|
with:
|
||||||
|
install: >-
|
||||||
|
base-devel
|
||||||
|
gcc
|
||||||
|
python-devel
|
||||||
|
|
||||||
|
- name: Prepare dist folder
|
||||||
|
shell: msys2 {0}
|
||||||
|
run: |
|
||||||
|
mkdir /c/tmp-dist
|
||||||
|
mkdir /c/tmp-dist/c
|
||||||
|
mkdir /c/tmp-dist/java
|
||||||
|
mkdir /c/tmp-dist/python
|
||||||
|
|
||||||
|
- name: Build C runtime
|
||||||
|
shell: msys2 {0}
|
||||||
|
run: |
|
||||||
|
cd src/runtime/c
|
||||||
|
autoreconf -i
|
||||||
|
./configure
|
||||||
|
make
|
||||||
|
make install
|
||||||
|
cp /mingw64/bin/libpgf-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
|
||||||
|
shell: msys2 {0}
|
||||||
|
run: |
|
||||||
|
export JDKPATH=/c/hostedtoolcache/windows/Java_Adopt_jdk/8.0.292-10/x64
|
||||||
|
export PATH="${PATH}:${JDKPATH}/bin"
|
||||||
|
cd src/runtime/java
|
||||||
|
make \
|
||||||
|
JNI_INCLUDES="-I \"${JDKPATH}/include\" -I \"${JDKPATH}/include/win32\" -I \"/mingw64/include\" -D__int64=int64_t" \
|
||||||
|
WINDOWS_LDFLAGS="-L\"/mingw64/lib\" -no-undefined"
|
||||||
|
make install
|
||||||
|
cp .libs/msys-jpgf-0.dll /c/tmp-dist/java/jpgf.dll
|
||||||
|
cp jpgf.jar /c/tmp-dist/java
|
||||||
|
|
||||||
|
- name: Build Python bindings
|
||||||
|
shell: msys2 {0}
|
||||||
|
env:
|
||||||
|
EXTRA_INCLUDE_DIRS: /mingw64/include
|
||||||
|
EXTRA_LIB_DIRS: /mingw64/lib
|
||||||
|
run: |
|
||||||
|
cd src/runtime/python
|
||||||
|
python setup.py build
|
||||||
|
python setup.py install
|
||||||
|
cp /usr/lib/python3.9/site-packages/pgf* /c/tmp-dist/python
|
||||||
|
|
||||||
|
- name: Setup Haskell
|
||||||
|
uses: actions/setup-haskell@v1
|
||||||
|
id: setup-haskell-cabal
|
||||||
|
with:
|
||||||
|
ghc-version: ${{ matrix.ghc }}
|
||||||
|
cabal-version: ${{ matrix.cabal }}
|
||||||
|
|
||||||
|
- name: Install Haskell build tools
|
||||||
|
run: |
|
||||||
|
cabal install alex happy
|
||||||
|
|
||||||
|
- name: Build GF
|
||||||
|
run: |
|
||||||
|
cabal install --only-dependencies -fserver
|
||||||
|
cabal configure -fserver
|
||||||
|
cabal build
|
||||||
|
copy dist\build\gf\gf.exe C:\tmp-dist
|
||||||
|
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: gf-${{ github.sha }}-windows
|
||||||
|
path: C:\tmp-dist\*
|
||||||
|
if-no-files-found: error
|
||||||
98
.github/workflows/build-python-package.yml
vendored
Normal file
98
.github/workflows/build-python-package.yml
vendored
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
name: Build & Publish Python Package
|
||||||
|
|
||||||
|
# Trigger the workflow on push or pull request, but only for the master branch
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
push:
|
||||||
|
branches: [master]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build_wheels:
|
||||||
|
name: Build wheel on ${{ matrix.os }}
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: true
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-18.04, macos-10.15]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v1
|
||||||
|
|
||||||
|
- uses: actions/setup-python@v1
|
||||||
|
name: Install Python
|
||||||
|
with:
|
||||||
|
python-version: '3.7'
|
||||||
|
|
||||||
|
- name: Install cibuildwheel
|
||||||
|
run: |
|
||||||
|
python -m pip install git+https://github.com/joerick/cibuildwheel.git@main
|
||||||
|
|
||||||
|
- name: Install build tools for OSX
|
||||||
|
if: startsWith(matrix.os, 'macos')
|
||||||
|
run: |
|
||||||
|
brew install automake
|
||||||
|
|
||||||
|
- name: Build wheels on Linux
|
||||||
|
if: startsWith(matrix.os, 'macos') != true
|
||||||
|
env:
|
||||||
|
CIBW_BEFORE_BUILD: cd src/runtime/c && autoreconf -i && ./configure && make && make install
|
||||||
|
run: |
|
||||||
|
python -m cibuildwheel src/runtime/python --output-dir wheelhouse
|
||||||
|
|
||||||
|
- name: Build wheels on OSX
|
||||||
|
if: startsWith(matrix.os, 'macos')
|
||||||
|
env:
|
||||||
|
CIBW_BEFORE_BUILD: cd src/runtime/c && glibtoolize && autoreconf -i && ./configure && make && make install
|
||||||
|
run: |
|
||||||
|
python -m cibuildwheel src/runtime/python --output-dir wheelhouse
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
path: ./wheelhouse
|
||||||
|
|
||||||
|
build_sdist:
|
||||||
|
name: Build source distribution
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- uses: actions/setup-python@v2
|
||||||
|
name: Install Python
|
||||||
|
with:
|
||||||
|
python-version: '3.7'
|
||||||
|
|
||||||
|
- name: Build sdist
|
||||||
|
run: cd src/runtime/python && python setup.py sdist
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
path: ./src/runtime/python/dist/*.tar.gz
|
||||||
|
|
||||||
|
upload_pypi:
|
||||||
|
name: Upload to PyPI
|
||||||
|
needs: [build_wheels, build_sdist]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.ref == 'refs/heads/master' && github.event_name == 'push'
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Set up Python
|
||||||
|
uses: actions/setup-python@v2
|
||||||
|
with:
|
||||||
|
python-version: '3.x'
|
||||||
|
|
||||||
|
- name: Install twine
|
||||||
|
run: pip install twine
|
||||||
|
|
||||||
|
- uses: actions/download-artifact@v2
|
||||||
|
with:
|
||||||
|
name: artifact
|
||||||
|
path: ./dist
|
||||||
|
|
||||||
|
- name: Publish
|
||||||
|
env:
|
||||||
|
TWINE_USERNAME: __token__
|
||||||
|
TWINE_PASSWORD: ${{ secrets.pypi_password }}
|
||||||
|
run: |
|
||||||
|
(cd ./src/runtime/python && curl -I --fail https://pypi.org/project/$(python setup.py --name)/$(python setup.py --version)/) || twine upload dist/*
|
||||||
11
.gitignore
vendored
11
.gitignore
vendored
@@ -5,7 +5,14 @@
|
|||||||
*.jar
|
*.jar
|
||||||
*.gfo
|
*.gfo
|
||||||
*.pgf
|
*.pgf
|
||||||
|
debian/.debhelper
|
||||||
|
debian/debhelper-build-stamp
|
||||||
|
debian/gf
|
||||||
|
debian/gf.debhelper.log
|
||||||
|
debian/gf.substvars
|
||||||
|
debian/files
|
||||||
dist/
|
dist/
|
||||||
|
dist-newstyle/
|
||||||
src/runtime/c/.libs/
|
src/runtime/c/.libs/
|
||||||
src/runtime/c/Makefile
|
src/runtime/c/Makefile
|
||||||
src/runtime/c/Makefile.in
|
src/runtime/c/Makefile.in
|
||||||
@@ -46,6 +53,10 @@ DATA_DIR
|
|||||||
|
|
||||||
stack*.yaml.lock
|
stack*.yaml.lock
|
||||||
|
|
||||||
|
# Output files for test suite
|
||||||
|
*.out
|
||||||
|
gf-tests.html
|
||||||
|
|
||||||
# Generated documentation (not exhaustive)
|
# Generated documentation (not exhaustive)
|
||||||
demos/index-numbers.html
|
demos/index-numbers.html
|
||||||
demos/resourcegrammars.html
|
demos/resourcegrammars.html
|
||||||
|
|||||||
41
Makefile
41
Makefile
@@ -1,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
|
||||||
|
|
||||||
|
|||||||
11
README.md
11
README.md
@@ -2,8 +2,6 @@
|
|||||||
|
|
||||||
# Grammatical Framework (GF)
|
# Grammatical Framework (GF)
|
||||||
|
|
||||||
[](https://travis-ci.org/GrammaticalFramework/gf-core)
|
|
||||||
|
|
||||||
The Grammatical Framework is a grammar formalism based on type theory.
|
The Grammatical Framework is a grammar formalism based on type theory.
|
||||||
It consists of:
|
It consists of:
|
||||||
|
|
||||||
@@ -32,13 +30,16 @@ GF particularly addresses four aspects of grammars:
|
|||||||
|
|
||||||
## Compilation and installation
|
## Compilation and installation
|
||||||
|
|
||||||
The simplest way of installing GF is with the command:
|
The simplest way of installing GF from source is with the command:
|
||||||
```
|
```
|
||||||
cabal install
|
cabal install
|
||||||
```
|
```
|
||||||
|
or:
|
||||||
|
```
|
||||||
|
stack install
|
||||||
|
```
|
||||||
|
|
||||||
For more details, see the [download page](http://www.grammaticalframework.org/download/index.html)
|
For more information, including links to precompiled binaries, see the [download page](http://www.grammaticalframework.org/download/index.html).
|
||||||
and [developers manual](http://www.grammaticalframework.org/doc/gf-developers.html).
|
|
||||||
|
|
||||||
## About this repository
|
## About this repository
|
||||||
|
|
||||||
|
|||||||
66
RELEASE.md
Normal file
66
RELEASE.md
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
# GF Core releases
|
||||||
|
|
||||||
|
**Note:**
|
||||||
|
The RGL is now released completely separately from GF Core.
|
||||||
|
See the [RGL's RELEASE.md](https://github.com/GrammaticalFramework/gf-rgl/blob/master/RELEASE.md).
|
||||||
|
|
||||||
|
## Creating a new release
|
||||||
|
|
||||||
|
### 1. Prepare the repository
|
||||||
|
|
||||||
|
**Web pages**
|
||||||
|
|
||||||
|
1. Create `download/index-X.Y.md` with installation instructions.
|
||||||
|
2. Create `download/release-X.Y.md` with changelog information.
|
||||||
|
3. Update `download/index.html` to redirect to the new version.
|
||||||
|
4. Add announcement in news section in `index.html`.
|
||||||
|
|
||||||
|
**Version numbers**
|
||||||
|
|
||||||
|
1. Update version number in `gf.cabal` (ommitting `-git` suffix).
|
||||||
|
2. Add a new line in `debian/changelog`.
|
||||||
|
|
||||||
|
### 2. Create GitHub release
|
||||||
|
|
||||||
|
1. When the above changes are committed to the `master` branch in the repository
|
||||||
|
and pushed, check that all CI workflows are successful (fixing as necessary):
|
||||||
|
- <https://github.com/GrammaticalFramework/gf-core/actions>
|
||||||
|
- <https://travis-ci.org/github/GrammaticalFramework/gf-core>
|
||||||
|
2. Create a GitHub release [here](https://github.com/GrammaticalFramework/gf-core/releases/new):
|
||||||
|
- Tag version format `RELEASE-X.Y`
|
||||||
|
- Title: "GF X.Y"
|
||||||
|
- Description: mention major changes since last release
|
||||||
|
3. Publish the release to trigger the building of the binary packages (below).
|
||||||
|
|
||||||
|
### 3. Binary packages
|
||||||
|
|
||||||
|
The binaries will be built automatically by GitHub Actions when the release is created,
|
||||||
|
but the generated _artifacts_ must be manually attached to the release as _assets_.
|
||||||
|
|
||||||
|
1. Go to the [actions page](https://github.com/GrammaticalFramework/gf-core/actions) and click "Build Binary Packages" under _Workflows_.
|
||||||
|
2. Choose the workflow run corresponding to the newly created release.
|
||||||
|
3. Download the artifacts locally. Extract the Ubuntu and macOS ones to get the `.deb` and `.pkg` files.
|
||||||
|
4. Go back to the [releases page](https://github.com/GrammaticalFramework/gf-core/releases) and click to edit the release information.
|
||||||
|
5. Add the downloaded artifacts as release assets, giving them names with format `gf-X.Y-PLATFORM.EXT` (e.g. `gf-3.11-macos.pkg`).
|
||||||
|
|
||||||
|
### 4. Upload to Hackage
|
||||||
|
|
||||||
|
In order to do this you will need to be added the [GF maintainers](https://hackage.haskell.org/package/gf/maintainers/) on Hackage.
|
||||||
|
|
||||||
|
1. Run `make sdist`
|
||||||
|
2. Upload the package, either:
|
||||||
|
1. **Manually**: visit <https://hackage.haskell.org/upload> and upload the file `dist/gf-X.Y.tar.gz`
|
||||||
|
2. **via Cabal (≥2.4)**: `cabal upload dist/gf-X.Y.tar.gz`
|
||||||
|
3. If the documentation-building fails on the Hackage server, do:
|
||||||
|
```
|
||||||
|
cabal v2-haddock --builddir=dist/docs --haddock-for-hackage --enable-doc
|
||||||
|
cabal upload --documentation dist/docs/*-docs.tar.gz
|
||||||
|
```
|
||||||
|
|
||||||
|
## Miscellaneous
|
||||||
|
|
||||||
|
### What is the tag `GF-3.10`?
|
||||||
|
|
||||||
|
For GF 3.10, the Core and RGL repositories had already been separated, however
|
||||||
|
the binary packages still included the RGL. `GF-3.10` is a tag that was created
|
||||||
|
in both repositories ([gf-core](https://github.com/GrammaticalFramework/gf-core/releases/tag/GF-3.10) and [gf-rgl](https://github.com/GrammaticalFramework/gf-rgl/releases/tag/GF-3.10)) to indicate which versions of each went into the binaries.
|
||||||
7
Setup.hs
7
Setup.hs
@@ -19,7 +19,6 @@ main = defaultMainWithHooks simpleUserHooks
|
|||||||
, preInst = gfPreInst
|
, preInst = gfPreInst
|
||||||
, postInst = gfPostInst
|
, postInst = gfPostInst
|
||||||
, postCopy = gfPostCopy
|
, postCopy = gfPostCopy
|
||||||
, sDistHook = gfSDist
|
|
||||||
}
|
}
|
||||||
where
|
where
|
||||||
gfPreBuild args = gfPre args . buildDistPref
|
gfPreBuild args = gfPre args . buildDistPref
|
||||||
@@ -29,17 +28,17 @@ main = defaultMainWithHooks simpleUserHooks
|
|||||||
return emptyHookedBuildInfo
|
return emptyHookedBuildInfo
|
||||||
|
|
||||||
gfPostBuild args flags pkg lbi = do
|
gfPostBuild args flags pkg lbi = do
|
||||||
noRGLmsg
|
-- noRGLmsg
|
||||||
let gf = default_gf lbi
|
let gf = default_gf lbi
|
||||||
buildWeb gf flags (pkg,lbi)
|
buildWeb gf flags (pkg,lbi)
|
||||||
|
|
||||||
gfPostInst args flags pkg lbi = do
|
gfPostInst args flags pkg lbi = do
|
||||||
noRGLmsg
|
-- noRGLmsg
|
||||||
saveInstallPath args flags (pkg,lbi)
|
saveInstallPath args flags (pkg,lbi)
|
||||||
installWeb (pkg,lbi)
|
installWeb (pkg,lbi)
|
||||||
|
|
||||||
gfPostCopy args flags pkg lbi = do
|
gfPostCopy args flags pkg lbi = do
|
||||||
noRGLmsg
|
-- noRGLmsg
|
||||||
saveCopyPath args flags (pkg,lbi)
|
saveCopyPath args flags (pkg,lbi)
|
||||||
copyWeb flags (pkg,lbi)
|
copyWeb flags (pkg,lbi)
|
||||||
|
|
||||||
|
|||||||
15
WebSetup.hs
15
WebSetup.hs
@@ -26,6 +26,14 @@ import Distribution.PackageDescription(PackageDescription(..))
|
|||||||
so users won't see this message unless they check the log.)
|
so users won't see this message unless they check the log.)
|
||||||
-}
|
-}
|
||||||
|
|
||||||
|
-- | Notice about contrib grammars
|
||||||
|
noContribMsg :: IO ()
|
||||||
|
noContribMsg = putStr $ unlines
|
||||||
|
[ "Example grammars are no longer included in the main GF repository, but have moved to gf-contrib."
|
||||||
|
, "If you want them to be built, clone the following repository in the same directory as gf-core:"
|
||||||
|
, "https://github.com/GrammaticalFramework/gf-contrib.git"
|
||||||
|
]
|
||||||
|
|
||||||
example_grammars :: [(String, String, [String])] -- [(pgf, subdir, source modules)]
|
example_grammars :: [(String, String, [String])] -- [(pgf, subdir, source modules)]
|
||||||
example_grammars =
|
example_grammars =
|
||||||
[("Letter.pgf","letter",letterSrc)
|
[("Letter.pgf","letter",letterSrc)
|
||||||
@@ -50,11 +58,8 @@ buildWeb gf flags (pkg,lbi) = do
|
|||||||
contrib_exists <- doesDirectoryExist contrib_dir
|
contrib_exists <- doesDirectoryExist contrib_dir
|
||||||
if contrib_exists
|
if contrib_exists
|
||||||
then mapM_ build_pgf example_grammars
|
then mapM_ build_pgf example_grammars
|
||||||
else putStr $ unlines
|
-- else noContribMsg
|
||||||
[ "Example grammars are no longer included in the main GF repository, but have moved to gf-contrib."
|
else return ()
|
||||||
, "If you want these example grammars to be built, clone this repository in the same top-level directory as GF:"
|
|
||||||
, "https://github.com/GrammaticalFramework/gf-contrib.git"
|
|
||||||
]
|
|
||||||
where
|
where
|
||||||
gfo_dir = buildDir lbi </> "examples"
|
gfo_dir = buildDir lbi </> "examples"
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,18 @@
|
|||||||
#! /bin/bash
|
#! /bin/bash
|
||||||
|
|
||||||
### This script builds a binary distribution of GF from the source
|
### This script builds a binary distribution of GF from source.
|
||||||
### package that this script is a part of. It assumes that you have installed
|
### It assumes that you have Haskell and Cabal installed.
|
||||||
### a recent version of the Haskell Platform.
|
### Two binary package formats are supported (specified with the FMT env var):
|
||||||
### Two binary package formats are supported: plain tar files (.tar.gz) and
|
### - plain tar files (.tar.gz)
|
||||||
### OS X Installer packages (.pkg).
|
### - macOS installer packages (.pkg)
|
||||||
|
|
||||||
os=$(uname) # Operating system name (e.g. Darwin or Linux)
|
os=$(uname) # Operating system name (e.g. Darwin or Linux)
|
||||||
hw=$(uname -m) # Hardware name (e.g. i686 or x86_64)
|
hw=$(uname -m) # Hardware name (e.g. i686 or x86_64)
|
||||||
|
|
||||||
# GF version number:
|
cabal="cabal v1-" # Cabal >= 2.4
|
||||||
|
# cabal="cabal " # Cabal <= 2.2
|
||||||
|
|
||||||
|
## Get GF version number from Cabal file
|
||||||
ver=$(grep -i ^version: gf.cabal | sed -e 's/version://' -e 's/ //g')
|
ver=$(grep -i ^version: gf.cabal | sed -e 's/version://' -e 's/ //g')
|
||||||
|
|
||||||
name="gf-$ver"
|
name="gf-$ver"
|
||||||
@@ -29,6 +32,7 @@ set -x # print commands before executing them
|
|||||||
pushd src/runtime/c
|
pushd src/runtime/c
|
||||||
bash setup.sh configure --prefix="$prefix"
|
bash setup.sh configure --prefix="$prefix"
|
||||||
bash setup.sh build
|
bash setup.sh build
|
||||||
|
bash setup.sh install prefix="$prefix" # hack required for GF build on macOS
|
||||||
bash setup.sh install prefix="$destdir$prefix"
|
bash setup.sh install prefix="$destdir$prefix"
|
||||||
popd
|
popd
|
||||||
|
|
||||||
@@ -38,7 +42,7 @@ if which >/dev/null python; then
|
|||||||
EXTRA_INCLUDE_DIRS="$extrainclude" EXTRA_LIB_DIRS="$extralib" python setup.py build
|
EXTRA_INCLUDE_DIRS="$extrainclude" EXTRA_LIB_DIRS="$extralib" python setup.py build
|
||||||
python setup.py install --prefix="$destdir$prefix"
|
python setup.py install --prefix="$destdir$prefix"
|
||||||
if [ "$fmt" == pkg ] ; then
|
if [ "$fmt" == pkg ] ; then
|
||||||
# A hack for Python on OS X to find the PGF modules
|
# A hack for Python on macOS to find the PGF modules
|
||||||
pyver=$(ls "$destdir$prefix/lib" | sed -n 's/^python//p')
|
pyver=$(ls "$destdir$prefix/lib" | sed -n 's/^python//p')
|
||||||
pydest="$destdir/Library/Python/$pyver/site-packages"
|
pydest="$destdir/Library/Python/$pyver/site-packages"
|
||||||
mkdir -p "$pydest"
|
mkdir -p "$pydest"
|
||||||
@@ -53,47 +57,36 @@ fi
|
|||||||
if which >/dev/null javac && which >/dev/null jar ; then
|
if which >/dev/null javac && which >/dev/null jar ; then
|
||||||
pushd src/runtime/java
|
pushd src/runtime/java
|
||||||
rm -f libjpgf.la # In case it contains the wrong INSTALL_PATH
|
rm -f libjpgf.la # In case it contains the wrong INSTALL_PATH
|
||||||
if make CFLAGS="-I$extrainclude -L$extralib" INSTALL_PATH="$prefix/lib"
|
if make CFLAGS="-I$extrainclude -L$extralib" INSTALL_PATH="$prefix"
|
||||||
then
|
then
|
||||||
make INSTALL_PATH="$destdir$prefix/lib" install
|
make INSTALL_PATH="$destdir$prefix" install
|
||||||
else
|
else
|
||||||
echo "*** Skipping the Java binding because of errors"
|
echo "Skipping the Java binding because of errors"
|
||||||
fi
|
fi
|
||||||
popd
|
popd
|
||||||
else
|
else
|
||||||
echo "Java SDK is not installed, so the Java binding will not be included"
|
echo "Java SDK is not installed, so the Java binding will not be included"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
## To find dynamic C run-time libraries when building GF below
|
||||||
|
export DYLD_LIBRARY_PATH="$extralib" LD_LIBRARY_PATH="$extralib"
|
||||||
|
|
||||||
## Build GF, with C run-time support enabled
|
## Build GF, with C run-time support enabled
|
||||||
cabal install -w "$ghc" --only-dependencies -fserver -fc-runtime $extra
|
${cabal}install -w "$ghc" --only-dependencies -fserver -fc-runtime $extra
|
||||||
cabal configure -w "$ghc" --prefix="$prefix" -fserver -fc-runtime $extra
|
${cabal}configure -w "$ghc" --prefix="$prefix" -fserver -fc-runtime $extra
|
||||||
DYLD_LIBRARY_PATH="$extralib" LD_LIBRARY_PATH="$extralib" cabal build
|
${cabal}build
|
||||||
# Building the example grammars will fail, because the RGL is missing
|
|
||||||
cabal copy --destdir="$destdir" # create www directory
|
|
||||||
|
|
||||||
## Build the RGL and copy it to $destdir
|
|
||||||
PATH=$PWD/dist/build/gf:$PATH
|
|
||||||
export GF_LIB_PATH="$(dirname $(find "$destdir" -name www))/lib" # hmm
|
|
||||||
mkdir -p "$GF_LIB_PATH"
|
|
||||||
pushd ../gf-rgl
|
|
||||||
make build
|
|
||||||
make copy
|
|
||||||
popd
|
|
||||||
|
|
||||||
# Build GF again, including example grammars that need the RGL
|
|
||||||
DYLD_LIBRARY_PATH="$extralib" LD_LIBRARY_PATH="$extralib" cabal build
|
|
||||||
|
|
||||||
## Copy GF to $destdir
|
## Copy GF to $destdir
|
||||||
cabal copy --destdir="$destdir"
|
${cabal}copy --destdir="$destdir"
|
||||||
libdir=$(dirname $(find "$destdir" -name PGF.hi))
|
libdir=$(dirname $(find "$destdir" -name PGF.hi))
|
||||||
cabal register --gen-pkg-config=$libdir/gf-$ver.conf
|
${cabal}register --gen-pkg-config="$libdir/gf-$ver.conf"
|
||||||
|
|
||||||
## Create the binary distribution package
|
## Create the binary distribution package
|
||||||
case $fmt in
|
case $fmt in
|
||||||
tar.gz)
|
tar.gz)
|
||||||
targz="$name-bin-$hw-$os.tar.gz" # the final tar file
|
targz="$name-bin-$hw-$os.tar.gz" # the final tar file
|
||||||
tar -C "$destdir/$prefix" -zcf "dist/$targz" .
|
tar --directory "$destdir/$prefix" --gzip --create --file "dist/$targz" .
|
||||||
echo "Created $targz, consider renaming it to something more user friendly"
|
echo "Created $targz"
|
||||||
;;
|
;;
|
||||||
pkg)
|
pkg)
|
||||||
pkg=$name.pkg
|
pkg=$name.pkg
|
||||||
@@ -101,4 +94,5 @@ case $fmt in
|
|||||||
echo "Created $pkg"
|
echo "Created $pkg"
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
## Cleanup
|
||||||
rm -r "$destdir"
|
rm -r "$destdir"
|
||||||
|
|||||||
@@ -82,9 +82,10 @@ $body$
|
|||||||
<li><a href="http://cloud.grammaticalframework.org/">GF Cloud</a></li>
|
<li><a href="http://cloud.grammaticalframework.org/">GF Cloud</a></li>
|
||||||
<li>
|
<li>
|
||||||
<a href="$rel-root$/doc/tutorial/gf-tutorial.html">Tutorial</a>
|
<a href="$rel-root$/doc/tutorial/gf-tutorial.html">Tutorial</a>
|
||||||
/
|
·
|
||||||
<a href="$rel-root$/lib/doc/rgl-tutorial/index.html">RGL Tutorial</a>
|
<a href="$rel-root$/lib/doc/rgl-tutorial/index.html">RGL Tutorial</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li><a href="$rel-root$/doc/gf-video-tutorials.html">Video Tutorials</a></li>
|
||||||
<li><a href="$rel-root$/download"><strong>Download GF</strong></a></li>
|
<li><a href="$rel-root$/download"><strong>Download GF</strong></a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ else
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
find . -name '*.md' | while read file ; do
|
find . -name '*.md' | while read file ; do
|
||||||
if [[ "$file" == *"README.md" ]] ; then continue ; fi
|
if [[ "$file" == *"README.md" ]] || [[ "$file" == *"RELEASE.md" ]] ; then continue ; fi
|
||||||
html="${file%.md}.html"
|
html="${file%.md}.html"
|
||||||
if [ "$file" -nt "$html" ] || [ "$template" -nt "$html" ] ; then
|
if [ "$file" -nt "$html" ] || [ "$template" -nt "$html" ] ; then
|
||||||
render_md_html "$file" "$html"
|
render_md_html "$file" "$html"
|
||||||
|
|||||||
6
debian/changelog
vendored
6
debian/changelog
vendored
@@ -1,3 +1,9 @@
|
|||||||
|
gf (3.10.4-1) xenial bionic cosmic; urgency=low
|
||||||
|
|
||||||
|
* GF 3.10.4
|
||||||
|
|
||||||
|
-- Thomas Hallgren <hallgren@chalmers.se> Fri, 18 Nov 2019 15:00:00 +0100
|
||||||
|
|
||||||
gf (3.10.3-1) xenial bionic cosmic; urgency=low
|
gf (3.10.3-1) xenial bionic cosmic; urgency=low
|
||||||
|
|
||||||
* GF 3.10.3
|
* GF 3.10.3
|
||||||
|
|||||||
2
debian/control
vendored
2
debian/control
vendored
@@ -3,7 +3,7 @@ Section: devel
|
|||||||
Priority: optional
|
Priority: optional
|
||||||
Maintainer: Thomas Hallgren <hallgren@chalmers.se>
|
Maintainer: Thomas Hallgren <hallgren@chalmers.se>
|
||||||
Standards-Version: 3.9.2
|
Standards-Version: 3.9.2
|
||||||
Build-Depends: debhelper (>= 5), haskell-platform (>= 2011.2.0.1), libghc-haskeline-dev, libghc-mtl-dev, libghc-json-dev, autoconf, automake, libtool-bin, python-dev, java-sdk, txt2tags, pandoc
|
Build-Depends: debhelper (>= 5), haskell-platform (>= 2011.2.0.1), libghc-haskeline-dev, libghc-mtl-dev, libghc-json-dev, autoconf, automake, libtool-bin, python-dev, java-sdk
|
||||||
Homepage: http://www.grammaticalframework.org/
|
Homepage: http://www.grammaticalframework.org/
|
||||||
|
|
||||||
Package: gf
|
Package: gf
|
||||||
|
|||||||
18
debian/rules
vendored
18
debian/rules
vendored
@@ -16,27 +16,23 @@ 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
|
||||||
|
|
||||||
override_dh_auto_build:
|
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/lib
|
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 # builds gf, fails to build example grammars
|
-$(SET_LDL) cabal v1-build
|
||||||
export $(SET_LDL); PATH=$(CURDIR)/dist/build/gf:$$PATH && make -C ../gf-rgl build
|
|
||||||
GF_LIB_PATH=$(CURDIR)/../gf-rgl/dist $(SET_LDL) cabal build # have RGL now, ok to build example grammars
|
|
||||||
make html
|
|
||||||
|
|
||||||
override_dh_auto_install:
|
override_dh_auto_install:
|
||||||
$(SET_LDL) cabal copy --destdir=$(CURDIR)/debian/gf # creates www directory
|
$(SET_LDL) cabal v1-copy --destdir=$(CURDIR)/debian/gf
|
||||||
export GF_LIB_PATH="$$(dirname $$(find "$(CURDIR)/debian/gf" -name www))/lib" && echo "GF_LIB_PATH=$$GF_LIB_PATH" && mkdir -p "$$GF_LIB_PATH" && make -C ../gf-rgl copy
|
|
||||||
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/lib install
|
cd src/runtime/java && make INSTALL_PATH=$(CURDIR)/debian/gf/usr install
|
||||||
D="`find debian/gf -name site-packages`" && [ -n "$$D" ] && cd $$D && cd .. && mv site-packages dist-packages
|
D="`find debian/gf -name site-packages`" && [ -n "$$D" ] && cd $$D && cd .. && mv site-packages dist-packages
|
||||||
|
|
||||||
override_dh_auto_clean:
|
override_dh_auto_clean:
|
||||||
|
|||||||
27
doc/errors/gluing.md
Normal file
27
doc/errors/gluing.md
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
## unsupported token gluing `foo + bar`
|
||||||
|
|
||||||
|
There was a problem in an expression using +, e.g. `foo + bar`.
|
||||||
|
This can be due to two causes, check which one applies in your case.
|
||||||
|
|
||||||
|
1. You are trying to use + on runtime arguments. Even if you are using
|
||||||
|
`foo + bar` in an oper, make sure that the oper isn't called in a
|
||||||
|
linearization that takes arguments. Both of the following are illegal:
|
||||||
|
|
||||||
|
lin Test foo bar = foo.s + bar.s -- explicit + in a lin
|
||||||
|
lin Test foo bar = opWithPlus foo bar -- the oper uses +
|
||||||
|
|
||||||
|
2. One of the arguments in `foo + bar` is a bound variable
|
||||||
|
from pattern matching a string, but the cases are non-exhaustive.
|
||||||
|
Example:
|
||||||
|
case "test" of {
|
||||||
|
x + "a" => x + "b" -- no applicable case for "test", so x = ???
|
||||||
|
} ;
|
||||||
|
|
||||||
|
You can fix this by adding a catch-all case in the end:
|
||||||
|
{ x + "a" => x + "b" ;
|
||||||
|
_ => "default case" } ;
|
||||||
|
|
||||||
|
3. If neither applies to your problem, submit a bug report and we
|
||||||
|
will update the error message and this documentation.
|
||||||
|
|
||||||
|
https://github.com/GrammaticalFramework/gf-core/issues
|
||||||
201
doc/gf-developers-old-cabal.t2t
Normal file
201
doc/gf-developers-old-cabal.t2t
Normal 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
|
||||||
|
```
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
GF Developers Guide
|
GF Developers Guide
|
||||||
|
|
||||||
2018-07-26
|
2021-07-15
|
||||||
|
|
||||||
%!options(html): --toc
|
%!options(html): --toc
|
||||||
|
|
||||||
@@ -15,386 +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.
|
|
||||||
|
|
||||||
== 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:
|
||||||
```
|
```
|
||||||
@@ -416,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.
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ The following people have contributed code to some of the versions:
|
|||||||
- [Janna Khegai](http://www.cs.chalmers.se/~janna) (Chalmers)
|
- [Janna Khegai](http://www.cs.chalmers.se/~janna) (Chalmers)
|
||||||
- [Peter Ljunglöf](http://www.cse.chalmers.se/~peb) (University of Gothenburg)
|
- [Peter Ljunglöf](http://www.cse.chalmers.se/~peb) (University of Gothenburg)
|
||||||
- Petri Mäenpää (Nokia)
|
- Petri Mäenpää (Nokia)
|
||||||
|
- Lauri Alanko (University of Helsinki)
|
||||||
|
|
||||||
At least the following colleagues are thanked for suggestions, bug
|
At least the following colleagues are thanked for suggestions, bug
|
||||||
reports, and other indirect contributions to the code.
|
reports, and other indirect contributions to the code.
|
||||||
|
|||||||
@@ -1809,6 +1809,23 @@ As the last rule, subtyping is transitive:
|
|||||||
- if *A* is a subtype of *B* and *B* is a subtype of *C*, then *A* is
|
- if *A* is a subtype of *B* and *B* is a subtype of *C*, then *A* is
|
||||||
a subtype of *C*.
|
a subtype of *C*.
|
||||||
|
|
||||||
|
### List categories
|
||||||
|
|
||||||
|
[]{#lists}
|
||||||
|
|
||||||
|
Since categories of lists of elements of another category are a common idiom, the following syntactic sugar is available:
|
||||||
|
|
||||||
|
cat [C] {n}
|
||||||
|
|
||||||
|
abbreviates a set of three judgements:
|
||||||
|
|
||||||
|
cat ListC ;
|
||||||
|
fun BaseC : C -> ... -> C -> ListC ; --n C’s
|
||||||
|
fun ConsC : C -> ListC -> ListC
|
||||||
|
|
||||||
|
The functions `BaseC` and `ConsC` are automatically generated in the abstract syntax, but their linearizations, as well as the linearization type of `ListC`, must be defined manually. The type expression `[C]` is in all contexts interchangeable with `ListC`.
|
||||||
|
|
||||||
|
More information on lists in GF can be found [here](https://inariksit.github.io/gf/2021/02/22/lists.html).
|
||||||
|
|
||||||
### Tables and table types
|
### Tables and table types
|
||||||
|
|
||||||
@@ -2113,7 +2130,7 @@ of *x*, and the application thereby disappears.
|
|||||||
|
|
||||||
[]{#reuse}
|
[]{#reuse}
|
||||||
|
|
||||||
*This section is valid for GF 3.0, which abandons the \"lock field\"*
|
*This section is valid for GF 3.0, which abandons the \"[lock field](https://inariksit.github.io/gf/2018/05/25/subtyping-gf.html#lock-fields)\"*
|
||||||
*discipline of GF 2.8.*
|
*discipline of GF 2.8.*
|
||||||
|
|
||||||
As explained [here](#openabstract), abstract syntax modules can be
|
As explained [here](#openabstract), abstract syntax modules can be
|
||||||
|
|||||||
35
doc/gf-video-tutorials.md
Normal file
35
doc/gf-video-tutorials.md
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
---
|
||||||
|
title: "Video tutorials"
|
||||||
|
---
|
||||||
|
|
||||||
|
The GF [YouTube channel](https://www.youtube.com/channel/UCZ96DechSUVcXAhtOId9VVA) keeps a playlist of [all GF videos](https://www.youtube.com/playlist?list=PLrgqBB5thLeT15fUtJ8_Dtk8ppdtH90MK), and more specific playlists for narrower topics.
|
||||||
|
If you make a video about GF, let us know and we'll add it to the suitable playlist(s)!
|
||||||
|
|
||||||
|
- [General introduction to GF](#general-introduction-to-gf)
|
||||||
|
- [Beginner resources](#beginner-resources)
|
||||||
|
- [Resource grammar tutorials](#resource-grammar-tutorials)
|
||||||
|
|
||||||
|
## General introduction to GF
|
||||||
|
|
||||||
|
These videos introduce GF at a high level, and present some use cases.
|
||||||
|
|
||||||
|
__Grammatical Framework: Formalizing the Grammars of the World__
|
||||||
|
|
||||||
|
<iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/x1LFbDQhbso" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
|
||||||
|
|
||||||
|
__Aarne Ranta: Automatic Translation for Consumers and Producers__
|
||||||
|
|
||||||
|
<iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/An-AmFScw1o" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
|
||||||
|
|
||||||
|
## Beginner resources
|
||||||
|
|
||||||
|
These videos show how to install GF on your computer (Mac or Windows), and how to play with simple grammars in a [Jupyter notebook](https://github.com/GrammaticalFramework/gf-binder) (any platform, hosted at [mybinder.org](https://mybinder.org)).
|
||||||
|
|
||||||
|
<iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/videoseries?list=PLrgqBB5thLeRa8eViJJnjT8jBhxqCPMF2" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
|
||||||
|
|
||||||
|
## Resource grammar tutorials
|
||||||
|
|
||||||
|
These videos show incremental improvements to a [miniature version of the resource grammar](https://github.com/inariksit/comp-syntax-2020/tree/master/lab2/grammar/dummy#readme).
|
||||||
|
They assume some prior knowledge of GF, roughly lessons 1-3 from the [GF tutorial](http://www.grammaticalframework.org/doc/tutorial/gf-tutorial.html).
|
||||||
|
|
||||||
|
<iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/videoseries?list=PLrgqBB5thLeTPkp88lnOmRtprCa8g0wX2" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
|
||||||
@@ -898,7 +898,7 @@ Parentheses are only needed for grouping.
|
|||||||
Parsing something that is not in grammar will fail:
|
Parsing something that is not in grammar will fail:
|
||||||
```
|
```
|
||||||
> parse "hello dad"
|
> parse "hello dad"
|
||||||
Unknown words: dad
|
The parser failed at token 2: "dad"
|
||||||
|
|
||||||
> parse "world hello"
|
> parse "world hello"
|
||||||
no tree found
|
no tree found
|
||||||
@@ -2475,7 +2475,7 @@ can be used to read a text and return for each word its analyses
|
|||||||
```
|
```
|
||||||
The command ``morpho_quiz = mq`` generates inflection exercises.
|
The command ``morpho_quiz = mq`` generates inflection exercises.
|
||||||
```
|
```
|
||||||
% gf -path=alltenses:prelude $GF_LIB_PATH/alltenses/IrregFre.gfo
|
% gf alltenses/IrregFre.gfo
|
||||||
|
|
||||||
> morpho_quiz -cat=V
|
> morpho_quiz -cat=V
|
||||||
|
|
||||||
@@ -2488,11 +2488,6 @@ The command ``morpho_quiz = mq`` generates inflection exercises.
|
|||||||
réapparaîtriez
|
réapparaîtriez
|
||||||
Score 0/1
|
Score 0/1
|
||||||
```
|
```
|
||||||
To create a list for later use, use the command ``morpho_list = ml``
|
|
||||||
```
|
|
||||||
> morpho_list -number=25 -cat=V | write_file exx.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -2651,12 +2646,12 @@ The verb //switch off// is called a
|
|||||||
|
|
||||||
We can define transitive verbs and their combinations as follows:
|
We can define transitive verbs and their combinations as follows:
|
||||||
```
|
```
|
||||||
lincat TV = {s : Number => Str ; part : Str} ;
|
lincat V2 = {s : Number => Str ; part : Str} ;
|
||||||
|
|
||||||
fun AppTV : Item -> TV -> Item -> Phrase ;
|
fun AppV2 : Item -> V2 -> Item -> Phrase ;
|
||||||
|
|
||||||
lin AppTV subj tv obj =
|
lin AppV2 subj v2 obj =
|
||||||
{s = subj.s ++ tv.s ! subj.n ++ obj.s ++ tv.part} ;
|
{s = subj.s ++ v2.s ! subj.n ++ obj.s ++ v2.part} ;
|
||||||
```
|
```
|
||||||
|
|
||||||
**Exercise**. Define the language ``a^n b^n c^n`` in GF, i.e.
|
**Exercise**. Define the language ``a^n b^n c^n`` in GF, i.e.
|
||||||
@@ -2722,11 +2717,11 @@ This topic will be covered in #Rseclexing.
|
|||||||
|
|
||||||
The symbol ``**`` is used for both record types and record objects.
|
The symbol ``**`` is used for both record types and record objects.
|
||||||
```
|
```
|
||||||
lincat TV = Verb ** {c : Case} ;
|
lincat V2 = Verb ** {c : Case} ;
|
||||||
|
|
||||||
lin Follow = regVerb "folgen" ** {c = Dative} ;
|
lin Follow = regVerb "folgen" ** {c = Dative} ;
|
||||||
```
|
```
|
||||||
``TV`` becomes a **subtype** of ``Verb``.
|
``V2`` (transitive verb) becomes a **subtype** of ``Verb``.
|
||||||
|
|
||||||
If //T// is a subtype of //R//, an object of //T// can be used whenever
|
If //T// is a subtype of //R//, an object of //T// can be used whenever
|
||||||
an object of //R// is required.
|
an object of //R// is required.
|
||||||
@@ -2757,7 +2752,11 @@ Thus the labels ``p1, p2,...`` are hard-coded.
|
|||||||
English indefinite article:
|
English indefinite article:
|
||||||
```
|
```
|
||||||
oper artIndef : Str =
|
oper artIndef : Str =
|
||||||
pre {"a" ; "an" / strs {"a" ; "e" ; "i" ; "o"}} ;
|
pre {
|
||||||
|
("a" | "e" | "i" | "o") => "an" ;
|
||||||
|
_ => "a"
|
||||||
|
} ;
|
||||||
|
|
||||||
```
|
```
|
||||||
Thus
|
Thus
|
||||||
```
|
```
|
||||||
@@ -2948,7 +2947,7 @@ We need the following combinations:
|
|||||||
```
|
```
|
||||||
We also need **lexical insertion**, to form phrases from single words:
|
We also need **lexical insertion**, to form phrases from single words:
|
||||||
```
|
```
|
||||||
mkCN : N -> NP ;
|
mkCN : N -> CN ;
|
||||||
mkAP : A -> AP ;
|
mkAP : A -> AP ;
|
||||||
```
|
```
|
||||||
Naming convention: to construct a //C//, use a function ``mk``//C//.
|
Naming convention: to construct a //C//, use a function ``mk``//C//.
|
||||||
@@ -2969,7 +2968,7 @@ can be built as follows:
|
|||||||
```
|
```
|
||||||
mkCl
|
mkCl
|
||||||
(mkNP these_Det
|
(mkNP these_Det
|
||||||
(mkCN (mkAP very_AdA (mkAP warm_A)) (mkCN pizza_CN)))
|
(mkCN (mkAP very_AdA (mkAP warm_A)) (mkCN pizza_N)))
|
||||||
(mkAP italian_AP)
|
(mkAP italian_AP)
|
||||||
```
|
```
|
||||||
The task now: to define the concrete syntax of ``Foods`` so that
|
The task now: to define the concrete syntax of ``Foods`` so that
|
||||||
@@ -3718,49 +3717,25 @@ Concrete syntax does not know if a category is a dependent type.
|
|||||||
```
|
```
|
||||||
Notice that the ``Kind`` argument is suppressed in linearization.
|
Notice that the ``Kind`` argument is suppressed in linearization.
|
||||||
|
|
||||||
Parsing with dependent types is performed in two phases:
|
Parsing with dependent types consists of two phases:
|
||||||
+ context-free parsing
|
+ context-free parsing
|
||||||
+ filtering through type checker
|
+ filtering through type checker
|
||||||
|
|
||||||
|
Parsing a type-correct command works as expected:
|
||||||
|
|
||||||
By just doing the first phase, the ``kind`` argument is not found:
|
|
||||||
```
|
```
|
||||||
> parse "dim the light"
|
> parse "dim the light"
|
||||||
CAction ? dim (DKindOne light)
|
|
||||||
```
|
|
||||||
Moreover, type-incorrect commands are not rejected:
|
|
||||||
```
|
|
||||||
> parse "dim the fan"
|
|
||||||
CAction ? dim (DKindOne fan)
|
|
||||||
```
|
|
||||||
The term ``?`` is a **metavariable**, returned by the parser
|
|
||||||
for any subtree that is suppressed by a linearization rule.
|
|
||||||
These are the same kind of metavariables as were used #Rsecediting
|
|
||||||
to mark incomplete parts of trees in the syntax editor.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#NEW
|
|
||||||
|
|
||||||
===Solving metavariables===
|
|
||||||
|
|
||||||
Use the command ``put_tree = pt`` with the option ``-typecheck``:
|
|
||||||
```
|
|
||||||
> parse "dim the light" | put_tree -typecheck
|
|
||||||
CAction light dim (DKindOne light)
|
CAction light dim (DKindOne light)
|
||||||
```
|
```
|
||||||
The ``typecheck`` process may fail, in which case an error message
|
However, type-incorrect commands are rejected by the typecheck:
|
||||||
is shown and no tree is returned:
|
|
||||||
```
|
```
|
||||||
> parse "dim the fan" | put_tree -typecheck
|
> parse "dim the fan"
|
||||||
|
The parsing is successful but the type checking failed with error(s):
|
||||||
Error in tree UCommand (CAction ? 0 dim (DKindOne fan)) :
|
Couldn't match expected type Device light
|
||||||
(? 0 <> fan) (? 0 <> light)
|
against the interred type Device fan
|
||||||
|
In the expression: DKindOne fan
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#NEW
|
#NEW
|
||||||
|
|
||||||
==Polymorphism==
|
==Polymorphism==
|
||||||
@@ -3786,23 +3761,19 @@ to express Haskell-type library functions:
|
|||||||
\_,_,_,f,x,y -> f y x ;
|
\_,_,_,f,x,y -> f y x ;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
#NEW
|
#NEW
|
||||||
|
|
||||||
===Dependent types: exercises===
|
===Dependent types: exercises===
|
||||||
|
|
||||||
1. Write an abstract syntax module with above contents
|
1. Write an abstract syntax module with above contents
|
||||||
and an appropriate English concrete syntax. Try to parse the commands
|
and an appropriate English concrete syntax. Try to parse the commands
|
||||||
//dim the light// and //dim the fan//, with and without ``solve`` filtering.
|
//dim the light// and //dim the fan//.
|
||||||
|
|
||||||
|
2. Perform random and exhaustive generation.
|
||||||
2. Perform random and exhaustive generation, with and without
|
|
||||||
``solve`` filtering.
|
|
||||||
|
|
||||||
3. Add some device kinds and actions to the grammar.
|
3. Add some device kinds and actions to the grammar.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#NEW
|
#NEW
|
||||||
|
|
||||||
==Proof objects==
|
==Proof objects==
|
||||||
@@ -3912,7 +3883,6 @@ fun
|
|||||||
Classes for new actions can be added incrementally.
|
Classes for new actions can be added incrementally.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#NEW
|
#NEW
|
||||||
|
|
||||||
==Variable bindings==
|
==Variable bindings==
|
||||||
@@ -4200,6 +4170,7 @@ We construct a calculator with addition, subtraction, multiplication, and
|
|||||||
division of integers.
|
division of integers.
|
||||||
```
|
```
|
||||||
abstract Calculator = {
|
abstract Calculator = {
|
||||||
|
flags startcat = Exp ;
|
||||||
|
|
||||||
cat Exp ;
|
cat Exp ;
|
||||||
|
|
||||||
@@ -4226,7 +4197,7 @@ We begin with a
|
|||||||
concrete syntax that always uses parentheses around binary
|
concrete syntax that always uses parentheses around binary
|
||||||
operator applications:
|
operator applications:
|
||||||
```
|
```
|
||||||
concrete CalculatorP of Calculator = {
|
concrete CalculatorP of Calculator = open Prelude in {
|
||||||
|
|
||||||
lincat
|
lincat
|
||||||
Exp = SS ;
|
Exp = SS ;
|
||||||
@@ -4737,10 +4708,6 @@ abstract Query = {
|
|||||||
|
|
||||||
To make it easy to define a transfer function, we export the
|
To make it easy to define a transfer function, we export the
|
||||||
abstract syntax to a system of Haskell datatypes:
|
abstract syntax to a system of Haskell datatypes:
|
||||||
```
|
|
||||||
% gf --output-format=haskell Query.pgf
|
|
||||||
```
|
|
||||||
It is also possible to produce the Haskell file together with PGF, by
|
|
||||||
```
|
```
|
||||||
% gf -make --output-format=haskell QueryEng.gf
|
% gf -make --output-format=haskell QueryEng.gf
|
||||||
```
|
```
|
||||||
|
|||||||
25
download/gfc
25
download/gfc
@@ -1,25 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
prefix="/usr/local"
|
|
||||||
|
|
||||||
case "i386-apple-darwin9.3.0" in
|
|
||||||
*-cygwin)
|
|
||||||
prefix=`cygpath -w "$prefix"`;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
exec_prefix="${prefix}"
|
|
||||||
GF_BIN_DIR="${exec_prefix}/bin"
|
|
||||||
GF_DATA_DIR="${prefix}/share/GF-3.0-beta"
|
|
||||||
|
|
||||||
GFBIN="$GF_BIN_DIR/gf"
|
|
||||||
|
|
||||||
if [ ! -x "${GFBIN}" ]; then
|
|
||||||
GFBIN=`which gf`
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! -x "${GFBIN}" ]; then
|
|
||||||
echo "gf not found."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
exec $GFBIN --batch "$@"
|
|
||||||
@@ -114,7 +114,7 @@ automatically by cabal, and therefore need to be installed manually.
|
|||||||
Here is one way to do this:
|
Here is one way to do this:
|
||||||
|
|
||||||
- On Ubuntu: `sudo apt-get install libghc-haskeline-dev`
|
- On Ubuntu: `sudo apt-get install libghc-haskeline-dev`
|
||||||
- On Fedora: `sudo yum install ghc-haskeline-devel`
|
- On Fedora: `sudo dnf install ghc-haskeline-devel`
|
||||||
|
|
||||||
**GHC version**
|
**GHC version**
|
||||||
|
|
||||||
@@ -171,6 +171,20 @@ in the RGL folder.
|
|||||||
This assumes that you already have GF installed.
|
This assumes that you already have GF installed.
|
||||||
For more details about building the RGL, see the [RGL README](https://github.com/GrammaticalFramework/gf-rgl/blob/master/README.md).
|
For more details about building the RGL, see the [RGL README](https://github.com/GrammaticalFramework/gf-rgl/blob/master/README.md).
|
||||||
|
|
||||||
|
## Installing the Python bindings from PyPI
|
||||||
|
|
||||||
|
The Python library is available on PyPI as `pgf`, so it can be installed using:
|
||||||
|
|
||||||
|
```
|
||||||
|
pip install pgf
|
||||||
|
```
|
||||||
|
|
||||||
|
We provide binary wheels for Linux and OSX (with Windows missing so far), which
|
||||||
|
include the C runtime and a ready-to-go. If there is no binary distribution for
|
||||||
|
your platform, this will install the source tarball, which will attempt to build
|
||||||
|
the binding during installation, and requires the GF C runtime to be installed on
|
||||||
|
your system.
|
||||||
|
|
||||||
## Older releases
|
## Older releases
|
||||||
|
|
||||||
- [GF 3.9](index-3.9.html) (August 2017)
|
- [GF 3.9](index-3.9.html) (August 2017)
|
||||||
173
download/index-3.11.md
Normal file
173
download/index-3.11.md
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
---
|
||||||
|
title: Grammatical Framework Download and Installation
|
||||||
|
...
|
||||||
|
|
||||||
|
**GF 3.11** was released on ... December 2020.
|
||||||
|
|
||||||
|
What's new? See the [release notes](release-3.11.html).
|
||||||
|
|
||||||
|
#### Note: GF core and the RGL
|
||||||
|
|
||||||
|
The following instructions explain how to install **GF core**, i.e. the compiler, shell and run-time systems.
|
||||||
|
Obtaining the **Resource Grammar Library (RGL)** is done separately; see the section at the bottom of this page.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Installing from a binary package
|
||||||
|
|
||||||
|
Binary packages are available for Debian/Ubuntu, macOS, and Windows and include:
|
||||||
|
|
||||||
|
- GF shell and grammar compiler
|
||||||
|
- `gf -server` mode
|
||||||
|
- C run-time system
|
||||||
|
- Java & Python bindings to the C run-time system
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
#### Debian/Ubuntu
|
||||||
|
|
||||||
|
To install the package use:
|
||||||
|
```
|
||||||
|
sudo dpkg -i gf_3.11.deb
|
||||||
|
```
|
||||||
|
|
||||||
|
The Ubuntu `.deb` packages should work on Ubuntu 16.04, 18.04 and similar Linux distributions.
|
||||||
|
|
||||||
|
#### macOS
|
||||||
|
|
||||||
|
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).
|
||||||
|
|
||||||
|
#### Windows
|
||||||
|
|
||||||
|
To install the package, unpack it anywhere.
|
||||||
|
|
||||||
|
You will probably need to update the `PATH` environment variable to include your chosen install location.
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
[GF is on Hackage](http://hackage.haskell.org/package/gf), so under
|
||||||
|
normal circumstances the procedure is fairly simple:
|
||||||
|
|
||||||
|
1. Install ghcup https://www.haskell.org/ghcup/
|
||||||
|
2. `ghcup install ghc 8.10.4`
|
||||||
|
3. `ghcup set ghc 8.10.4`
|
||||||
|
4. `cabal update`
|
||||||
|
5. On Linux: install some C libraries from your Linux distribution (see note below)
|
||||||
|
6. `cabal install gf-3.11`
|
||||||
|
|
||||||
|
You can also download the source code release from [GitHub](https://github.com/GrammaticalFramework/gf-core/releases),
|
||||||
|
and follow the instructions below under **Installing from the latest developer source code**.
|
||||||
|
|
||||||
|
### Notes
|
||||||
|
|
||||||
|
**Installation location**
|
||||||
|
|
||||||
|
The above steps installs GF for a single user.
|
||||||
|
The executables are put in `$HOME/.cabal/bin` (or on macOS in `$HOME/Library/Haskell/bin`),
|
||||||
|
so you might want to add this directory to your path (in `.bash_profile` or similar):
|
||||||
|
|
||||||
|
```
|
||||||
|
PATH=$HOME/.cabal/bin:$PATH
|
||||||
|
```
|
||||||
|
|
||||||
|
**Haskeline**
|
||||||
|
|
||||||
|
GF uses [`haskeline`](http://hackage.haskell.org/package/haskeline), which
|
||||||
|
on Linux depends on some non-Haskell libraries that won't be installed
|
||||||
|
automatically by cabal, and therefore need to be installed manually.
|
||||||
|
Here is one way to do this:
|
||||||
|
|
||||||
|
- On Ubuntu: `sudo apt-get install libghc-haskeline-dev`
|
||||||
|
- On Fedora: `sudo dnf install ghc-haskeline-devel`
|
||||||
|
|
||||||
|
**GHC version**
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
If you haven't already, clone the repository with:
|
||||||
|
|
||||||
|
```
|
||||||
|
git clone https://github.com/GrammaticalFramework/gf-core.git
|
||||||
|
```
|
||||||
|
|
||||||
|
If you've already cloned the repository previously, update with:
|
||||||
|
|
||||||
|
```
|
||||||
|
git pull
|
||||||
|
```
|
||||||
|
|
||||||
|
Then install with:
|
||||||
|
|
||||||
|
```
|
||||||
|
cabal install
|
||||||
|
```
|
||||||
|
|
||||||
|
or, if you're a Stack user:
|
||||||
|
|
||||||
|
```
|
||||||
|
stack install
|
||||||
|
```
|
||||||
|
|
||||||
|
The above notes for installing from source apply also in these cases.
|
||||||
|
For more info on working with the GF source code, see the
|
||||||
|
[GF Developers Guide](../doc/gf-developers.html).
|
||||||
|
|
||||||
|
## Installing the Python bindings from PyPI
|
||||||
|
|
||||||
|
The Python library is available on PyPI as `pgf`, so it can be installed using:
|
||||||
|
|
||||||
|
```
|
||||||
|
pip install pgf
|
||||||
|
```
|
||||||
|
|
||||||
|
We provide binary wheels for Linux and macOS, which include the C runtime and are ready-to-go.
|
||||||
|
If there is no binary distribution for your platform, this will install the source tarball,
|
||||||
|
which will attempt to build the binding during installation,
|
||||||
|
and requires the GF C runtime to be installed on your system.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Installing the RGL from a binary release
|
||||||
|
|
||||||
|
Binary releases of the RGL are made available on [GitHub](https://github.com/GrammaticalFramework/gf-rgl/releases).
|
||||||
|
In general the steps to follow are:
|
||||||
|
|
||||||
|
1. Download a binary release and extract it somewhere on your system.
|
||||||
|
2. Set the environment variable `GF_LIB_PATH` to point to wherever you extracted the RGL.
|
||||||
|
|
||||||
|
## Installing the RGL from source
|
||||||
|
|
||||||
|
To compile the RGL, you will need to have GF already installed and in your path.
|
||||||
|
|
||||||
|
1. Obtain the RGL source code, either by:
|
||||||
|
- cloning with `git clone https://github.com/GrammaticalFramework/gf-rgl.git`
|
||||||
|
- downloading a source archive [here](https://github.com/GrammaticalFramework/gf-rgl/archive/master.zip)
|
||||||
|
2. Run `make` in the source code folder.
|
||||||
|
|
||||||
|
For more options, see the [RGL README](https://github.com/GrammaticalFramework/gf-rgl/blob/master/README.md).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Older releases
|
||||||
|
|
||||||
|
- [GF 3.10](index-3.10.html) (December 2018)
|
||||||
|
- [GF 3.9](index-3.9.html) (August 2017)
|
||||||
|
- [GF 3.8](index-3.8.html) (June 2016)
|
||||||
|
- [GF 3.7.1](index-3.7.1.html) (October 2015)
|
||||||
|
- [GF 3.7](index-3.7.html) (June 2015)
|
||||||
|
- [GF 3.6](index-3.6.html) (June 2014)
|
||||||
|
- [GF 3.5](index-3.5.html) (August 2013)
|
||||||
|
- [GF 3.4](index-3.4.html) (January 2013)
|
||||||
|
- [GF 3.3.3](index-3.3.3.html) (March 2012)
|
||||||
|
- [GF 3.3](index-3.3.html) (October 2011)
|
||||||
|
- [GF 3.2.9](index-3.2.9.html) source-only snapshot (September 2011)
|
||||||
|
- [GF 3.2](index-3.2.html) (December 2010)
|
||||||
|
- [GF 3.1.6](index-3.1.6.html) (April 2010)
|
||||||
8
download/index.html
Normal file
8
download/index.html
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="refresh" content="0; URL=/download/index-3.10.html" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
You are being redirected to <a href="index-3.10.html">the current version</a> of this page.
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
43
download/release-3.11.md
Normal file
43
download/release-3.11.md
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
---
|
||||||
|
title: GF 3.11 Release Notes
|
||||||
|
date: ... July 2021
|
||||||
|
...
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
See the [download page](index-3.11.html).
|
||||||
|
|
||||||
|
## What's new
|
||||||
|
|
||||||
|
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).
|
||||||
|
|
||||||
|
Over 500 changes have been pushed to GF core
|
||||||
|
since the release of GF 3.10 in December 2018.
|
||||||
|
|
||||||
|
## General
|
||||||
|
|
||||||
|
- Make the test suite work again.
|
||||||
|
- Compatibility with new versions of GHC, including multiple Stack files for the different versions.
|
||||||
|
- Support for newer version of Ubuntu 20.04 in the precompiled binaries.
|
||||||
|
- Updates to build scripts and CI workflows.
|
||||||
|
- Bug fixes and code cleanup.
|
||||||
|
|
||||||
|
## GF compiler and run-time library
|
||||||
|
|
||||||
|
- Add CoNLL output to `visualize_tree` shell command.
|
||||||
|
- Add canonical GF 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).
|
||||||
|
- Improvements in time & space requirements when compiling certain grammars.
|
||||||
|
- Improvements to Haskell export.
|
||||||
|
- Improvements to the GF shell.
|
||||||
|
- Improvements to canonical GF compilation.
|
||||||
|
- Improvements to the C runtime.
|
||||||
|
- Improvements to `gf -server` mode.
|
||||||
|
- Clearer compiler error messages.
|
||||||
|
|
||||||
|
## Other
|
||||||
|
|
||||||
|
- Web page and documentation improvements.
|
||||||
|
- Add WordNet module to GFSE.
|
||||||
159
gf.cabal
159
gf.cabal
@@ -1,19 +1,19 @@
|
|||||||
name: gf
|
name: gf
|
||||||
version: 3.10.3-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
|
||||||
data-files:
|
data-files:
|
||||||
www/*.html
|
www/*.html
|
||||||
www/*.css
|
www/*.css
|
||||||
@@ -41,11 +41,11 @@ 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
|
||||||
@@ -71,18 +71,27 @@ flag c-runtime
|
|||||||
Description: Include functionality from the C run-time library (which must be installed already)
|
Description: Include functionality from the C run-time library (which must be installed already)
|
||||||
Default: False
|
Default: False
|
||||||
|
|
||||||
Library
|
library
|
||||||
default-language: Haskell2010
|
default-language: Haskell2010
|
||||||
build-depends: base >= 4.6 && <5,
|
build-depends:
|
||||||
array,
|
-- GHC 8.0.2 to GHC 8.10.4
|
||||||
containers,
|
array >= 0.5.1 && < 0.6,
|
||||||
bytestring,
|
base >= 4.9.1 && < 4.15,
|
||||||
utf8-string,
|
bytestring >= 0.10.8 && < 0.11,
|
||||||
random,
|
containers >= 0.5.7 && < 0.7,
|
||||||
pretty,
|
exceptions >= 0.8.3 && < 0.11,
|
||||||
mtl,
|
ghc-prim >= 0.5.0 && < 0.7,
|
||||||
exceptions,
|
mtl >= 2.2.1 && < 2.3,
|
||||||
ghc-prim
|
pretty >= 1.1.3 && < 1.2,
|
||||||
|
random >= 1.1 && < 1.3,
|
||||||
|
utf8-string >= 1.0.1.1 && < 1.1,
|
||||||
|
-- We need transformers-compat >= 0.6.3, but that is only in newer snapshots where it is redundant.
|
||||||
|
transformers-compat >= 0.5.1.4 && < 0.7
|
||||||
|
|
||||||
|
if impl(ghc<8.0)
|
||||||
|
build-depends:
|
||||||
|
fail >= 4.9.0 && < 4.10
|
||||||
|
|
||||||
hs-source-dirs: src/runtime/haskell
|
hs-source-dirs: src/runtime/haskell
|
||||||
|
|
||||||
other-modules:
|
other-modules:
|
||||||
@@ -98,8 +107,6 @@ Library
|
|||||||
--if impl(ghc>=7.8)
|
--if impl(ghc>=7.8)
|
||||||
-- ghc-options: +RTS -A20M -RTS
|
-- ghc-options: +RTS -A20M -RTS
|
||||||
ghc-prof-options: -fprof-auto
|
ghc-prof-options: -fprof-auto
|
||||||
if impl(ghc>=8.6)
|
|
||||||
Default-extensions: NoMonadFailDesugaring
|
|
||||||
|
|
||||||
exposed-modules:
|
exposed-modules:
|
||||||
PGF
|
PGF
|
||||||
@@ -133,8 +140,12 @@ Library
|
|||||||
|
|
||||||
if flag(c-runtime)
|
if flag(c-runtime)
|
||||||
exposed-modules: PGF2
|
exposed-modules: PGF2
|
||||||
other-modules: PGF2.FFI PGF2.Expr PGF2.Type
|
other-modules:
|
||||||
GF.Interactive2 GF.Command.Commands2
|
PGF2.FFI
|
||||||
|
PGF2.Expr
|
||||||
|
PGF2.Type
|
||||||
|
GF.Interactive2
|
||||||
|
GF.Command.Commands2
|
||||||
hs-source-dirs: src/runtime/haskell-bind
|
hs-source-dirs: src/runtime/haskell-bind
|
||||||
build-tools: hsc2hs
|
build-tools: hsc2hs
|
||||||
extra-libraries: pgf gu
|
extra-libraries: pgf gu
|
||||||
@@ -143,8 +154,14 @@ Library
|
|||||||
|
|
||||||
---- GF compiler as a library:
|
---- GF compiler as a library:
|
||||||
|
|
||||||
build-depends: filepath, directory>=1.2, time,
|
build-depends:
|
||||||
process, haskeline, parallel>=3, json
|
directory >= 1.3.0 && < 1.4,
|
||||||
|
filepath >= 1.4.1 && < 1.5,
|
||||||
|
haskeline >= 0.7.3 && < 0.9,
|
||||||
|
json >= 0.9.1 && < 0.11,
|
||||||
|
parallel >= 3.2.1.1 && < 3.3,
|
||||||
|
process >= 1.4.3 && < 1.7,
|
||||||
|
time >= 1.6.0 && < 1.10
|
||||||
|
|
||||||
hs-source-dirs: src/compiler
|
hs-source-dirs: src/compiler
|
||||||
exposed-modules:
|
exposed-modules:
|
||||||
@@ -155,12 +172,19 @@ Library
|
|||||||
GF.Grammar.Canonical
|
GF.Grammar.Canonical
|
||||||
|
|
||||||
other-modules:
|
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
|
||||||
GF.Grammar
|
GF.Grammar
|
||||||
|
|
||||||
GF.Data.Operations GF.Infra.Option GF.Infra.UseIO
|
GF.Data.Operations
|
||||||
|
GF.Infra.Option
|
||||||
|
GF.Infra.UseIO
|
||||||
|
|
||||||
GF.Command.Abstract
|
GF.Command.Abstract
|
||||||
GF.Command.CommandInfo
|
GF.Command.CommandInfo
|
||||||
@@ -175,9 +199,7 @@ Library
|
|||||||
GF.Command.TreeOperations
|
GF.Command.TreeOperations
|
||||||
GF.Compile.CFGtoPGF
|
GF.Compile.CFGtoPGF
|
||||||
GF.Compile.CheckGrammar
|
GF.Compile.CheckGrammar
|
||||||
GF.Compile.Compute.AppPredefined
|
GF.Compile.Compute.Concrete
|
||||||
GF.Compile.Compute.ConcreteNew
|
|
||||||
-- GF.Compile.Compute.ConcreteNew1
|
|
||||||
GF.Compile.Compute.Predef
|
GF.Compile.Compute.Predef
|
||||||
GF.Compile.Compute.Value
|
GF.Compile.Compute.Value
|
||||||
GF.Compile.ExampleBased
|
GF.Compile.ExampleBased
|
||||||
@@ -206,7 +228,6 @@ Library
|
|||||||
GF.Compile.TypeCheck.Concrete
|
GF.Compile.TypeCheck.Concrete
|
||||||
GF.Compile.TypeCheck.ConcreteNew
|
GF.Compile.TypeCheck.ConcreteNew
|
||||||
GF.Compile.TypeCheck.Primitives
|
GF.Compile.TypeCheck.Primitives
|
||||||
GF.Compile.TypeCheck.RConcrete
|
|
||||||
GF.Compile.TypeCheck.TC
|
GF.Compile.TypeCheck.TC
|
||||||
GF.Compile.Update
|
GF.Compile.Update
|
||||||
GF.Data.BacktrackM
|
GF.Data.BacktrackM
|
||||||
@@ -273,12 +294,17 @@ Library
|
|||||||
cpp-options: -DC_RUNTIME
|
cpp-options: -DC_RUNTIME
|
||||||
|
|
||||||
if flag(server)
|
if flag(server)
|
||||||
build-depends: httpd-shed>=0.4.0.3, network>=2.3 && <2.7,
|
build-depends:
|
||||||
cgi>=3001.2.2.0
|
cgi >= 3001.3.0.2 && < 3001.6,
|
||||||
|
httpd-shed >= 0.4.0 && < 0.5,
|
||||||
|
network>=2.3 && <2.7
|
||||||
if flag(network-uri)
|
if flag(network-uri)
|
||||||
build-depends: network-uri>=2.6, network>=2.6
|
build-depends:
|
||||||
|
network-uri >= 2.6.1.0 && < 2.7,
|
||||||
|
network>=2.6 && <2.7
|
||||||
else
|
else
|
||||||
build-depends: network<2.6
|
build-depends:
|
||||||
|
network >= 2.5 && <2.6
|
||||||
|
|
||||||
cpp-options: -DSERVER_MODE
|
cpp-options: -DSERVER_MODE
|
||||||
other-modules:
|
other-modules:
|
||||||
@@ -295,7 +321,10 @@ Library
|
|||||||
Fold
|
Fold
|
||||||
ExampleDemo
|
ExampleDemo
|
||||||
ExampleService
|
ExampleService
|
||||||
hs-source-dirs: src/server src/server/transfer src/example-based
|
hs-source-dirs:
|
||||||
|
src/server
|
||||||
|
src/server/transfer
|
||||||
|
src/example-based
|
||||||
|
|
||||||
if flag(interrupt)
|
if flag(interrupt)
|
||||||
cpp-options: -DUSE_INTERRUPT
|
cpp-options: -DUSE_INTERRUPT
|
||||||
@@ -304,26 +333,35 @@ Library
|
|||||||
other-modules: GF.System.NoSignal
|
other-modules: GF.System.NoSignal
|
||||||
|
|
||||||
if impl(ghc>=7.8)
|
if impl(ghc>=7.8)
|
||||||
build-tools: happy>=1.19, alex>=3.1
|
build-tools:
|
||||||
|
happy>=1.19,
|
||||||
|
alex>=3.1
|
||||||
-- ghc-options: +RTS -A20M -RTS
|
-- ghc-options: +RTS -A20M -RTS
|
||||||
else
|
else
|
||||||
build-tools: happy, alex>=3
|
build-tools:
|
||||||
|
happy,
|
||||||
|
alex>=3
|
||||||
|
|
||||||
ghc-options: -fno-warn-tabs
|
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,
|
||||||
|
unix >= 2.7.2 && < 2.8
|
||||||
|
|
||||||
if impl(ghc>=8.2)
|
if impl(ghc>=8.2)
|
||||||
ghc-options: -fhide-source-paths
|
ghc-options: -fhide-source-paths
|
||||||
|
|
||||||
Executable gf
|
executable gf
|
||||||
hs-source-dirs: src/programs
|
hs-source-dirs: src/programs
|
||||||
main-is: gf-main.hs
|
main-is: gf-main.hs
|
||||||
default-language: Haskell2010
|
default-language: Haskell2010
|
||||||
build-depends: gf, base
|
build-depends:
|
||||||
|
gf,
|
||||||
|
base
|
||||||
ghc-options: -threaded
|
ghc-options: -threaded
|
||||||
--ghc-options: -fwarn-unused-imports
|
--ghc-options: -fwarn-unused-imports
|
||||||
|
|
||||||
@@ -337,19 +375,30 @@ Executable gf
|
|||||||
if impl(ghc>=8.2)
|
if impl(ghc>=8.2)
|
||||||
ghc-options: -fhide-source-paths
|
ghc-options: -fhide-source-paths
|
||||||
|
|
||||||
executable pgf-shell
|
-- executable pgf-shell
|
||||||
--if !flag(c-runtime)
|
-- --if !flag(c-runtime)
|
||||||
buildable: False
|
-- buildable: False
|
||||||
main-is: pgf-shell.hs
|
-- main-is: pgf-shell.hs
|
||||||
hs-source-dirs: src/runtime/haskell-bind/examples
|
-- hs-source-dirs: src/runtime/haskell-bind/examples
|
||||||
build-depends: gf, base, containers, mtl, lifted-base
|
-- build-depends:
|
||||||
default-language: Haskell2010
|
-- gf,
|
||||||
if impl(ghc>=7.0)
|
-- base,
|
||||||
ghc-options: -rtsopts
|
-- 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
|
||||||
default-language: Haskell2010
|
default-language: Haskell2010
|
||||||
|
|||||||
50
index.html
50
index.html
@@ -22,9 +22,9 @@
|
|||||||
<h4 class="text-black-50">A programming language for multilingual grammar applications</h4>
|
<h4 class="text-black-50">A programming language for multilingual grammar applications</h4>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row my-4">
|
<div class="row mt-4">
|
||||||
|
|
||||||
<div class="col-sm-6 col-md-3">
|
<div class="col-sm-6 col-md-3 mb-4">
|
||||||
<h3>Get started</h3>
|
<h3>Get started</h3>
|
||||||
<ul class="mb-2">
|
<ul class="mb-2">
|
||||||
<li><a href="https://www.youtube.com/watch?v=x1LFbDQhbso">Google Tech Talk</a></li>
|
<li><a href="https://www.youtube.com/watch?v=x1LFbDQhbso">Google Tech Talk</a></li>
|
||||||
@@ -39,6 +39,7 @@
|
|||||||
/
|
/
|
||||||
<a href="lib/doc/rgl-tutorial/index.html">RGL Tutorial</a>
|
<a href="lib/doc/rgl-tutorial/index.html">RGL Tutorial</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li><a href="doc/gf-video-tutorials.html">Video Tutorials</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<a href="download/index.html" class="btn btn-primary ml-3">
|
<a href="download/index.html" class="btn btn-primary ml-3">
|
||||||
@@ -47,7 +48,7 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-sm-6 col-md-3">
|
<div class="col-sm-6 col-md-3 mb-4">
|
||||||
<h3>Learn more</h3>
|
<h3>Learn more</h3>
|
||||||
|
|
||||||
<ul class="mb-2">
|
<ul class="mb-2">
|
||||||
@@ -55,6 +56,7 @@
|
|||||||
<li><a href="doc/gf-refman.html">Reference Manual</a></li>
|
<li><a href="doc/gf-refman.html">Reference Manual</a></li>
|
||||||
<li><a href="doc/gf-shell-reference.html">Shell Reference</a></li>
|
<li><a href="doc/gf-shell-reference.html">Shell Reference</a></li>
|
||||||
<li><a href="http://www.molto-project.eu/sites/default/files/MOLTO_D2.3.pdf">Best Practices</a> <small>[PDF]</small></li>
|
<li><a href="http://www.molto-project.eu/sites/default/files/MOLTO_D2.3.pdf">Best Practices</a> <small>[PDF]</small></li>
|
||||||
|
<li><a href="https://www.mitpressjournals.org/doi/pdf/10.1162/COLI_a_00378">Scaling Up (Computational Linguistics 2020)</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<a href="lib/doc/synopsis/index.html" class="btn btn-primary ml-3">
|
<a href="lib/doc/synopsis/index.html" class="btn btn-primary ml-3">
|
||||||
@@ -63,27 +65,30 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-sm-6 col-md-3">
|
<div class="col-sm-6 col-md-3 mb-4">
|
||||||
<h3>Develop</h3>
|
<h3>Develop</h3>
|
||||||
<ul class="mb-2">
|
<ul class="mb-2">
|
||||||
<li><a href="doc/gf-developers.html">Developers Guide</a></li>
|
<li><a href="doc/gf-developers.html">Developers Guide</a></li>
|
||||||
<!-- <li><a href="/~hallgren/gf-experiment/browse/">Browse Source Code</a></li> -->
|
<!-- <li><a href="/~hallgren/gf-experiment/browse/">Browse Source Code</a></li> -->
|
||||||
<li><a href="http://hackage.haskell.org/package/gf/docs/PGF.html">PGF library API (Haskell runtime)</a></li>
|
<li>PGF library API:<br>
|
||||||
<li><a href="doc/runtime-api.html">PGF library API (C runtime)</a></li>
|
<a href="http://hackage.haskell.org/package/gf/docs/PGF.html">Haskell</a> /
|
||||||
|
<a href="doc/runtime-api.html">C runtime</a>
|
||||||
|
</li>
|
||||||
<li><a href="http://hackage.haskell.org/package/gf/docs/GF.html">GF compiler API</a></li>
|
<li><a href="http://hackage.haskell.org/package/gf/docs/GF.html">GF compiler API</a></li>
|
||||||
<!-- <li><a href="src/ui/android/README">GF on Android (new)</a></li>
|
<!-- <li><a href="src/ui/android/README">GF on Android (new)</a></li>
|
||||||
<li><a href="/android/">GF on Android (old) </a></li> -->
|
<li><a href="/android/">GF on Android (old) </a></li> -->
|
||||||
<li><a href="doc/gf-editor-modes.html">Text Editor Support</a></li>
|
<li><a href="doc/gf-editor-modes.html">Text Editor Support</a></li>
|
||||||
|
<li><a href="http://www.grammaticalframework.org/~john/rgl-browser/">RGL source browser</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-sm-6 col-md-3">
|
<div class="col-sm-6 col-md-3 mb-4">
|
||||||
<h3>Contribute</h3>
|
<h3>Contribute</h3>
|
||||||
<ul class="mb-2">
|
<ul class="mb-2">
|
||||||
<li><a href="http://groups.google.com/group/gf-dev">Mailing List</a></li>
|
<li><a href="http://groups.google.com/group/gf-dev">Mailing List</a></li>
|
||||||
<li><a href="https://github.com/GrammaticalFramework/gf-core/issues">Issue Tracker</a></li>
|
<li><a href="https://github.com/GrammaticalFramework/gf-core/issues">Issue Tracker</a></li>
|
||||||
<li><a href="doc/gf-people.html">Authors</a></li>
|
<li><a href="doc/gf-people.html">Authors</a></li>
|
||||||
<li><a href="//school.grammaticalframework.org/2018/">Summer School</a></li>
|
<li><a href="//school.grammaticalframework.org/2020/">Summer School</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
<a href="https://github.com/GrammaticalFramework/" class="btn btn-primary ml-3">
|
<a href="https://github.com/GrammaticalFramework/" class="btn btn-primary ml-3">
|
||||||
<i class="fab fa-github mr-1"></i>
|
<i class="fab fa-github mr-1"></i>
|
||||||
@@ -169,6 +174,7 @@ least one, it may help you to get a first idea of what GF is.
|
|||||||
<li>macOS</li>
|
<li>macOS</li>
|
||||||
<li>Windows</li>
|
<li>Windows</li>
|
||||||
<li>Android mobile platform (via Java; runtime)</li>
|
<li>Android mobile platform (via Java; runtime)</li>
|
||||||
|
<li>iOS mobile platform (iPhone, iPad)</li>
|
||||||
<li>via compilation to JavaScript, almost any platform that has a web browser (runtime)</li>
|
<li>via compilation to JavaScript, almost any platform that has a web browser (runtime)</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
@@ -208,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>.
|
||||||
@@ -222,6 +228,18 @@ least one, it may help you to get a first idea of what GF is.
|
|||||||
<h2>News</h2>
|
<h2>News</h2>
|
||||||
|
|
||||||
<dl class="row">
|
<dl class="row">
|
||||||
|
<dt class="col-sm-3 text-center text-nowrap">2021-05-05</dt>
|
||||||
|
<dd class="col-sm-9">
|
||||||
|
<a href="https://cloud.grammaticalframework.org/wordnet/">GF WordNet</a> now supports languages for which there are no other WordNets. New additions: Afrikaans, German, Korean, Maltese, Polish, Somali, Swahili.
|
||||||
|
</dd>
|
||||||
|
<dt class="col-sm-3 text-center text-nowrap">2021-03-01</dt>
|
||||||
|
<dd class="col-sm-9">
|
||||||
|
<a href="//school.grammaticalframework.org/2020/">Seventh GF Summer School</a>, in Singapore and online, 26 July – 8 August 2021.
|
||||||
|
</dd>
|
||||||
|
<dt class="col-sm-3 text-center text-nowrap">2020-09-29</dt>
|
||||||
|
<dd class="col-sm-9">
|
||||||
|
<a href="https://www.mitpressjournals.org/doi/pdf/10.1162/COLI_a_00378">Abstract Syntax as Interlingua</a>: Scaling Up the Grammatical Framework from Controlled Languages to Robust Pipelines. A paper in Computational Linguistics (2020) summarizing much of the development in GF in the past ten years.
|
||||||
|
</dd>
|
||||||
<dt class="col-sm-3 text-center text-nowrap">2018-12-03</dt>
|
<dt class="col-sm-3 text-center text-nowrap">2018-12-03</dt>
|
||||||
<dd class="col-sm-9">
|
<dd class="col-sm-9">
|
||||||
<a href="//school.grammaticalframework.org/2018/">Sixth GF Summer School</a> in Stellenbosch (South Africa), 3–14 December 2018
|
<a href="//school.grammaticalframework.org/2018/">Sixth GF Summer School</a> in Stellenbosch (South Africa), 3–14 December 2018
|
||||||
@@ -324,9 +342,11 @@ least one, it may help you to get a first idea of what GF is.
|
|||||||
Afrikaans,
|
Afrikaans,
|
||||||
Amharic (partial),
|
Amharic (partial),
|
||||||
Arabic (partial),
|
Arabic (partial),
|
||||||
|
Basque (partial),
|
||||||
Bulgarian,
|
Bulgarian,
|
||||||
Catalan,
|
Catalan,
|
||||||
Chinese,
|
Chinese,
|
||||||
|
Czech (partial),
|
||||||
Danish,
|
Danish,
|
||||||
Dutch,
|
Dutch,
|
||||||
English,
|
English,
|
||||||
@@ -338,10 +358,12 @@ least one, it may help you to get a first idea of what GF is.
|
|||||||
Greek modern,
|
Greek modern,
|
||||||
Hebrew (fragments),
|
Hebrew (fragments),
|
||||||
Hindi,
|
Hindi,
|
||||||
|
Hungarian (partial),
|
||||||
Interlingua,
|
Interlingua,
|
||||||
Japanese,
|
|
||||||
Italian,
|
Italian,
|
||||||
Latin (fragments),
|
Japanese,
|
||||||
|
Korean (partial),
|
||||||
|
Latin (partial),
|
||||||
Latvian,
|
Latvian,
|
||||||
Maltese,
|
Maltese,
|
||||||
Mongolian,
|
Mongolian,
|
||||||
@@ -354,7 +376,9 @@ least one, it may help you to get a first idea of what GF is.
|
|||||||
Romanian,
|
Romanian,
|
||||||
Russian,
|
Russian,
|
||||||
Sindhi,
|
Sindhi,
|
||||||
|
Slovak (partial),
|
||||||
Slovene (partial),
|
Slovene (partial),
|
||||||
|
Somali (partial),
|
||||||
Spanish,
|
Spanish,
|
||||||
Swahili (fragments),
|
Swahili (fragments),
|
||||||
Swedish,
|
Swedish,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
{-# LANGUAGE FlexibleInstances, UndecidableInstances #-}
|
{-# LANGUAGE FlexibleInstances, UndecidableInstances, CPP #-}
|
||||||
module GF.Command.Commands (
|
module GF.Command.Commands (
|
||||||
PGFEnv,HasPGFEnv(..),pgf,mos,pgfEnv,pgfCommands,
|
PGFEnv,HasPGFEnv(..),pgf,mos,pgfEnv,pgfCommands,
|
||||||
options,flags,
|
options,flags,
|
||||||
@@ -34,6 +34,7 @@ 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 qualified Control.Monad.Fail as Fail
|
||||||
--import Debug.Trace
|
--import Debug.Trace
|
||||||
|
|
||||||
|
|
||||||
@@ -44,7 +45,7 @@ pgfEnv pgf = Env pgf mos
|
|||||||
|
|
||||||
class (Functor m,Monad m,MonadSIO m) => HasPGFEnv m where getPGFEnv :: m PGFEnv
|
class (Functor m,Monad m,MonadSIO m) => HasPGFEnv m where getPGFEnv :: m PGFEnv
|
||||||
|
|
||||||
instance (Monad m,HasPGFEnv m) => TypeCheckArg m where
|
instance (Monad m,HasPGFEnv m,Fail.MonadFail m) => TypeCheckArg m where
|
||||||
typeCheckArg e = (either (fail . render . ppTcError) (return . fst)
|
typeCheckArg e = (either (fail . render . ppTcError) (return . fst)
|
||||||
. flip inferExpr e . pgf) =<< getPGFEnv
|
. flip inferExpr e . pgf) =<< getPGFEnv
|
||||||
|
|
||||||
@@ -740,7 +741,7 @@ pgfCommands = Map.fromList [
|
|||||||
Nothing -> do putStrLn ("unknown category of function identifier "++show id)
|
Nothing -> do putStrLn ("unknown category of function identifier "++show id)
|
||||||
return void
|
return void
|
||||||
[e] -> case inferExpr pgf e of
|
[e] -> case inferExpr pgf e of
|
||||||
Left tcErr -> error $ render (ppTcError tcErr)
|
Left tcErr -> errorWithoutStackTrace $ render (ppTcError tcErr)
|
||||||
Right (e,ty) -> do putStrLn ("Expression: "++showExpr [] e)
|
Right (e,ty) -> do putStrLn ("Expression: "++showExpr [] e)
|
||||||
putStrLn ("Type: "++showType [] ty)
|
putStrLn ("Type: "++showType [] ty)
|
||||||
putStrLn ("Probability: "++show (probTree pgf e))
|
putStrLn ("Probability: "++show (probTree pgf e))
|
||||||
@@ -1018,3 +1019,7 @@ stanzas = map unlines . chop . lines where
|
|||||||
chop ls = case break (=="") ls of
|
chop ls = case break (=="") ls of
|
||||||
(ls1,[]) -> [ls1]
|
(ls1,[]) -> [ls1]
|
||||||
(ls1,_:ls2) -> ls1 : chop ls2
|
(ls1,_:ls2) -> ls1 : chop ls2
|
||||||
|
|
||||||
|
#if !(MIN_VERSION_base(4,9,0))
|
||||||
|
errorWithoutStackTrace = error
|
||||||
|
#endif
|
||||||
@@ -18,6 +18,7 @@ import Data.Maybe
|
|||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
import GF.Text.Pretty
|
import GF.Text.Pretty
|
||||||
import Control.Monad(mplus)
|
import Control.Monad(mplus)
|
||||||
|
import qualified Control.Monad.Fail as Fail
|
||||||
|
|
||||||
|
|
||||||
data PGFEnv = Env {pgf::Maybe PGF,concs::Map.Map ConcName Concr}
|
data PGFEnv = Env {pgf::Maybe PGF,concs::Map.Map ConcName Concr}
|
||||||
@@ -25,7 +26,7 @@ data PGFEnv = Env {pgf::Maybe PGF,concs::Map.Map ConcName Concr}
|
|||||||
pgfEnv pgf = Env (Just pgf) (languages pgf)
|
pgfEnv pgf = Env (Just pgf) (languages pgf)
|
||||||
emptyPGFEnv = Env Nothing Map.empty
|
emptyPGFEnv = Env Nothing Map.empty
|
||||||
|
|
||||||
class (Monad m,MonadSIO m) => HasPGFEnv m where getPGFEnv :: m PGFEnv
|
class (Fail.MonadFail m,MonadSIO m) => HasPGFEnv m where getPGFEnv :: m PGFEnv
|
||||||
|
|
||||||
instance (Monad m,HasPGFEnv m) => TypeCheckArg m where
|
instance (Monad m,HasPGFEnv m) => TypeCheckArg m where
|
||||||
typeCheckArg e = do env <- getPGFEnv
|
typeCheckArg e = do env <- getPGFEnv
|
||||||
@@ -806,6 +807,10 @@ hsExpr c =
|
|||||||
Just (f,cs) -> H.mkApp (H.mkCId f) (map hsExpr cs)
|
Just (f,cs) -> H.mkApp (H.mkCId f) (map hsExpr cs)
|
||||||
_ -> case unStr c of
|
_ -> case unStr c of
|
||||||
Just str -> H.mkStr str
|
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
|
_ -> error $ "GF.Command.Commands2.hsExpr "++show c
|
||||||
|
|
||||||
cExpr e =
|
cExpr e =
|
||||||
@@ -813,6 +818,10 @@ cExpr e =
|
|||||||
Just (f,es) -> mkApp (H.showCId f) (map cExpr es)
|
Just (f,es) -> mkApp (H.showCId f) (map cExpr es)
|
||||||
_ -> case H.unStr e of
|
_ -> case H.unStr e of
|
||||||
Just str -> mkStr str
|
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
|
_ -> error $ "GF.Command.Commands2.cExpr "++show e
|
||||||
|
|
||||||
needPGF exec opts ts =
|
needPGF exec opts ts =
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import GF.Command.Abstract --(isOpt,valStrOpts,prOpt)
|
|||||||
import GF.Text.Pretty
|
import GF.Text.Pretty
|
||||||
import GF.Text.Transliterations
|
import GF.Text.Transliterations
|
||||||
import GF.Text.Lexing(stringOp,opInEnv)
|
import GF.Text.Lexing(stringOp,opInEnv)
|
||||||
|
import Data.Char (isSpace)
|
||||||
|
|
||||||
import qualified PGF as H(showCId,showExpr,toATree,toTrie,Trie(..))
|
import qualified PGF as H(showCId,showExpr,toATree,toTrie,Trie(..))
|
||||||
|
|
||||||
@@ -170,7 +171,8 @@ commonCommands = fmap (mapCommandExec liftSIO) $ Map.fromList [
|
|||||||
restrictedSystem $ syst ++ " <" ++ tmpi ++ " >" ++ tmpo
|
restrictedSystem $ syst ++ " <" ++ tmpi ++ " >" ++ tmpo
|
||||||
fmap fromString $ restricted $ readFile tmpo,
|
fmap fromString $ restricted $ readFile tmpo,
|
||||||
-}
|
-}
|
||||||
fmap fromString . restricted . readShellProcess syst $ toString arg,
|
fmap (fromStrings . lines) . restricted . readShellProcess syst . unlines . map (dropWhile (=='\n')) $ toStrings $ arg,
|
||||||
|
|
||||||
flags = [
|
flags = [
|
||||||
("command","the system command applied to the argument")
|
("command","the system command applied to the argument")
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ import GF.Infra.UseIO(putStrLnE)
|
|||||||
|
|
||||||
import Control.Monad(when)
|
import Control.Monad(when)
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
|
import GF.Infra.UseIO (Output)
|
||||||
|
import qualified Control.Monad.Fail as Fail
|
||||||
|
|
||||||
data CommandEnv m = CommandEnv {
|
data CommandEnv m = CommandEnv {
|
||||||
commands :: Map.Map String (CommandInfo m),
|
commands :: Map.Map String (CommandInfo m),
|
||||||
@@ -22,6 +24,7 @@ data CommandEnv m = CommandEnv {
|
|||||||
mkCommandEnv cmds = CommandEnv cmds Map.empty Map.empty
|
mkCommandEnv cmds = CommandEnv cmds Map.empty Map.empty
|
||||||
|
|
||||||
--interpretCommandLine :: CommandEnv -> String -> SIO ()
|
--interpretCommandLine :: CommandEnv -> String -> SIO ()
|
||||||
|
interpretCommandLine :: (Fail.MonadFail m, Output m, TypeCheckArg m) => CommandEnv m -> String -> m ()
|
||||||
interpretCommandLine env line =
|
interpretCommandLine env line =
|
||||||
case readCommandLine line of
|
case readCommandLine line of
|
||||||
Just [] -> return ()
|
Just [] -> return ()
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ import GF.Grammar.Parser (runP, pExp)
|
|||||||
import GF.Grammar.ShowTerm
|
import GF.Grammar.ShowTerm
|
||||||
import GF.Grammar.Lookup (allOpers,allOpersTo)
|
import GF.Grammar.Lookup (allOpers,allOpersTo)
|
||||||
import GF.Compile.Rename(renameSourceTerm)
|
import GF.Compile.Rename(renameSourceTerm)
|
||||||
import qualified GF.Compile.Compute.ConcreteNew as CN(normalForm,resourceValues)
|
import GF.Compile.Compute.Concrete(normalForm,resourceValues)
|
||||||
import GF.Compile.TypeCheck.RConcrete as TC(inferLType,ppType)
|
import GF.Compile.TypeCheck.Concrete as TC(inferLType,ppType)
|
||||||
import GF.Infra.Dependencies(depGraph)
|
import GF.Infra.Dependencies(depGraph)
|
||||||
import GF.Infra.CheckM(runCheck)
|
import GF.Infra.CheckM(runCheck)
|
||||||
|
|
||||||
@@ -259,7 +259,7 @@ checkComputeTerm os sgr t =
|
|||||||
((t,_),_) <- runCheck $ do t <- renameSourceTerm sgr mo t
|
((t,_),_) <- runCheck $ do t <- renameSourceTerm sgr mo t
|
||||||
inferLType sgr [] t
|
inferLType sgr [] t
|
||||||
let opts = modifyFlags (\fs->fs{optTrace=isOpt "trace" os})
|
let opts = modifyFlags (\fs->fs{optTrace=isOpt "trace" os})
|
||||||
t1 = CN.normalForm (CN.resourceValues opts sgr) (L NoLoc identW) t
|
t1 = normalForm (resourceValues opts sgr) (L NoLoc identW) t
|
||||||
t2 = evalStr t1
|
t2 = evalStr t1
|
||||||
checkPredefError t2
|
checkPredefError t2
|
||||||
where
|
where
|
||||||
|
|||||||
@@ -27,9 +27,9 @@ import GF.Infra.Ident
|
|||||||
import GF.Infra.Option
|
import GF.Infra.Option
|
||||||
|
|
||||||
import GF.Compile.TypeCheck.Abstract
|
import GF.Compile.TypeCheck.Abstract
|
||||||
import GF.Compile.TypeCheck.RConcrete
|
import GF.Compile.TypeCheck.Concrete(computeLType,checkLType,inferLType,ppType)
|
||||||
import qualified GF.Compile.TypeCheck.ConcreteNew as CN
|
import qualified GF.Compile.TypeCheck.ConcreteNew as CN(checkLType,inferLType)
|
||||||
import qualified GF.Compile.Compute.ConcreteNew as CN
|
import qualified GF.Compile.Compute.Concrete as CN(normalForm,resourceValues)
|
||||||
|
|
||||||
import GF.Grammar
|
import GF.Grammar
|
||||||
import GF.Grammar.Lexer
|
import GF.Grammar.Lexer
|
||||||
@@ -270,7 +270,7 @@ checkInfo opts cwd sgr (m,mo) c info = checkInModule cwd mo NoLoc empty $ do
|
|||||||
chIn loc cat = checkInModule cwd mo loc ("Happened in" <+> cat <+> c)
|
chIn loc cat = checkInModule cwd mo loc ("Happened in" <+> cat <+> c)
|
||||||
|
|
||||||
mkPar (f,co) = do
|
mkPar (f,co) = do
|
||||||
vs <- liftM combinations $ mapM (\(_,_,ty) -> allParamValues gr ty) co
|
vs <- liftM sequence $ mapM (\(_,_,ty) -> allParamValues gr ty) co
|
||||||
return $ map (mkApp (QC (m,f))) vs
|
return $ map (mkApp (QC (m,f))) vs
|
||||||
|
|
||||||
checkUniq xss = case xss of
|
checkUniq xss = case xss of
|
||||||
|
|||||||
@@ -1,143 +0,0 @@
|
|||||||
----------------------------------------------------------------------
|
|
||||||
-- |
|
|
||||||
-- Module : AppPredefined
|
|
||||||
-- Maintainer : AR
|
|
||||||
-- Stability : (stable)
|
|
||||||
-- Portability : (portable)
|
|
||||||
--
|
|
||||||
-- > CVS $Date: 2005/10/06 14:21:34 $
|
|
||||||
-- > CVS $Author: aarne $
|
|
||||||
-- > CVS $Revision: 1.13 $
|
|
||||||
--
|
|
||||||
-- Predefined function type signatures and definitions.
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
module GF.Compile.Compute.AppPredefined ({-
|
|
||||||
isInPredefined, typPredefined, arrityPredefined, predefModInfo, appPredefined-}
|
|
||||||
) where
|
|
||||||
{-
|
|
||||||
import GF.Compile.TypeCheck.Primitives
|
|
||||||
import GF.Infra.Option
|
|
||||||
import GF.Data.Operations
|
|
||||||
import GF.Grammar
|
|
||||||
import GF.Grammar.Predef
|
|
||||||
|
|
||||||
import qualified Data.Map as Map
|
|
||||||
import GF.Text.Pretty
|
|
||||||
import Data.Char (isUpper,toUpper,toLower)
|
|
||||||
|
|
||||||
-- predefined function type signatures and definitions. AR 12/3/2003.
|
|
||||||
|
|
||||||
isInPredefined :: Ident -> Bool
|
|
||||||
isInPredefined f = Map.member f primitives
|
|
||||||
|
|
||||||
arrityPredefined :: Ident -> Maybe Int
|
|
||||||
arrityPredefined f = do ty <- typPredefined f
|
|
||||||
let (ctxt,_) = typeFormCnc ty
|
|
||||||
return (length ctxt)
|
|
||||||
|
|
||||||
predefModInfo :: SourceModInfo
|
|
||||||
predefModInfo = ModInfo MTResource MSComplete noOptions [] Nothing [] [] "Predef.gf" Nothing primitives
|
|
||||||
|
|
||||||
appPredefined :: Term -> Err (Term,Bool)
|
|
||||||
appPredefined t = case t of
|
|
||||||
App f x0 -> do
|
|
||||||
(x,_) <- appPredefined x0
|
|
||||||
case f of
|
|
||||||
-- one-place functions
|
|
||||||
Q (mod,f) | mod == cPredef ->
|
|
||||||
case x of
|
|
||||||
(K s) | f == cLength -> retb $ EInt $ length s
|
|
||||||
(K s) | f == cIsUpper -> retb $ if (all isUpper s) then predefTrue else predefFalse
|
|
||||||
(K s) | f == cToUpper -> retb $ K $ map toUpper s
|
|
||||||
(K s) | f == cToLower -> retb $ K $ map toLower s
|
|
||||||
(K s) | f == cError -> retb $ Error s
|
|
||||||
|
|
||||||
_ -> retb t
|
|
||||||
|
|
||||||
-- two-place functions
|
|
||||||
App (Q (mod,f)) z0 | mod == cPredef -> do
|
|
||||||
(z,_) <- appPredefined z0
|
|
||||||
case (norm z, norm x) of
|
|
||||||
(EInt i, K s) | f == cDrop -> retb $ K (drop i s)
|
|
||||||
(EInt i, K s) | f == cTake -> retb $ K (take i s)
|
|
||||||
(EInt i, K s) | f == cTk -> retb $ K (take (max 0 (length s - i)) s)
|
|
||||||
(EInt i, K s) | f == cDp -> retb $ K (drop (max 0 (length s - i)) s)
|
|
||||||
(K s, K t) | f == cEqStr -> retb $ if s == t then predefTrue else predefFalse
|
|
||||||
(K s, K t) | f == cOccur -> retb $ if substring s t then predefTrue else predefFalse
|
|
||||||
(K s, K t) | f == cOccurs -> retb $ if any (flip elem t) s then predefTrue else predefFalse
|
|
||||||
(EInt i, EInt j) | f == cEqInt -> retb $ if i==j then predefTrue else predefFalse
|
|
||||||
(EInt i, EInt j) | f == cLessInt -> retb $ if i<j then predefTrue else predefFalse
|
|
||||||
(EInt i, EInt j) | f == cPlus -> retb $ EInt $ i+j
|
|
||||||
(_, t) | f == cShow && notVar t -> retb $ foldrC $ map K $ words $ render (ppTerm Unqualified 0 t)
|
|
||||||
(_, K s) | f == cRead -> retb $ Cn (identS s) --- because of K, only works for atomic tags
|
|
||||||
(_, t) | f == cToStr -> trm2str t >>= retb
|
|
||||||
_ -> retb t ---- prtBad "cannot compute predefined" t
|
|
||||||
|
|
||||||
-- three-place functions
|
|
||||||
App (App (Q (mod,f)) z0) y0 | mod == cPredef -> do
|
|
||||||
(y,_) <- appPredefined y0
|
|
||||||
(z,_) <- appPredefined z0
|
|
||||||
case (z, y, x) of
|
|
||||||
(ty,op,t) | f == cMapStr -> retf $ mapStr ty op t
|
|
||||||
_ | f == cEqVal && notVar y && notVar x -> retb $ if y==x then predefTrue else predefFalse
|
|
||||||
_ -> retb t ---- prtBad "cannot compute predefined" t
|
|
||||||
|
|
||||||
_ -> retb t ---- prtBad "cannot compute predefined" t
|
|
||||||
_ -> retb t
|
|
||||||
---- should really check the absence of arg variables
|
|
||||||
where
|
|
||||||
retb t = return (retc t,True) -- no further computing needed
|
|
||||||
retf t = return (retc t,False) -- must be computed further
|
|
||||||
retc t = case t of
|
|
||||||
K [] -> t
|
|
||||||
K s -> foldr1 C (map K (words s))
|
|
||||||
_ -> t
|
|
||||||
norm t = case t of
|
|
||||||
Empty -> K []
|
|
||||||
C u v -> case (norm u,norm v) of
|
|
||||||
(K x,K y) -> K (x +++ y)
|
|
||||||
_ -> t
|
|
||||||
_ -> t
|
|
||||||
notVar t = case t of
|
|
||||||
Vr _ -> False
|
|
||||||
App f a -> notVar f && notVar a
|
|
||||||
_ -> True ---- would need to check that t is a value
|
|
||||||
foldrC ts = if null ts then Empty else foldr1 C ts
|
|
||||||
|
|
||||||
-- read makes variables into constants
|
|
||||||
|
|
||||||
predefTrue = QC (cPredef,cPTrue)
|
|
||||||
predefFalse = QC (cPredef,cPFalse)
|
|
||||||
|
|
||||||
substring :: String -> String -> Bool
|
|
||||||
substring s t = case (s,t) of
|
|
||||||
(c:cs, d:ds) -> (c == d && substring cs ds) || substring s ds
|
|
||||||
([],_) -> True
|
|
||||||
_ -> False
|
|
||||||
|
|
||||||
trm2str :: Term -> Err Term
|
|
||||||
trm2str t = case t of
|
|
||||||
R ((_,(_,s)):_) -> trm2str s
|
|
||||||
T _ ((_,s):_) -> trm2str s
|
|
||||||
V _ (s:_) -> trm2str s
|
|
||||||
C _ _ -> return $ t
|
|
||||||
K _ -> return $ t
|
|
||||||
S c _ -> trm2str c
|
|
||||||
Empty -> return $ t
|
|
||||||
_ -> Bad (render (text "cannot get Str from term" <+> ppTerm Unqualified 0 t))
|
|
||||||
|
|
||||||
-- simultaneous recursion on type and term: type arg is essential!
|
|
||||||
-- But simplify the task by assuming records are type-annotated
|
|
||||||
-- (this has been done in type checking)
|
|
||||||
mapStr :: Type -> Term -> Term -> Term
|
|
||||||
mapStr ty f t = case (ty,t) of
|
|
||||||
_ | elem ty [typeStr,typeTok] -> App f t
|
|
||||||
(_, R ts) -> R [(l,mapField v) | (l,v) <- ts]
|
|
||||||
(Table a b,T ti cs) -> T ti [(p,mapStr b f v) | (p,v) <- cs]
|
|
||||||
_ -> t
|
|
||||||
where
|
|
||||||
mapField (mty,te) = case mty of
|
|
||||||
Just ty -> (mty,mapStr ty f te)
|
|
||||||
_ -> (mty,te)
|
|
||||||
-}
|
|
||||||
@@ -1,3 +1,590 @@
|
|||||||
module GF.Compile.Compute.Concrete{-(module M)-} where
|
-- | Functions for computing the values of terms in the concrete syntax, in
|
||||||
--import GF.Compile.Compute.ConcreteLazy as M -- New
|
-- | preparation for PMCFG generation.
|
||||||
--import GF.Compile.Compute.ConcreteStrict as M -- Old, inefficient
|
module GF.Compile.Compute.Concrete
|
||||||
|
(GlobalEnv, GLocation, resourceValues, geLoc, geGrammar,
|
||||||
|
normalForm,
|
||||||
|
Value(..), Bind(..), Env, value2term, eval, vapply
|
||||||
|
) where
|
||||||
|
import Prelude hiding ((<>)) -- GHC 8.4.1 clash with Text.PrettyPrint
|
||||||
|
|
||||||
|
import GF.Grammar hiding (Env, VGen, VApp, VRecType)
|
||||||
|
import GF.Grammar.Lookup(lookupResDefLoc,allParamValues)
|
||||||
|
import GF.Grammar.Predef(cPredef,cErrorType,cTok,cStr,cTrace,cPBool)
|
||||||
|
import GF.Grammar.PatternMatch(matchPattern,measurePatt)
|
||||||
|
import GF.Grammar.Lockfield(isLockLabel,lockRecType) --unlockRecord,lockLabel
|
||||||
|
import GF.Compile.Compute.Value hiding (Error)
|
||||||
|
import GF.Compile.Compute.Predef(predef,predefName,delta)
|
||||||
|
import GF.Data.Str(Str,glueStr,str2strings,str,sstr,plusStr,strTok)
|
||||||
|
import GF.Data.Operations(Err,err,errIn,maybeErr,mapPairsM)
|
||||||
|
import GF.Data.Utilities(mapFst,mapSnd)
|
||||||
|
import GF.Infra.Option
|
||||||
|
import Control.Monad(ap,liftM,liftM2) -- ,unless,mplus
|
||||||
|
import Data.List (findIndex,intersect,nub,elemIndex,(\\)) --,isInfixOf
|
||||||
|
--import Data.Char (isUpper,toUpper,toLower)
|
||||||
|
import GF.Text.Pretty
|
||||||
|
import qualified Data.Map as Map
|
||||||
|
import Debug.Trace(trace)
|
||||||
|
|
||||||
|
-- * Main entry points
|
||||||
|
|
||||||
|
normalForm :: GlobalEnv -> L Ident -> Term -> Term
|
||||||
|
normalForm (GE gr rv opts _) loc = err (bugloc loc) id . nfx (GE gr rv opts loc)
|
||||||
|
|
||||||
|
nfx :: GlobalEnv -> Term -> Err Term
|
||||||
|
nfx env@(GE _ _ _ loc) t = do
|
||||||
|
v <- eval env [] t
|
||||||
|
return (value2term loc [] v)
|
||||||
|
-- Old value2term error message:
|
||||||
|
-- Left i -> fail ("variable #"++show i++" is out of scope")
|
||||||
|
|
||||||
|
eval :: GlobalEnv -> Env -> Term -> Err Value
|
||||||
|
eval (GE gr rvs opts loc) env t = ($ (map snd env)) # value cenv t
|
||||||
|
where
|
||||||
|
cenv = CE gr rvs opts loc (map fst env)
|
||||||
|
|
||||||
|
--apply env = apply' env
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- * Environments
|
||||||
|
|
||||||
|
type ResourceValues = Map.Map ModuleName (Map.Map Ident (Err Value))
|
||||||
|
|
||||||
|
data GlobalEnv = GE Grammar ResourceValues Options GLocation
|
||||||
|
data CompleteEnv = CE {srcgr::Grammar,rvs::ResourceValues,
|
||||||
|
opts::Options,
|
||||||
|
gloc::GLocation,local::LocalScope}
|
||||||
|
type GLocation = L Ident
|
||||||
|
type LocalScope = [Ident]
|
||||||
|
type Stack = [Value]
|
||||||
|
type OpenValue = Stack->Value
|
||||||
|
|
||||||
|
geLoc (GE _ _ _ loc) = loc
|
||||||
|
geGrammar (GE gr _ _ _) = gr
|
||||||
|
|
||||||
|
ext b env = env{local=b:local env}
|
||||||
|
extend bs env = env{local=bs++local env}
|
||||||
|
global env = GE (srcgr env) (rvs env) (opts env) (gloc env)
|
||||||
|
|
||||||
|
var :: CompleteEnv -> Ident -> Err OpenValue
|
||||||
|
var env x = maybe unbound pick' (elemIndex x (local env))
|
||||||
|
where
|
||||||
|
unbound = fail ("Unknown variable: "++showIdent x)
|
||||||
|
pick' i = return $ \ vs -> maybe (err i vs) ok (pick i vs)
|
||||||
|
err i vs = bug $ "Stack problem: "++showIdent x++": "
|
||||||
|
++unwords (map showIdent (local env))
|
||||||
|
++" => "++show (i,length vs)
|
||||||
|
ok v = --trace ("var "++show x++" = "++show v) $
|
||||||
|
v
|
||||||
|
|
||||||
|
pick :: Int -> Stack -> Maybe Value
|
||||||
|
pick 0 (v:_) = Just v
|
||||||
|
pick i (_:vs) = pick (i-1) vs
|
||||||
|
pick i vs = Nothing -- bug $ "pick "++show (i,vs)
|
||||||
|
|
||||||
|
resource env (m,c) =
|
||||||
|
-- err bug id $
|
||||||
|
if isPredefCat c
|
||||||
|
then value0 env =<< lockRecType c defLinType -- hmm
|
||||||
|
else maybe e id $ Map.lookup c =<< Map.lookup m (rvs env)
|
||||||
|
where e = fail $ "Not found: "++render m++"."++showIdent c
|
||||||
|
|
||||||
|
-- | Convert operators once, not every time they are looked up
|
||||||
|
resourceValues :: Options -> SourceGrammar -> GlobalEnv
|
||||||
|
resourceValues opts gr = env
|
||||||
|
where
|
||||||
|
env = GE gr rvs opts (L NoLoc identW)
|
||||||
|
rvs = Map.mapWithKey moduleResources (moduleMap gr)
|
||||||
|
moduleResources m = Map.mapWithKey (moduleResource m) . jments
|
||||||
|
moduleResource m c _info = do L l t <- lookupResDefLoc gr (m,c)
|
||||||
|
let loc = L l c
|
||||||
|
qloc = L l (Q (m,c))
|
||||||
|
eval (GE gr rvs opts loc) [] (traceRes qloc t)
|
||||||
|
|
||||||
|
traceRes = if flag optTrace opts
|
||||||
|
then traceResource
|
||||||
|
else const id
|
||||||
|
|
||||||
|
-- * Tracing
|
||||||
|
|
||||||
|
-- | Insert a call to the trace function under the top-level lambdas
|
||||||
|
traceResource (L l q) t =
|
||||||
|
case termFormCnc t of
|
||||||
|
(abs,body) -> mkAbs abs (mkApp traceQ [args,body])
|
||||||
|
where
|
||||||
|
args = R $ tuple2record (K lstr:[Vr x|(bt,x)<-abs,bt==Explicit])
|
||||||
|
lstr = render (l<>":"<>ppTerm Qualified 0 q)
|
||||||
|
traceQ = Q (cPredef,cTrace)
|
||||||
|
|
||||||
|
-- * Computing values
|
||||||
|
|
||||||
|
-- | Computing the value of a top-level term
|
||||||
|
value0 :: CompleteEnv -> Term -> Err Value
|
||||||
|
value0 env = eval (global env) []
|
||||||
|
|
||||||
|
-- | Computing the value of a term
|
||||||
|
value :: CompleteEnv -> Term -> Err OpenValue
|
||||||
|
value env t0 =
|
||||||
|
-- Each terms is traversed only once by this function, using only statically
|
||||||
|
-- available information. Notably, the values of lambda bound variables
|
||||||
|
-- will be unknown during the term traversal phase.
|
||||||
|
-- The result is an OpenValue, which is a function that may be applied many
|
||||||
|
-- times to different dynamic values, but without the term traversal overhead
|
||||||
|
-- and without recomputing other statically known information.
|
||||||
|
-- For this to work, there should be no recursive calls under lambdas here.
|
||||||
|
-- Whenever we need to construct the OpenValue function with an explicit
|
||||||
|
-- lambda, we have to lift the recursive calls outside the lambda.
|
||||||
|
-- (See e.g. the rules for Let, Prod and Abs)
|
||||||
|
{-
|
||||||
|
trace (render $ text "value"<+>sep [ppL (gloc env)<>text ":",
|
||||||
|
brackets (fsep (map ppIdent (local env))),
|
||||||
|
ppTerm Unqualified 10 t0]) $
|
||||||
|
--}
|
||||||
|
errIn (render t0) $
|
||||||
|
case t0 of
|
||||||
|
Vr x -> var env x
|
||||||
|
Q x@(m,f)
|
||||||
|
| m == cPredef -> if f==cErrorType -- to be removed
|
||||||
|
then let p = identS "P"
|
||||||
|
in const # value0 env (mkProd [(Implicit,p,typeType)] (Vr p) [])
|
||||||
|
else if f==cPBool
|
||||||
|
then const # resource env x
|
||||||
|
else const . flip VApp [] # predef f
|
||||||
|
| otherwise -> const # resource env x --valueResDef (fst env) x
|
||||||
|
QC x -> return $ const (VCApp x [])
|
||||||
|
App e1 e2 -> apply' env e1 . (:[]) =<< value env e2
|
||||||
|
Let (x,(oty,t)) body -> do vb <- value (ext x env) body
|
||||||
|
vt <- value env t
|
||||||
|
return $ \ vs -> vb (vt vs:vs)
|
||||||
|
Meta i -> return $ \ vs -> VMeta i (zip (local env) vs) []
|
||||||
|
Prod bt x t1 t2 ->
|
||||||
|
do vt1 <- value env t1
|
||||||
|
vt2 <- value (ext x env) t2
|
||||||
|
return $ \ vs -> VProd bt (vt1 vs) x $ Bind $ \ vx -> vt2 (vx:vs)
|
||||||
|
Abs bt x t -> do vt <- value (ext x env) t
|
||||||
|
return $ VAbs bt x . Bind . \ vs vx -> vt (vx:vs)
|
||||||
|
EInt n -> return $ const (VInt n)
|
||||||
|
EFloat f -> return $ const (VFloat f)
|
||||||
|
K s -> return $ const (VString s)
|
||||||
|
Empty -> return $ const (VString "")
|
||||||
|
Sort s | s == cTok -> return $ const (VSort cStr) -- to be removed
|
||||||
|
| otherwise -> return $ const (VSort s)
|
||||||
|
ImplArg t -> (VImplArg.) # value env t
|
||||||
|
Table p res -> liftM2 VTblType # value env p <# value env res
|
||||||
|
RecType rs -> do lovs <- mapPairsM (value env) rs
|
||||||
|
return $ \vs->VRecType $ mapSnd ($vs) lovs
|
||||||
|
t@(ExtR t1 t2) -> ((extR t.)# both id) # both (value env) (t1,t2)
|
||||||
|
FV ts -> ((vfv .) # sequence) # mapM (value env) ts
|
||||||
|
R as -> do lovs <- mapPairsM (value env.snd) as
|
||||||
|
return $ \ vs->VRec $ mapSnd ($vs) lovs
|
||||||
|
T i cs -> valueTable env i cs
|
||||||
|
V ty ts -> do pvs <- paramValues env ty
|
||||||
|
((VV ty pvs .) . sequence) # mapM (value env) ts
|
||||||
|
C t1 t2 -> ((ok2p vconcat.) # both id) # both (value env) (t1,t2)
|
||||||
|
S t1 t2 -> ((select env.) # both id) # both (value env) (t1,t2)
|
||||||
|
P t l -> --maybe (bug $ "project "++show l++" from "++show v) id $
|
||||||
|
do ov <- value env t
|
||||||
|
return $ \ vs -> let v = ov vs
|
||||||
|
in maybe (VP v l) id (proj l v)
|
||||||
|
Alts t tts -> (\v vts -> VAlts # v <# mapM (both id) vts) # value env t <# mapM (both (value env)) tts
|
||||||
|
Strs ts -> ((VStrs.) # sequence) # mapM (value env) ts
|
||||||
|
Glue t1 t2 -> ((ok2p (glue env).) # both id) # both (value env) (t1,t2)
|
||||||
|
ELin c r -> (unlockVRec (gloc env) c.) # value env r
|
||||||
|
EPatt p -> return $ const (VPatt p) -- hmm
|
||||||
|
EPattType ty -> do vt <- value env ty
|
||||||
|
return (VPattType . vt)
|
||||||
|
Typed t ty -> value env t
|
||||||
|
t -> fail.render $ "value"<+>ppTerm Unqualified 10 t $$ show t
|
||||||
|
|
||||||
|
vconcat vv@(v1,v2) =
|
||||||
|
case vv of
|
||||||
|
(VString "",_) -> v2
|
||||||
|
(_,VString "") -> v1
|
||||||
|
(VApp NonExist _,_) -> v1
|
||||||
|
(_,VApp NonExist _) -> v2
|
||||||
|
_ -> VC v1 v2
|
||||||
|
|
||||||
|
proj l v | isLockLabel l = return (VRec [])
|
||||||
|
---- a workaround 18/2/2005: take this away and find the reason
|
||||||
|
---- why earlier compilation destroys the lock field
|
||||||
|
proj l v =
|
||||||
|
case v of
|
||||||
|
VFV vs -> liftM vfv (mapM (proj l) vs)
|
||||||
|
VRec rs -> lookup l rs
|
||||||
|
-- VExtR v1 v2 -> proj l v2 `mplus` proj l v1 -- hmm
|
||||||
|
VS (VV pty pvs rs) v2 -> flip VS v2 . VV pty pvs # mapM (proj l) rs
|
||||||
|
_ -> return (ok1 VP v l)
|
||||||
|
|
||||||
|
ok1 f v1@(VError {}) _ = v1
|
||||||
|
ok1 f v1 v2 = f v1 v2
|
||||||
|
|
||||||
|
ok2 f v1@(VError {}) _ = v1
|
||||||
|
ok2 f _ v2@(VError {}) = v2
|
||||||
|
ok2 f v1 v2 = f v1 v2
|
||||||
|
|
||||||
|
ok2p f (v1@VError {},_) = v1
|
||||||
|
ok2p f (_,v2@VError {}) = v2
|
||||||
|
ok2p f vv = f vv
|
||||||
|
|
||||||
|
unlockVRec loc c0 v0 = v0
|
||||||
|
{-
|
||||||
|
unlockVRec loc c0 v0 = unlockVRec' c0 v0
|
||||||
|
where
|
||||||
|
unlockVRec' ::Ident -> Value -> Value
|
||||||
|
unlockVRec' c v =
|
||||||
|
case v of
|
||||||
|
-- VClosure env t -> err bug (VClosure env) (unlockRecord c t)
|
||||||
|
VAbs bt x (Bind f) -> VAbs bt x (Bind $ \ v -> unlockVRec' c (f v))
|
||||||
|
VRec rs -> plusVRec rs lock
|
||||||
|
-- _ -> VExtR v (VRec lock) -- hmm
|
||||||
|
_ -> {-trace (render $ ppL loc $ "unlock non-record "++show v0)-} v -- hmm
|
||||||
|
-- _ -> bugloc loc $ "unlock non-record "++show v0
|
||||||
|
where
|
||||||
|
lock = [(lockLabel c,VRec [])]
|
||||||
|
-}
|
||||||
|
|
||||||
|
-- suspicious, but backwards compatible
|
||||||
|
plusVRec rs1 rs2 = VRec ([(l,v)|(l,v)<-rs1,l `notElem` ls2] ++ rs2)
|
||||||
|
where ls2 = map fst rs2
|
||||||
|
|
||||||
|
extR t vv =
|
||||||
|
case vv of
|
||||||
|
(VFV vs,v2) -> vfv [extR t (v1,v2)|v1<-vs]
|
||||||
|
(v1,VFV vs) -> vfv [extR t (v1,v2)|v2<-vs]
|
||||||
|
(VRecType rs1, VRecType rs2) ->
|
||||||
|
case intersect (map fst rs1) (map fst rs2) of
|
||||||
|
[] -> VRecType (rs1 ++ rs2)
|
||||||
|
ls -> error $ "clash"<+>show ls
|
||||||
|
(VRec rs1, VRec rs2) -> plusVRec rs1 rs2
|
||||||
|
(v1 , VRec [(l,_)]) | isLockLabel l -> v1 -- hmm
|
||||||
|
(VS (VV t pvs vs) s,v2) -> VS (VV t pvs [extR t (v1,v2)|v1<-vs]) s
|
||||||
|
-- (v1,v2) -> ok2 VExtR v1 v2 -- hmm
|
||||||
|
(v1,v2) -> error $ "not records" $$ show v1 $$ show v2
|
||||||
|
where
|
||||||
|
error explain = ppbug $ "The term" <+> t
|
||||||
|
<+> "is not reducible" $$ explain
|
||||||
|
|
||||||
|
glue env (v1,v2) = glu v1 v2
|
||||||
|
where
|
||||||
|
glu v1 v2 =
|
||||||
|
case (v1,v2) of
|
||||||
|
(VFV vs,v2) -> vfv [glu v1 v2|v1<-vs]
|
||||||
|
(v1,VFV vs) -> vfv [glu v1 v2|v2<-vs]
|
||||||
|
(VString s1,VString s2) -> VString (s1++s2)
|
||||||
|
(v1,VAlts d vs) -> VAlts (glx d) [(glx v,c) | (v,c) <- vs]
|
||||||
|
where glx v2 = glu v1 v2
|
||||||
|
(v1@(VAlts {}),v2) ->
|
||||||
|
--err (const (ok2 VGlue v1 v2)) id $
|
||||||
|
err bug id $
|
||||||
|
do y' <- strsFromValue v2
|
||||||
|
x' <- strsFromValue v1
|
||||||
|
return $ vfv [foldr1 VC (map VString (str2strings (glueStr v u))) | v <- x', u <- y']
|
||||||
|
(VC va vb,v2) -> VC va (glu vb v2)
|
||||||
|
(v1,VC va vb) -> VC (glu v1 va) vb
|
||||||
|
(VS (VV ty pvs vs) vb,v2) -> VS (VV ty pvs [glu v v2|v<-vs]) vb
|
||||||
|
(v1,VS (VV ty pvs vs) vb) -> VS (VV ty pvs [glu v1 v|v<-vs]) vb
|
||||||
|
(v1@(VApp NonExist _),_) -> v1
|
||||||
|
(_,v2@(VApp NonExist _)) -> v2
|
||||||
|
-- (v1,v2) -> ok2 VGlue v1 v2
|
||||||
|
(v1,v2) -> if flag optPlusAsBind (opts env)
|
||||||
|
then VC v1 (VC (VApp BIND []) v2)
|
||||||
|
else let loc = gloc env
|
||||||
|
vt v = value2term loc (local env) v
|
||||||
|
-- Old value2term error message:
|
||||||
|
-- Left i -> Error ('#':show i)
|
||||||
|
originalMsg = render $ ppL loc (hang "unsupported token gluing" 4
|
||||||
|
(Glue (vt v1) (vt v2)))
|
||||||
|
term = render $ pp $ Glue (vt v1) (vt v2)
|
||||||
|
in error $ unlines
|
||||||
|
[originalMsg
|
||||||
|
,""
|
||||||
|
,"There was a problem in the expression `"++term++"`, either:"
|
||||||
|
,"1) You are trying to use + on runtime arguments, possibly via an oper."
|
||||||
|
,"2) One of the arguments in `"++term++"` is a bound variable from pattern matching a string, but the cases are non-exhaustive."
|
||||||
|
,"For more help see https://github.com/GrammaticalFramework/gf-core/tree/master/doc/errors/gluing.md"
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
-- | to get a string from a value that represents a sequence of terminals
|
||||||
|
strsFromValue :: Value -> Err [Str]
|
||||||
|
strsFromValue t = case t of
|
||||||
|
VString s -> return [str s]
|
||||||
|
VC s t -> do
|
||||||
|
s' <- strsFromValue s
|
||||||
|
t' <- strsFromValue t
|
||||||
|
return [plusStr x y | x <- s', y <- t']
|
||||||
|
{-
|
||||||
|
VGlue s t -> do
|
||||||
|
s' <- strsFromValue s
|
||||||
|
t' <- strsFromValue t
|
||||||
|
return [glueStr x y | x <- s', y <- t']
|
||||||
|
-}
|
||||||
|
VAlts d vs -> do
|
||||||
|
d0 <- strsFromValue d
|
||||||
|
v0 <- mapM (strsFromValue . fst) vs
|
||||||
|
c0 <- mapM (strsFromValue . snd) vs
|
||||||
|
--let vs' = zip v0 c0
|
||||||
|
return [strTok (str2strings def) vars |
|
||||||
|
def <- d0,
|
||||||
|
vars <- [[(str2strings v, map sstr c) | (v,c) <- zip vv c0] |
|
||||||
|
vv <- sequence v0]
|
||||||
|
]
|
||||||
|
VFV ts -> concat # mapM strsFromValue ts
|
||||||
|
VStrs ts -> concat # mapM strsFromValue ts
|
||||||
|
|
||||||
|
_ -> fail ("cannot get Str from value " ++ show t)
|
||||||
|
|
||||||
|
vfv vs = case nub vs of
|
||||||
|
[v] -> v
|
||||||
|
vs -> VFV vs
|
||||||
|
|
||||||
|
select env vv =
|
||||||
|
case vv of
|
||||||
|
(v1,VFV vs) -> vfv [select env (v1,v2)|v2<-vs]
|
||||||
|
(VFV vs,v2) -> vfv [select env (v1,v2)|v1<-vs]
|
||||||
|
(v1@(VV pty vs rs),v2) ->
|
||||||
|
err (const (VS v1 v2)) id $
|
||||||
|
do --ats <- allParamValues (srcgr env) pty
|
||||||
|
--let vs = map (value0 env) ats
|
||||||
|
i <- maybeErr "no match" $ findIndex (==v2) vs
|
||||||
|
return (ix (gloc env) "select" rs i)
|
||||||
|
(VT _ _ [(PW,Bind b)],_) -> {-trace "eliminate wild card table" $-} b []
|
||||||
|
(v1@(VT _ _ cs),v2) ->
|
||||||
|
err (\_->ok2 VS v1 v2) (err bug id . valueMatch env) $
|
||||||
|
match (gloc env) cs v2
|
||||||
|
(VS (VV pty pvs rs) v12,v2) -> VS (VV pty pvs [select env (v11,v2)|v11<-rs]) v12
|
||||||
|
(v1,v2) -> ok2 VS v1 v2
|
||||||
|
|
||||||
|
match loc cs v =
|
||||||
|
err bad return (matchPattern cs (value2term loc [] v))
|
||||||
|
-- Old value2term error message:
|
||||||
|
-- Left i -> bad ("variable #"++show i++" is out of scope")
|
||||||
|
where
|
||||||
|
bad = fail . ("In pattern matching: "++)
|
||||||
|
|
||||||
|
valueMatch :: CompleteEnv -> (Bind Env,Substitution) -> Err Value
|
||||||
|
valueMatch env (Bind f,env') = f # mapPairsM (value0 env) env'
|
||||||
|
|
||||||
|
valueTable :: CompleteEnv -> TInfo -> [Case] -> Err OpenValue
|
||||||
|
valueTable env i cs =
|
||||||
|
case i of
|
||||||
|
TComp ty -> do pvs <- paramValues env ty
|
||||||
|
((VV ty pvs .) # sequence) # mapM (value env.snd) cs
|
||||||
|
_ -> do ty <- getTableType i
|
||||||
|
cs' <- mapM valueCase cs
|
||||||
|
err (dynamic cs' ty) return (convert cs' ty)
|
||||||
|
where
|
||||||
|
dynamic cs' ty _ = cases cs' # value env ty
|
||||||
|
|
||||||
|
cases cs' vty vs = err keep ($vs) (convertv cs' (vty vs))
|
||||||
|
where
|
||||||
|
keep msg = --trace (msg++"\n"++render (ppTerm Unqualified 0 (T i cs))) $
|
||||||
|
VT wild (vty vs) (mapSnd ($vs) cs')
|
||||||
|
|
||||||
|
wild = case i of TWild _ -> True; _ -> False
|
||||||
|
|
||||||
|
convertv cs' vty =
|
||||||
|
convert' cs' =<< paramValues'' env (value2term (gloc env) [] vty)
|
||||||
|
-- Old value2term error message: Left i -> fail ("variable #"++show i++" is out of scope")
|
||||||
|
|
||||||
|
convert cs' ty = convert' cs' =<< paramValues' env ty
|
||||||
|
|
||||||
|
convert' cs' ((pty,vs),pvs) =
|
||||||
|
do sts <- mapM (matchPattern cs') vs
|
||||||
|
return $ \ vs -> VV pty pvs $ map (err bug id . valueMatch env)
|
||||||
|
(mapFst ($vs) sts)
|
||||||
|
|
||||||
|
valueCase (p,t) = do p' <- measurePatt # inlinePattMacro p
|
||||||
|
pvs <- linPattVars p'
|
||||||
|
vt <- value (extend pvs env) t
|
||||||
|
return (p',\vs-> Bind $ \bs-> vt (push' p' bs pvs vs))
|
||||||
|
|
||||||
|
inlinePattMacro p =
|
||||||
|
case p of
|
||||||
|
PM qc -> do r <- resource env qc
|
||||||
|
case r of
|
||||||
|
VPatt p' -> inlinePattMacro p'
|
||||||
|
_ -> ppbug $ hang "Expected pattern macro:" 4
|
||||||
|
(show r)
|
||||||
|
_ -> composPattOp inlinePattMacro p
|
||||||
|
|
||||||
|
|
||||||
|
paramValues env ty = snd # paramValues' env ty
|
||||||
|
|
||||||
|
paramValues' env ty = paramValues'' env =<< nfx (global env) ty
|
||||||
|
|
||||||
|
paramValues'' env pty = do ats <- allParamValues (srcgr env) pty
|
||||||
|
pvs <- mapM (eval (global env) []) ats
|
||||||
|
return ((pty,ats),pvs)
|
||||||
|
|
||||||
|
push' p bs xs = if length bs/=length xs
|
||||||
|
then bug $ "push "++show (p,bs,xs)
|
||||||
|
else push bs xs
|
||||||
|
|
||||||
|
push :: Env -> LocalScope -> Stack -> Stack
|
||||||
|
push bs [] vs = vs
|
||||||
|
push bs (x:xs) vs = maybe err id (lookup x bs):push bs xs vs
|
||||||
|
where err = bug $ "Unbound pattern variable "++showIdent x
|
||||||
|
|
||||||
|
apply' :: CompleteEnv -> Term -> [OpenValue] -> Err OpenValue
|
||||||
|
apply' env t [] = value env t
|
||||||
|
apply' env t vs =
|
||||||
|
case t of
|
||||||
|
QC x -> return $ \ svs -> VCApp x (map ($svs) vs)
|
||||||
|
{-
|
||||||
|
Q x@(m,f) | m==cPredef -> return $
|
||||||
|
let constr = --trace ("predef "++show x) .
|
||||||
|
VApp x
|
||||||
|
in \ svs -> maybe constr id (Map.lookup f predefs)
|
||||||
|
$ map ($svs) vs
|
||||||
|
| otherwise -> do r <- resource env x
|
||||||
|
return $ \ svs -> vapply (gloc env) r (map ($svs) vs)
|
||||||
|
-}
|
||||||
|
App t1 t2 -> apply' env t1 . (:vs) =<< value env t2
|
||||||
|
_ -> do fv <- value env t
|
||||||
|
return $ \ svs -> vapply (gloc env) (fv svs) (map ($svs) vs)
|
||||||
|
|
||||||
|
vapply :: GLocation -> Value -> [Value] -> Value
|
||||||
|
vapply loc v [] = v
|
||||||
|
vapply loc v vs =
|
||||||
|
case v of
|
||||||
|
VError {} -> v
|
||||||
|
-- VClosure env (Abs b x t) -> beta gr env b x t vs
|
||||||
|
VAbs bt _ (Bind f) -> vbeta loc bt f vs
|
||||||
|
VApp pre vs1 -> delta' pre (vs1++vs)
|
||||||
|
where
|
||||||
|
delta' Trace (v1:v2:vs) = let vr = vapply loc v2 vs
|
||||||
|
in vtrace loc v1 vr
|
||||||
|
delta' pre vs = err msg vfv $ mapM (delta pre) (varyList vs)
|
||||||
|
--msg = const (VApp pre (vs1++vs))
|
||||||
|
msg = bug . (("Applying Predef."++showIdent (predefName pre)++": ")++)
|
||||||
|
VS (VV t pvs fs) s -> VS (VV t pvs [vapply loc f vs|f<-fs]) s
|
||||||
|
VFV fs -> vfv [vapply loc f vs|f<-fs]
|
||||||
|
VCApp f vs0 -> VCApp f (vs0++vs)
|
||||||
|
VMeta i env vs0 -> VMeta i env (vs0++vs)
|
||||||
|
VGen i vs0 -> VGen i (vs0++vs)
|
||||||
|
v -> bug $ "vapply "++show v++" "++show vs
|
||||||
|
|
||||||
|
vbeta loc bt f (v:vs) =
|
||||||
|
case (bt,v) of
|
||||||
|
(Implicit,VImplArg v) -> ap v
|
||||||
|
(Explicit, v) -> ap v
|
||||||
|
where
|
||||||
|
ap (VFV avs) = vfv [vapply loc (f v) vs|v<-avs]
|
||||||
|
ap v = vapply loc (f v) vs
|
||||||
|
|
||||||
|
vary (VFV vs) = vs
|
||||||
|
vary v = [v]
|
||||||
|
varyList = mapM vary
|
||||||
|
|
||||||
|
{-
|
||||||
|
beta env b x t (v:vs) =
|
||||||
|
case (b,v) of
|
||||||
|
(Implicit,VImplArg v) -> apply' (ext (x,v) env) t vs
|
||||||
|
(Explicit, v) -> apply' (ext (x,v) env) t vs
|
||||||
|
-}
|
||||||
|
|
||||||
|
vtrace loc arg res = trace (render (hang (pv arg) 4 ("->"<+>pv res))) res
|
||||||
|
where
|
||||||
|
pv v = case v of
|
||||||
|
VRec (f:as) -> hang (pf f) 4 (fsep (map pa as))
|
||||||
|
_ -> ppV v
|
||||||
|
pf (_,VString n) = pp n
|
||||||
|
pf (_,v) = ppV v
|
||||||
|
pa (_,v) = ppV v
|
||||||
|
ppV v = ppTerm Unqualified 10 (value2term' True loc [] v)
|
||||||
|
-- Old value2term error message:
|
||||||
|
-- Left i -> "variable #" <> pp i <+> "is out of scope"
|
||||||
|
|
||||||
|
-- | Convert a value back to a term
|
||||||
|
value2term :: GLocation -> [Ident] -> Value -> Term
|
||||||
|
value2term = value2term' False
|
||||||
|
|
||||||
|
value2term' :: Bool -> p -> [Ident] -> Value -> Term
|
||||||
|
value2term' stop loc xs v0 =
|
||||||
|
case v0 of
|
||||||
|
VApp pre vs -> applyMany (Q (cPredef,predefName pre)) vs
|
||||||
|
VCApp f vs -> applyMany (QC f) vs
|
||||||
|
VGen j vs -> applyMany (var j) vs
|
||||||
|
VMeta j env vs -> applyMany (Meta j) vs
|
||||||
|
VProd bt v x f -> Prod bt x (v2t v) (v2t' x f)
|
||||||
|
VAbs bt x f -> Abs bt x (v2t' x f)
|
||||||
|
VInt n -> EInt n
|
||||||
|
VFloat f -> EFloat f
|
||||||
|
VString s -> if null s then Empty else K s
|
||||||
|
VSort s -> Sort s
|
||||||
|
VImplArg v -> ImplArg (v2t v)
|
||||||
|
VTblType p res -> Table (v2t p) (v2t res)
|
||||||
|
VRecType rs -> RecType [(l, v2t v) | (l,v) <- rs]
|
||||||
|
VRec as -> R [(l, (Nothing, v2t v)) | (l,v) <- as]
|
||||||
|
VV t _ vs -> V t (map v2t vs)
|
||||||
|
VT wild v cs -> T ((if wild then TWild else TTyped) (v2t v)) (map nfcase cs)
|
||||||
|
VFV vs -> FV (map v2t vs)
|
||||||
|
VC v1 v2 -> C (v2t v1) (v2t v2)
|
||||||
|
VS v1 v2 -> S (v2t v1) (v2t v2)
|
||||||
|
VP v l -> P (v2t v) l
|
||||||
|
VPatt p -> EPatt p
|
||||||
|
VPattType v -> EPattType $ v2t v
|
||||||
|
VAlts v vvs -> Alts (v2t v) [(v2t x, v2t y) | (x,y) <- vvs]
|
||||||
|
VStrs vs -> Strs (map v2t vs)
|
||||||
|
-- VGlue v1 v2 -> Glue (v2t v1) (v2t v2)
|
||||||
|
-- VExtR v1 v2 -> ExtR (v2t v1) (v2t v2)
|
||||||
|
VError err -> Error err
|
||||||
|
where
|
||||||
|
applyMany f vs = foldl App f (map v2t vs)
|
||||||
|
v2t = v2txs xs
|
||||||
|
v2txs = value2term' stop loc
|
||||||
|
v2t' x f = v2txs (x:xs) (bind f (gen xs))
|
||||||
|
|
||||||
|
var j
|
||||||
|
| j<length xs = Vr (reverse xs !! j)
|
||||||
|
| otherwise = error ("variable #"++show j++" is out of scope")
|
||||||
|
|
||||||
|
|
||||||
|
pushs xs e = foldr push e xs
|
||||||
|
push x (env,xs) = ((x,gen xs):env,x:xs)
|
||||||
|
gen xs = VGen (length xs) []
|
||||||
|
|
||||||
|
nfcase (p,f) = (,) p (v2txs xs' (bind f env'))
|
||||||
|
where (env',xs') = pushs (pattVars p) ([],xs)
|
||||||
|
|
||||||
|
bind (Bind f) x = if stop
|
||||||
|
then VSort (identS "...") -- hmm
|
||||||
|
else f x
|
||||||
|
|
||||||
|
|
||||||
|
linPattVars p =
|
||||||
|
if null dups
|
||||||
|
then return pvs
|
||||||
|
else fail.render $ hang "Pattern is not linear. All variable names on the left-hand side must be distinct." 4 (ppPatt Unqualified 0 p)
|
||||||
|
where
|
||||||
|
allpvs = allPattVars p
|
||||||
|
pvs = nub allpvs
|
||||||
|
dups = allpvs \\ pvs
|
||||||
|
|
||||||
|
pattVars = nub . allPattVars
|
||||||
|
allPattVars p =
|
||||||
|
case p of
|
||||||
|
PV i -> [i]
|
||||||
|
PAs i p -> i:allPattVars p
|
||||||
|
_ -> collectPattOp allPattVars p
|
||||||
|
|
||||||
|
---
|
||||||
|
ix loc fn xs i =
|
||||||
|
if i<n
|
||||||
|
then xs !! i
|
||||||
|
else bugloc loc $ "(!!): index too large in "++fn++", "++show i++"<"++show n
|
||||||
|
where n = length xs
|
||||||
|
|
||||||
|
infixl 1 #,<# --,@@
|
||||||
|
|
||||||
|
f # x = fmap f x
|
||||||
|
mf <# mx = ap mf mx
|
||||||
|
--m1 @@ m2 = (m1 =<<) . m2
|
||||||
|
|
||||||
|
both f (x,y) = (,) # f x <# f y
|
||||||
|
|
||||||
|
bugloc loc s = ppbug $ ppL loc s
|
||||||
|
|
||||||
|
bug msg = ppbug msg
|
||||||
|
ppbug doc = error $ render $ hang "Internal error in Compute.Concrete:" 4 doc
|
||||||
|
|||||||
@@ -1,580 +0,0 @@
|
|||||||
-- | Functions for computing the values of terms in the concrete syntax, in
|
|
||||||
-- | preparation for PMCFG generation.
|
|
||||||
module GF.Compile.Compute.ConcreteNew
|
|
||||||
(GlobalEnv, GLocation, resourceValues, geLoc, geGrammar,
|
|
||||||
normalForm,
|
|
||||||
Value(..), Bind(..), Env, value2term, eval, vapply
|
|
||||||
) where
|
|
||||||
import Prelude hiding ((<>)) -- GHC 8.4.1 clash with Text.PrettyPrint
|
|
||||||
|
|
||||||
import GF.Grammar hiding (Env, VGen, VApp, VRecType)
|
|
||||||
import GF.Grammar.Lookup(lookupResDefLoc,allParamValues)
|
|
||||||
import GF.Grammar.Predef(cPredef,cErrorType,cTok,cStr,cTrace,cPBool)
|
|
||||||
import GF.Grammar.PatternMatch(matchPattern,measurePatt)
|
|
||||||
import GF.Grammar.Lockfield(isLockLabel,lockRecType) --unlockRecord,lockLabel
|
|
||||||
import GF.Compile.Compute.Value hiding (Error)
|
|
||||||
import GF.Compile.Compute.Predef(predef,predefName,delta)
|
|
||||||
import GF.Data.Str(Str,glueStr,str2strings,str,sstr,plusStr,strTok)
|
|
||||||
import GF.Data.Operations(Err,err,errIn,maybeErr,combinations,mapPairsM)
|
|
||||||
import GF.Data.Utilities(mapFst,mapSnd)
|
|
||||||
import GF.Infra.Option
|
|
||||||
import Control.Monad(ap,liftM,liftM2) -- ,unless,mplus
|
|
||||||
import Data.List (findIndex,intersect,nub,elemIndex,(\\)) --,isInfixOf
|
|
||||||
--import Data.Char (isUpper,toUpper,toLower)
|
|
||||||
import GF.Text.Pretty
|
|
||||||
import qualified Data.Map as Map
|
|
||||||
import Debug.Trace(trace)
|
|
||||||
|
|
||||||
-- * Main entry points
|
|
||||||
|
|
||||||
normalForm :: GlobalEnv -> L Ident -> Term -> Term
|
|
||||||
normalForm (GE gr rv opts _) loc = err (bugloc loc) id . nfx (GE gr rv opts loc)
|
|
||||||
|
|
||||||
nfx env@(GE _ _ _ loc) t = do
|
|
||||||
v <- eval env [] t
|
|
||||||
case value2term loc [] v of
|
|
||||||
Left i -> fail ("variable #"++show i++" is out of scope")
|
|
||||||
Right t -> return t
|
|
||||||
|
|
||||||
eval :: GlobalEnv -> Env -> Term -> Err Value
|
|
||||||
eval (GE gr rvs opts loc) env t = ($ (map snd env)) # value cenv t
|
|
||||||
where
|
|
||||||
cenv = CE gr rvs opts loc (map fst env)
|
|
||||||
|
|
||||||
--apply env = apply' env
|
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
-- * Environments
|
|
||||||
|
|
||||||
type ResourceValues = Map.Map ModuleName (Map.Map Ident (Err Value))
|
|
||||||
|
|
||||||
data GlobalEnv = GE Grammar ResourceValues Options GLocation
|
|
||||||
data CompleteEnv = CE {srcgr::Grammar,rvs::ResourceValues,
|
|
||||||
opts::Options,
|
|
||||||
gloc::GLocation,local::LocalScope}
|
|
||||||
type GLocation = L Ident
|
|
||||||
type LocalScope = [Ident]
|
|
||||||
type Stack = [Value]
|
|
||||||
type OpenValue = Stack->Value
|
|
||||||
|
|
||||||
geLoc (GE _ _ _ loc) = loc
|
|
||||||
geGrammar (GE gr _ _ _) = gr
|
|
||||||
|
|
||||||
ext b env = env{local=b:local env}
|
|
||||||
extend bs env = env{local=bs++local env}
|
|
||||||
global env = GE (srcgr env) (rvs env) (opts env) (gloc env)
|
|
||||||
|
|
||||||
var :: CompleteEnv -> Ident -> Err OpenValue
|
|
||||||
var env x = maybe unbound pick' (elemIndex x (local env))
|
|
||||||
where
|
|
||||||
unbound = fail ("Unknown variable: "++showIdent x)
|
|
||||||
pick' i = return $ \ vs -> maybe (err i vs) ok (pick i vs)
|
|
||||||
err i vs = bug $ "Stack problem: "++showIdent x++": "
|
|
||||||
++unwords (map showIdent (local env))
|
|
||||||
++" => "++show (i,length vs)
|
|
||||||
ok v = --trace ("var "++show x++" = "++show v) $
|
|
||||||
v
|
|
||||||
|
|
||||||
pick :: Int -> Stack -> Maybe Value
|
|
||||||
pick 0 (v:_) = Just v
|
|
||||||
pick i (_:vs) = pick (i-1) vs
|
|
||||||
pick i vs = Nothing -- bug $ "pick "++show (i,vs)
|
|
||||||
|
|
||||||
resource env (m,c) =
|
|
||||||
-- err bug id $
|
|
||||||
if isPredefCat c
|
|
||||||
then value0 env =<< lockRecType c defLinType -- hmm
|
|
||||||
else maybe e id $ Map.lookup c =<< Map.lookup m (rvs env)
|
|
||||||
where e = fail $ "Not found: "++render m++"."++showIdent c
|
|
||||||
|
|
||||||
-- | Convert operators once, not every time they are looked up
|
|
||||||
resourceValues :: Options -> SourceGrammar -> GlobalEnv
|
|
||||||
resourceValues opts gr = env
|
|
||||||
where
|
|
||||||
env = GE gr rvs opts (L NoLoc identW)
|
|
||||||
rvs = Map.mapWithKey moduleResources (moduleMap gr)
|
|
||||||
moduleResources m = Map.mapWithKey (moduleResource m) . jments
|
|
||||||
moduleResource m c _info = do L l t <- lookupResDefLoc gr (m,c)
|
|
||||||
let loc = L l c
|
|
||||||
qloc = L l (Q (m,c))
|
|
||||||
eval (GE gr rvs opts loc) [] (traceRes qloc t)
|
|
||||||
|
|
||||||
traceRes = if flag optTrace opts
|
|
||||||
then traceResource
|
|
||||||
else const id
|
|
||||||
|
|
||||||
-- * Tracing
|
|
||||||
|
|
||||||
-- | Insert a call to the trace function under the top-level lambdas
|
|
||||||
traceResource (L l q) t =
|
|
||||||
case termFormCnc t of
|
|
||||||
(abs,body) -> mkAbs abs (mkApp traceQ [args,body])
|
|
||||||
where
|
|
||||||
args = R $ tuple2record (K lstr:[Vr x|(bt,x)<-abs,bt==Explicit])
|
|
||||||
lstr = render (l<>":"<>ppTerm Qualified 0 q)
|
|
||||||
traceQ = Q (cPredef,cTrace)
|
|
||||||
|
|
||||||
-- * Computing values
|
|
||||||
|
|
||||||
-- | Computing the value of a top-level term
|
|
||||||
value0 :: CompleteEnv -> Term -> Err Value
|
|
||||||
value0 env = eval (global env) []
|
|
||||||
|
|
||||||
-- | Computing the value of a term
|
|
||||||
value :: CompleteEnv -> Term -> Err OpenValue
|
|
||||||
value env t0 =
|
|
||||||
-- Each terms is traversed only once by this function, using only statically
|
|
||||||
-- available information. Notably, the values of lambda bound variables
|
|
||||||
-- will be unknown during the term traversal phase.
|
|
||||||
-- The result is an OpenValue, which is a function that may be applied many
|
|
||||||
-- times to different dynamic values, but without the term traversal overhead
|
|
||||||
-- and without recomputing other statically known information.
|
|
||||||
-- For this to work, there should be no recursive calls under lambdas here.
|
|
||||||
-- Whenever we need to construct the OpenValue function with an explicit
|
|
||||||
-- lambda, we have to lift the recursive calls outside the lambda.
|
|
||||||
-- (See e.g. the rules for Let, Prod and Abs)
|
|
||||||
{-
|
|
||||||
trace (render $ text "value"<+>sep [ppL (gloc env)<>text ":",
|
|
||||||
brackets (fsep (map ppIdent (local env))),
|
|
||||||
ppTerm Unqualified 10 t0]) $
|
|
||||||
--}
|
|
||||||
errIn (render t0) $
|
|
||||||
case t0 of
|
|
||||||
Vr x -> var env x
|
|
||||||
Q x@(m,f)
|
|
||||||
| m == cPredef -> if f==cErrorType -- to be removed
|
|
||||||
then let p = identS "P"
|
|
||||||
in const # value0 env (mkProd [(Implicit,p,typeType)] (Vr p) [])
|
|
||||||
else if f==cPBool
|
|
||||||
then const # resource env x
|
|
||||||
else const . flip VApp [] # predef f
|
|
||||||
| otherwise -> const # resource env x --valueResDef (fst env) x
|
|
||||||
QC x -> return $ const (VCApp x [])
|
|
||||||
App e1 e2 -> apply' env e1 . (:[]) =<< value env e2
|
|
||||||
Let (x,(oty,t)) body -> do vb <- value (ext x env) body
|
|
||||||
vt <- value env t
|
|
||||||
return $ \ vs -> vb (vt vs:vs)
|
|
||||||
Meta i -> return $ \ vs -> VMeta i (zip (local env) vs) []
|
|
||||||
Prod bt x t1 t2 ->
|
|
||||||
do vt1 <- value env t1
|
|
||||||
vt2 <- value (ext x env) t2
|
|
||||||
return $ \ vs -> VProd bt (vt1 vs) x $ Bind $ \ vx -> vt2 (vx:vs)
|
|
||||||
Abs bt x t -> do vt <- value (ext x env) t
|
|
||||||
return $ VAbs bt x . Bind . \ vs vx -> vt (vx:vs)
|
|
||||||
EInt n -> return $ const (VInt n)
|
|
||||||
EFloat f -> return $ const (VFloat f)
|
|
||||||
K s -> return $ const (VString s)
|
|
||||||
Empty -> return $ const (VString "")
|
|
||||||
Sort s | s == cTok -> return $ const (VSort cStr) -- to be removed
|
|
||||||
| otherwise -> return $ const (VSort s)
|
|
||||||
ImplArg t -> (VImplArg.) # value env t
|
|
||||||
Table p res -> liftM2 VTblType # value env p <# value env res
|
|
||||||
RecType rs -> do lovs <- mapPairsM (value env) rs
|
|
||||||
return $ \vs->VRecType $ mapSnd ($vs) lovs
|
|
||||||
t@(ExtR t1 t2) -> ((extR t.)# both id) # both (value env) (t1,t2)
|
|
||||||
FV ts -> ((vfv .) # sequence) # mapM (value env) ts
|
|
||||||
R as -> do lovs <- mapPairsM (value env.snd) as
|
|
||||||
return $ \ vs->VRec $ mapSnd ($vs) lovs
|
|
||||||
T i cs -> valueTable env i cs
|
|
||||||
V ty ts -> do pvs <- paramValues env ty
|
|
||||||
((VV ty pvs .) . sequence) # mapM (value env) ts
|
|
||||||
C t1 t2 -> ((ok2p vconcat.) # both id) # both (value env) (t1,t2)
|
|
||||||
S t1 t2 -> ((select env.) # both id) # both (value env) (t1,t2)
|
|
||||||
P t l -> --maybe (bug $ "project "++show l++" from "++show v) id $
|
|
||||||
do ov <- value env t
|
|
||||||
return $ \ vs -> let v = ov vs
|
|
||||||
in maybe (VP v l) id (proj l v)
|
|
||||||
Alts t tts -> (\v vts -> VAlts # v <# mapM (both id) vts) # value env t <# mapM (both (value env)) tts
|
|
||||||
Strs ts -> ((VStrs.) # sequence) # mapM (value env) ts
|
|
||||||
Glue t1 t2 -> ((ok2p (glue env).) # both id) # both (value env) (t1,t2)
|
|
||||||
ELin c r -> (unlockVRec (gloc env) c.) # value env r
|
|
||||||
EPatt p -> return $ const (VPatt p) -- hmm
|
|
||||||
EPattType ty -> do vt <- value env ty
|
|
||||||
return (VPattType . vt)
|
|
||||||
Typed t ty -> value env t
|
|
||||||
t -> fail.render $ "value"<+>ppTerm Unqualified 10 t $$ show t
|
|
||||||
|
|
||||||
vconcat vv@(v1,v2) =
|
|
||||||
case vv of
|
|
||||||
(VString "",_) -> v2
|
|
||||||
(_,VString "") -> v1
|
|
||||||
(VApp NonExist _,_) -> v1
|
|
||||||
(_,VApp NonExist _) -> v2
|
|
||||||
_ -> VC v1 v2
|
|
||||||
|
|
||||||
proj l v | isLockLabel l = return (VRec [])
|
|
||||||
---- a workaround 18/2/2005: take this away and find the reason
|
|
||||||
---- why earlier compilation destroys the lock field
|
|
||||||
proj l v =
|
|
||||||
case v of
|
|
||||||
VFV vs -> liftM vfv (mapM (proj l) vs)
|
|
||||||
VRec rs -> lookup l rs
|
|
||||||
-- VExtR v1 v2 -> proj l v2 `mplus` proj l v1 -- hmm
|
|
||||||
VS (VV pty pvs rs) v2 -> flip VS v2 . VV pty pvs # mapM (proj l) rs
|
|
||||||
_ -> return (ok1 VP v l)
|
|
||||||
|
|
||||||
ok1 f v1@(VError {}) _ = v1
|
|
||||||
ok1 f v1 v2 = f v1 v2
|
|
||||||
|
|
||||||
ok2 f v1@(VError {}) _ = v1
|
|
||||||
ok2 f _ v2@(VError {}) = v2
|
|
||||||
ok2 f v1 v2 = f v1 v2
|
|
||||||
|
|
||||||
ok2p f (v1@VError {},_) = v1
|
|
||||||
ok2p f (_,v2@VError {}) = v2
|
|
||||||
ok2p f vv = f vv
|
|
||||||
|
|
||||||
unlockVRec loc c0 v0 = v0
|
|
||||||
{-
|
|
||||||
unlockVRec loc c0 v0 = unlockVRec' c0 v0
|
|
||||||
where
|
|
||||||
unlockVRec' ::Ident -> Value -> Value
|
|
||||||
unlockVRec' c v =
|
|
||||||
case v of
|
|
||||||
-- VClosure env t -> err bug (VClosure env) (unlockRecord c t)
|
|
||||||
VAbs bt x (Bind f) -> VAbs bt x (Bind $ \ v -> unlockVRec' c (f v))
|
|
||||||
VRec rs -> plusVRec rs lock
|
|
||||||
-- _ -> VExtR v (VRec lock) -- hmm
|
|
||||||
_ -> {-trace (render $ ppL loc $ "unlock non-record "++show v0)-} v -- hmm
|
|
||||||
-- _ -> bugloc loc $ "unlock non-record "++show v0
|
|
||||||
where
|
|
||||||
lock = [(lockLabel c,VRec [])]
|
|
||||||
-}
|
|
||||||
|
|
||||||
-- suspicious, but backwards compatible
|
|
||||||
plusVRec rs1 rs2 = VRec ([(l,v)|(l,v)<-rs1,l `notElem` ls2] ++ rs2)
|
|
||||||
where ls2 = map fst rs2
|
|
||||||
|
|
||||||
extR t vv =
|
|
||||||
case vv of
|
|
||||||
(VFV vs,v2) -> vfv [extR t (v1,v2)|v1<-vs]
|
|
||||||
(v1,VFV vs) -> vfv [extR t (v1,v2)|v2<-vs]
|
|
||||||
(VRecType rs1, VRecType rs2) ->
|
|
||||||
case intersect (map fst rs1) (map fst rs2) of
|
|
||||||
[] -> VRecType (rs1 ++ rs2)
|
|
||||||
ls -> error $ "clash"<+>show ls
|
|
||||||
(VRec rs1, VRec rs2) -> plusVRec rs1 rs2
|
|
||||||
(v1 , VRec [(l,_)]) | isLockLabel l -> v1 -- hmm
|
|
||||||
(VS (VV t pvs vs) s,v2) -> VS (VV t pvs [extR t (v1,v2)|v1<-vs]) s
|
|
||||||
-- (v1,v2) -> ok2 VExtR v1 v2 -- hmm
|
|
||||||
(v1,v2) -> error $ "not records" $$ show v1 $$ show v2
|
|
||||||
where
|
|
||||||
error explain = ppbug $ "The term" <+> t
|
|
||||||
<+> "is not reducible" $$ explain
|
|
||||||
|
|
||||||
glue env (v1,v2) = glu v1 v2
|
|
||||||
where
|
|
||||||
glu v1 v2 =
|
|
||||||
case (v1,v2) of
|
|
||||||
(VFV vs,v2) -> vfv [glu v1 v2|v1<-vs]
|
|
||||||
(v1,VFV vs) -> vfv [glu v1 v2|v2<-vs]
|
|
||||||
(VString s1,VString s2) -> VString (s1++s2)
|
|
||||||
(v1,VAlts d vs) -> VAlts (glx d) [(glx v,c) | (v,c) <- vs]
|
|
||||||
where glx v2 = glu v1 v2
|
|
||||||
(v1@(VAlts {}),v2) ->
|
|
||||||
--err (const (ok2 VGlue v1 v2)) id $
|
|
||||||
err bug id $
|
|
||||||
do y' <- strsFromValue v2
|
|
||||||
x' <- strsFromValue v1
|
|
||||||
return $ vfv [foldr1 VC (map VString (str2strings (glueStr v u))) | v <- x', u <- y']
|
|
||||||
(VC va vb,v2) -> VC va (glu vb v2)
|
|
||||||
(v1,VC va vb) -> VC (glu v1 va) vb
|
|
||||||
(VS (VV ty pvs vs) vb,v2) -> VS (VV ty pvs [glu v v2|v<-vs]) vb
|
|
||||||
(v1,VS (VV ty pvs vs) vb) -> VS (VV ty pvs [glu v1 v|v<-vs]) vb
|
|
||||||
(v1@(VApp NonExist _),_) -> v1
|
|
||||||
(_,v2@(VApp NonExist _)) -> v2
|
|
||||||
-- (v1,v2) -> ok2 VGlue v1 v2
|
|
||||||
(v1,v2) -> if flag optPlusAsBind (opts env)
|
|
||||||
then VC v1 (VC (VApp BIND []) v2)
|
|
||||||
else let loc = gloc env
|
|
||||||
vt v = case value2term loc (local env) v of
|
|
||||||
Left i -> Error ('#':show i)
|
|
||||||
Right t -> t
|
|
||||||
in error . render $
|
|
||||||
ppL loc (hang "unsupported token gluing:" 4
|
|
||||||
(Glue (vt v1) (vt v2)))
|
|
||||||
|
|
||||||
|
|
||||||
-- | to get a string from a value that represents a sequence of terminals
|
|
||||||
strsFromValue :: Value -> Err [Str]
|
|
||||||
strsFromValue t = case t of
|
|
||||||
VString s -> return [str s]
|
|
||||||
VC s t -> do
|
|
||||||
s' <- strsFromValue s
|
|
||||||
t' <- strsFromValue t
|
|
||||||
return [plusStr x y | x <- s', y <- t']
|
|
||||||
{-
|
|
||||||
VGlue s t -> do
|
|
||||||
s' <- strsFromValue s
|
|
||||||
t' <- strsFromValue t
|
|
||||||
return [glueStr x y | x <- s', y <- t']
|
|
||||||
-}
|
|
||||||
VAlts d vs -> do
|
|
||||||
d0 <- strsFromValue d
|
|
||||||
v0 <- mapM (strsFromValue . fst) vs
|
|
||||||
c0 <- mapM (strsFromValue . snd) vs
|
|
||||||
--let vs' = zip v0 c0
|
|
||||||
return [strTok (str2strings def) vars |
|
|
||||||
def <- d0,
|
|
||||||
vars <- [[(str2strings v, map sstr c) | (v,c) <- zip vv c0] |
|
|
||||||
vv <- combinations v0]
|
|
||||||
]
|
|
||||||
VFV ts -> concat # mapM strsFromValue ts
|
|
||||||
VStrs ts -> concat # mapM strsFromValue ts
|
|
||||||
|
|
||||||
_ -> fail ("cannot get Str from value " ++ show t)
|
|
||||||
|
|
||||||
vfv vs = case nub vs of
|
|
||||||
[v] -> v
|
|
||||||
vs -> VFV vs
|
|
||||||
|
|
||||||
select env vv =
|
|
||||||
case vv of
|
|
||||||
(v1,VFV vs) -> vfv [select env (v1,v2)|v2<-vs]
|
|
||||||
(VFV vs,v2) -> vfv [select env (v1,v2)|v1<-vs]
|
|
||||||
(v1@(VV pty vs rs),v2) ->
|
|
||||||
err (const (VS v1 v2)) id $
|
|
||||||
do --ats <- allParamValues (srcgr env) pty
|
|
||||||
--let vs = map (value0 env) ats
|
|
||||||
i <- maybeErr "no match" $ findIndex (==v2) vs
|
|
||||||
return (ix (gloc env) "select" rs i)
|
|
||||||
(VT _ _ [(PW,Bind b)],_) -> {-trace "eliminate wild card table" $-} b []
|
|
||||||
(v1@(VT _ _ cs),v2) ->
|
|
||||||
err (\_->ok2 VS v1 v2) (err bug id . valueMatch env) $
|
|
||||||
match (gloc env) cs v2
|
|
||||||
(VS (VV pty pvs rs) v12,v2) -> VS (VV pty pvs [select env (v11,v2)|v11<-rs]) v12
|
|
||||||
(v1,v2) -> ok2 VS v1 v2
|
|
||||||
|
|
||||||
match loc cs v =
|
|
||||||
case value2term loc [] v of
|
|
||||||
Left i -> bad ("variable #"++show i++" is out of scope")
|
|
||||||
Right t -> err bad return (matchPattern cs t)
|
|
||||||
where
|
|
||||||
bad = fail . ("In pattern matching: "++)
|
|
||||||
|
|
||||||
valueMatch :: CompleteEnv -> (Bind Env,Substitution) -> Err Value
|
|
||||||
valueMatch env (Bind f,env') = f # mapPairsM (value0 env) env'
|
|
||||||
|
|
||||||
valueTable :: CompleteEnv -> TInfo -> [Case] -> Err OpenValue
|
|
||||||
valueTable env i cs =
|
|
||||||
case i of
|
|
||||||
TComp ty -> do pvs <- paramValues env ty
|
|
||||||
((VV ty pvs .) # sequence) # mapM (value env.snd) cs
|
|
||||||
_ -> do ty <- getTableType i
|
|
||||||
cs' <- mapM valueCase cs
|
|
||||||
err (dynamic cs' ty) return (convert cs' ty)
|
|
||||||
where
|
|
||||||
dynamic cs' ty _ = cases cs' # value env ty
|
|
||||||
|
|
||||||
cases cs' vty vs = err keep ($vs) (convertv cs' (vty vs))
|
|
||||||
where
|
|
||||||
keep msg = --trace (msg++"\n"++render (ppTerm Unqualified 0 (T i cs))) $
|
|
||||||
VT wild (vty vs) (mapSnd ($vs) cs')
|
|
||||||
|
|
||||||
wild = case i of TWild _ -> True; _ -> False
|
|
||||||
|
|
||||||
convertv cs' vty =
|
|
||||||
case value2term (gloc env) [] vty of
|
|
||||||
Left i -> fail ("variable #"++show i++" is out of scope")
|
|
||||||
Right pty -> convert' cs' =<< paramValues'' env pty
|
|
||||||
|
|
||||||
convert cs' ty = convert' cs' =<< paramValues' env ty
|
|
||||||
|
|
||||||
convert' cs' ((pty,vs),pvs) =
|
|
||||||
do sts <- mapM (matchPattern cs') vs
|
|
||||||
return $ \ vs -> VV pty pvs $ map (err bug id . valueMatch env)
|
|
||||||
(mapFst ($vs) sts)
|
|
||||||
|
|
||||||
valueCase (p,t) = do p' <- measurePatt # inlinePattMacro p
|
|
||||||
pvs <- linPattVars p'
|
|
||||||
vt <- value (extend pvs env) t
|
|
||||||
return (p',\vs-> Bind $ \bs-> vt (push' p' bs pvs vs))
|
|
||||||
|
|
||||||
inlinePattMacro p =
|
|
||||||
case p of
|
|
||||||
PM qc -> do r <- resource env qc
|
|
||||||
case r of
|
|
||||||
VPatt p' -> inlinePattMacro p'
|
|
||||||
_ -> ppbug $ hang "Expected pattern macro:" 4
|
|
||||||
(show r)
|
|
||||||
_ -> composPattOp inlinePattMacro p
|
|
||||||
|
|
||||||
|
|
||||||
paramValues env ty = snd # paramValues' env ty
|
|
||||||
|
|
||||||
paramValues' env ty = paramValues'' env =<< nfx (global env) ty
|
|
||||||
|
|
||||||
paramValues'' env pty = do ats <- allParamValues (srcgr env) pty
|
|
||||||
pvs <- mapM (eval (global env) []) ats
|
|
||||||
return ((pty,ats),pvs)
|
|
||||||
|
|
||||||
push' p bs xs = if length bs/=length xs
|
|
||||||
then bug $ "push "++show (p,bs,xs)
|
|
||||||
else push bs xs
|
|
||||||
|
|
||||||
push :: Env -> LocalScope -> Stack -> Stack
|
|
||||||
push bs [] vs = vs
|
|
||||||
push bs (x:xs) vs = maybe err id (lookup x bs):push bs xs vs
|
|
||||||
where err = bug $ "Unbound pattern variable "++showIdent x
|
|
||||||
|
|
||||||
apply' :: CompleteEnv -> Term -> [OpenValue] -> Err OpenValue
|
|
||||||
apply' env t [] = value env t
|
|
||||||
apply' env t vs =
|
|
||||||
case t of
|
|
||||||
QC x -> return $ \ svs -> VCApp x (map ($svs) vs)
|
|
||||||
{-
|
|
||||||
Q x@(m,f) | m==cPredef -> return $
|
|
||||||
let constr = --trace ("predef "++show x) .
|
|
||||||
VApp x
|
|
||||||
in \ svs -> maybe constr id (Map.lookup f predefs)
|
|
||||||
$ map ($svs) vs
|
|
||||||
| otherwise -> do r <- resource env x
|
|
||||||
return $ \ svs -> vapply (gloc env) r (map ($svs) vs)
|
|
||||||
-}
|
|
||||||
App t1 t2 -> apply' env t1 . (:vs) =<< value env t2
|
|
||||||
_ -> do fv <- value env t
|
|
||||||
return $ \ svs -> vapply (gloc env) (fv svs) (map ($svs) vs)
|
|
||||||
|
|
||||||
vapply :: GLocation -> Value -> [Value] -> Value
|
|
||||||
vapply loc v [] = v
|
|
||||||
vapply loc v vs =
|
|
||||||
case v of
|
|
||||||
VError {} -> v
|
|
||||||
-- VClosure env (Abs b x t) -> beta gr env b x t vs
|
|
||||||
VAbs bt _ (Bind f) -> vbeta loc bt f vs
|
|
||||||
VApp pre vs1 -> delta' pre (vs1++vs)
|
|
||||||
where
|
|
||||||
delta' Trace (v1:v2:vs) = let vr = vapply loc v2 vs
|
|
||||||
in vtrace loc v1 vr
|
|
||||||
delta' pre vs = err msg vfv $ mapM (delta pre) (varyList vs)
|
|
||||||
--msg = const (VApp pre (vs1++vs))
|
|
||||||
msg = bug . (("Applying Predef."++showIdent (predefName pre)++": ")++)
|
|
||||||
VS (VV t pvs fs) s -> VS (VV t pvs [vapply loc f vs|f<-fs]) s
|
|
||||||
VFV fs -> vfv [vapply loc f vs|f<-fs]
|
|
||||||
VCApp f vs0 -> VCApp f (vs0++vs)
|
|
||||||
VMeta i env vs0 -> VMeta i env (vs0++vs)
|
|
||||||
VGen i vs0 -> VGen i (vs0++vs)
|
|
||||||
v -> bug $ "vapply "++show v++" "++show vs
|
|
||||||
|
|
||||||
vbeta loc bt f (v:vs) =
|
|
||||||
case (bt,v) of
|
|
||||||
(Implicit,VImplArg v) -> ap v
|
|
||||||
(Explicit, v) -> ap v
|
|
||||||
where
|
|
||||||
ap (VFV avs) = vfv [vapply loc (f v) vs|v<-avs]
|
|
||||||
ap v = vapply loc (f v) vs
|
|
||||||
|
|
||||||
vary (VFV vs) = vs
|
|
||||||
vary v = [v]
|
|
||||||
varyList = mapM vary
|
|
||||||
|
|
||||||
{-
|
|
||||||
beta env b x t (v:vs) =
|
|
||||||
case (b,v) of
|
|
||||||
(Implicit,VImplArg v) -> apply' (ext (x,v) env) t vs
|
|
||||||
(Explicit, v) -> apply' (ext (x,v) env) t vs
|
|
||||||
-}
|
|
||||||
|
|
||||||
vtrace loc arg res = trace (render (hang (pv arg) 4 ("->"<+>pv res))) res
|
|
||||||
where
|
|
||||||
pv v = case v of
|
|
||||||
VRec (f:as) -> hang (pf f) 4 (fsep (map pa as))
|
|
||||||
_ -> ppV v
|
|
||||||
pf (_,VString n) = pp n
|
|
||||||
pf (_,v) = ppV v
|
|
||||||
pa (_,v) = ppV v
|
|
||||||
ppV v = case value2term' True loc [] v of
|
|
||||||
Left i -> "variable #" <> pp i <+> "is out of scope"
|
|
||||||
Right t -> ppTerm Unqualified 10 t
|
|
||||||
|
|
||||||
-- | Convert a value back to a term
|
|
||||||
value2term :: GLocation -> [Ident] -> Value -> Either Int Term
|
|
||||||
value2term = value2term' False
|
|
||||||
value2term' stop loc xs v0 =
|
|
||||||
case v0 of
|
|
||||||
VApp pre vs -> liftM (foldl App (Q (cPredef,predefName pre))) (mapM v2t vs)
|
|
||||||
VCApp f vs -> liftM (foldl App (QC f)) (mapM v2t vs)
|
|
||||||
VGen j vs -> liftM2 (foldl App) (var j) (mapM v2t vs)
|
|
||||||
VMeta j env vs -> liftM (foldl App (Meta j)) (mapM v2t vs)
|
|
||||||
VProd bt v x f -> liftM2 (Prod bt x) (v2t v) (v2t' x f)
|
|
||||||
VAbs bt x f -> liftM (Abs bt x) (v2t' x f)
|
|
||||||
VInt n -> return (EInt n)
|
|
||||||
VFloat f -> return (EFloat f)
|
|
||||||
VString s -> return (if null s then Empty else K s)
|
|
||||||
VSort s -> return (Sort s)
|
|
||||||
VImplArg v -> liftM ImplArg (v2t v)
|
|
||||||
VTblType p res -> liftM2 Table (v2t p) (v2t res)
|
|
||||||
VRecType rs -> liftM RecType (mapM (\(l,v) -> fmap ((,) l) (v2t v)) rs)
|
|
||||||
VRec as -> liftM R (mapM (\(l,v) -> v2t v >>= \t -> return (l,(Nothing,t))) as)
|
|
||||||
VV t _ vs -> liftM (V t) (mapM v2t vs)
|
|
||||||
VT wild v cs -> v2t v >>= \t -> liftM (T ((if wild then TWild else TTyped) t)) (mapM nfcase cs)
|
|
||||||
VFV vs -> liftM FV (mapM v2t vs)
|
|
||||||
VC v1 v2 -> liftM2 C (v2t v1) (v2t v2)
|
|
||||||
VS v1 v2 -> liftM2 S (v2t v1) (v2t v2)
|
|
||||||
VP v l -> v2t v >>= \t -> return (P t l)
|
|
||||||
VPatt p -> return (EPatt p)
|
|
||||||
VPattType v -> v2t v >>= return . EPattType
|
|
||||||
VAlts v vvs -> liftM2 Alts (v2t v) (mapM (\(x,y) -> liftM2 (,) (v2t x) (v2t y)) vvs)
|
|
||||||
VStrs vs -> liftM Strs (mapM v2t vs)
|
|
||||||
-- VGlue v1 v2 -> Glue (v2t v1) (v2t v2)
|
|
||||||
-- VExtR v1 v2 -> ExtR (v2t v1) (v2t v2)
|
|
||||||
VError err -> return (Error err)
|
|
||||||
_ -> bug ("value2term "++show loc++" : "++show v0)
|
|
||||||
where
|
|
||||||
v2t = v2txs xs
|
|
||||||
v2txs = value2term' stop loc
|
|
||||||
v2t' x f = v2txs (x:xs) (bind f (gen xs))
|
|
||||||
|
|
||||||
var j
|
|
||||||
| j<length xs = Right (Vr (reverse xs !! j))
|
|
||||||
| otherwise = Left j
|
|
||||||
|
|
||||||
|
|
||||||
pushs xs e = foldr push e xs
|
|
||||||
push x (env,xs) = ((x,gen xs):env,x:xs)
|
|
||||||
gen xs = VGen (length xs) []
|
|
||||||
|
|
||||||
nfcase (p,f) = liftM ((,) p) (v2txs xs' (bind f env'))
|
|
||||||
where (env',xs') = pushs (pattVars p) ([],xs)
|
|
||||||
|
|
||||||
bind (Bind f) x = if stop
|
|
||||||
then VSort (identS "...") -- hmm
|
|
||||||
else f x
|
|
||||||
|
|
||||||
|
|
||||||
linPattVars p =
|
|
||||||
if null dups
|
|
||||||
then return pvs
|
|
||||||
else fail.render $ hang "Pattern is not linear:" 4 (ppPatt Unqualified 0 p)
|
|
||||||
where
|
|
||||||
allpvs = allPattVars p
|
|
||||||
pvs = nub allpvs
|
|
||||||
dups = allpvs \\ pvs
|
|
||||||
|
|
||||||
pattVars = nub . allPattVars
|
|
||||||
allPattVars p =
|
|
||||||
case p of
|
|
||||||
PV i -> [i]
|
|
||||||
PAs i p -> i:allPattVars p
|
|
||||||
_ -> collectPattOp allPattVars p
|
|
||||||
|
|
||||||
---
|
|
||||||
ix loc fn xs i =
|
|
||||||
if i<n
|
|
||||||
then xs !! i
|
|
||||||
else bugloc loc $ "(!!): index too large in "++fn++", "++show i++"<"++show n
|
|
||||||
where n = length xs
|
|
||||||
|
|
||||||
infixl 1 #,<# --,@@
|
|
||||||
|
|
||||||
f # x = fmap f x
|
|
||||||
mf <# mx = ap mf mx
|
|
||||||
--m1 @@ m2 = (m1 =<<) . m2
|
|
||||||
|
|
||||||
both f (x,y) = (,) # f x <# f y
|
|
||||||
|
|
||||||
bugloc loc s = ppbug $ ppL loc s
|
|
||||||
|
|
||||||
bug msg = ppbug msg
|
|
||||||
ppbug doc = error $ render $ hang "Internal error in Compute.ConcreteNew:" 4 doc
|
|
||||||
@@ -27,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
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ data Value
|
|||||||
| VGen Int [Value] -- for lambda bound variables, possibly applied
|
| VGen Int [Value] -- for lambda bound variables, possibly applied
|
||||||
| VMeta MetaId Env [Value]
|
| VMeta MetaId Env [Value]
|
||||||
-- -- | VClosure Env Term -- used in Typecheck.ConcreteNew
|
-- -- | VClosure Env Term -- used in Typecheck.ConcreteNew
|
||||||
| VAbs BindType Ident Binding -- used in Compute.ConcreteNew
|
| VAbs BindType Ident Binding -- used in Compute.Concrete
|
||||||
| VProd BindType Value Ident Binding -- used in Compute.ConcreteNew
|
| VProd BindType Value Ident Binding -- used in Compute.Concrete
|
||||||
| VInt Int
|
| VInt Int
|
||||||
| VFloat Double
|
| VFloat Double
|
||||||
| VString String
|
| VString String
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import GF.Text.Pretty
|
|||||||
--import GF.Grammar.Predef(cPredef,cInts)
|
--import GF.Grammar.Predef(cPredef,cInts)
|
||||||
--import GF.Compile.Compute.Predef(predef)
|
--import GF.Compile.Compute.Predef(predef)
|
||||||
--import GF.Compile.Compute.Value(Predefined(..))
|
--import GF.Compile.Compute.Value(Predefined(..))
|
||||||
import GF.Infra.Ident(Ident,identS,identW,prefixIdent)
|
import GF.Infra.Ident(Ident,identC,identS,identW,prefixIdent,showRawIdent,rawIdentS)
|
||||||
import GF.Infra.Option
|
import GF.Infra.Option
|
||||||
import GF.Haskell as H
|
import GF.Haskell as H
|
||||||
import GF.Grammar.Canonical as C
|
import GF.Grammar.Canonical as C
|
||||||
@@ -21,7 +21,7 @@ concretes2haskell opts absname gr =
|
|||||||
| let Grammar abstr cncs = grammar2canonical opts absname gr,
|
| let Grammar abstr cncs = grammar2canonical opts absname gr,
|
||||||
cncmod<-cncs,
|
cncmod<-cncs,
|
||||||
let ModId name = concName cncmod
|
let ModId name = concName cncmod
|
||||||
filename = name ++ ".hs" :: FilePath
|
filename = showRawIdent name ++ ".hs" :: FilePath
|
||||||
]
|
]
|
||||||
|
|
||||||
-- | Generate Haskell code for the given concrete module.
|
-- | Generate Haskell code for the given concrete module.
|
||||||
@@ -53,7 +53,7 @@ concrete2haskell opts
|
|||||||
labels = S.difference (S.unions (map S.fromList recs)) common_labels
|
labels = S.difference (S.unions (map S.fromList recs)) common_labels
|
||||||
common_records = S.fromList [[label_s]]
|
common_records = S.fromList [[label_s]]
|
||||||
common_labels = S.fromList [label_s]
|
common_labels = S.fromList [label_s]
|
||||||
label_s = LabelId "s"
|
label_s = LabelId (rawIdentS "s")
|
||||||
|
|
||||||
signature (CatDef c _) = TypeSig lf (Fun abs (pure lin))
|
signature (CatDef c _) = TypeSig lf (Fun abs (pure lin))
|
||||||
where
|
where
|
||||||
@@ -321,7 +321,7 @@ coerce env ty t =
|
|||||||
TableValue ti [TableRow p (coerce env tv t)|TableRow p t<-cs]
|
TableValue ti [TableRow p (coerce env tv t)|TableRow p t<-cs]
|
||||||
(RecordType rt,RecordValue r) ->
|
(RecordType rt,RecordValue r) ->
|
||||||
RecordValue [RecordRow l (coerce env ft f) |
|
RecordValue [RecordRow l (coerce env ft f) |
|
||||||
RecordRow l f<-r,ft<-[ft|RecordRow l' ft<-rt,l'==l]]
|
RecordRow l f<-r,ft<-[ft | RecordRow l' ft <- rt, l'==l]]
|
||||||
(RecordType rt,VarValue x)->
|
(RecordType rt,VarValue x)->
|
||||||
case lookup x env of
|
case lookup x env of
|
||||||
Just ty' | ty'/=ty -> -- better to compare to normal form of ty'
|
Just ty' | ty'/=ty -> -- better to compare to normal form of ty'
|
||||||
@@ -334,18 +334,17 @@ coerce env ty t =
|
|||||||
_ -> t
|
_ -> t
|
||||||
where
|
where
|
||||||
app f ts = ParamConstant (Param f ts) -- !! a hack
|
app f ts = ParamConstant (Param f ts) -- !! a hack
|
||||||
to_rcon = ParamId . Unqual . to_rcon' . labels
|
to_rcon = ParamId . Unqual . rawIdentS . to_rcon' . labels
|
||||||
|
|
||||||
patVars p = []
|
patVars p = []
|
||||||
|
|
||||||
labels r = [l|RecordRow l _<-r]
|
labels r = [l | RecordRow l _ <- r]
|
||||||
|
|
||||||
proj = Var . identS . proj'
|
proj = Var . identS . proj'
|
||||||
proj' (LabelId l) = "proj_"++l
|
proj' (LabelId l) = "proj_" ++ showRawIdent l
|
||||||
rcon = Var . rcon'
|
rcon = Var . rcon'
|
||||||
rcon' = identS . rcon_name
|
rcon' = identS . rcon_name
|
||||||
rcon_name ls = "R"++concat (sort ['_':l|LabelId l<-ls])
|
rcon_name ls = "R"++concat (sort ['_':showRawIdent l | LabelId l <- ls])
|
||||||
|
|
||||||
to_rcon' = ("to_"++) . rcon_name
|
to_rcon' = ("to_"++) . rcon_name
|
||||||
|
|
||||||
recordType ls =
|
recordType ls =
|
||||||
@@ -400,17 +399,17 @@ linfunName c = prefixIdent "lin" (toIdent c)
|
|||||||
|
|
||||||
class ToIdent i where toIdent :: i -> Ident
|
class ToIdent i where toIdent :: i -> Ident
|
||||||
|
|
||||||
instance ToIdent ParamId where toIdent (ParamId q) = qIdentS q
|
instance ToIdent ParamId where toIdent (ParamId q) = qIdentC q
|
||||||
instance ToIdent PredefId where toIdent (PredefId s) = identS s
|
instance ToIdent PredefId where toIdent (PredefId s) = identC s
|
||||||
instance ToIdent CatId where toIdent (CatId s) = identS s
|
instance ToIdent CatId where toIdent (CatId s) = identC s
|
||||||
instance ToIdent C.FunId where toIdent (FunId s) = identS s
|
instance ToIdent C.FunId where toIdent (FunId s) = identC s
|
||||||
instance ToIdent VarValueId where toIdent (VarValueId q) = qIdentS q
|
instance ToIdent VarValueId where toIdent (VarValueId q) = qIdentC q
|
||||||
|
|
||||||
qIdentS = identS . unqual
|
qIdentC = identS . unqual
|
||||||
|
|
||||||
unqual (Qual (ModId m) n) = m++"_"++n
|
unqual (Qual (ModId m) n) = showRawIdent m++"_"++ showRawIdent n
|
||||||
unqual (Unqual n) = n
|
unqual (Unqual n) = showRawIdent n
|
||||||
|
|
||||||
instance ToIdent VarId where
|
instance ToIdent VarId where
|
||||||
toIdent Anonymous = identW
|
toIdent Anonymous = identW
|
||||||
toIdent (VarId s) = identS s
|
toIdent (VarId s) = identC s
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import GF.Data.BacktrackM
|
|||||||
import GF.Data.Operations
|
import GF.Data.Operations
|
||||||
import GF.Infra.UseIO (ePutStr,ePutStrLn) -- IOE,
|
import GF.Infra.UseIO (ePutStr,ePutStrLn) -- IOE,
|
||||||
import GF.Data.Utilities (updateNthM) --updateNth
|
import GF.Data.Utilities (updateNthM) --updateNth
|
||||||
import GF.Compile.Compute.ConcreteNew(normalForm,resourceValues)
|
import GF.Compile.Compute.Concrete(normalForm,resourceValues)
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
import qualified Data.Set as Set
|
import qualified Data.Set as Set
|
||||||
import qualified Data.List as List
|
import qualified Data.List as List
|
||||||
@@ -41,6 +41,7 @@ import Control.Monad
|
|||||||
import Control.Monad.Identity
|
import Control.Monad.Identity
|
||||||
--import Control.Exception
|
--import Control.Exception
|
||||||
--import Debug.Trace(trace)
|
--import Debug.Trace(trace)
|
||||||
|
import qualified Control.Monad.Fail as Fail
|
||||||
|
|
||||||
----------------------------------------------------------------------
|
----------------------------------------------------------------------
|
||||||
-- main conversion function
|
-- main conversion function
|
||||||
@@ -196,6 +197,9 @@ newtype CnvMonad a = CM {unCM :: SourceGrammar
|
|||||||
-> ([ProtoFCat],[Symbol])
|
-> ([ProtoFCat],[Symbol])
|
||||||
-> Branch b}
|
-> Branch b}
|
||||||
|
|
||||||
|
instance Fail.MonadFail CnvMonad where
|
||||||
|
fail = bug
|
||||||
|
|
||||||
instance Applicative CnvMonad where
|
instance Applicative CnvMonad where
|
||||||
pure = return
|
pure = return
|
||||||
(<*>) = ap
|
(<*>) = ap
|
||||||
@@ -614,6 +618,23 @@ mkArray lst = listArray (0,length lst-1) lst
|
|||||||
mkSetArray map = array (0,Map.size map-1) [(v,k) | (k,v) <- Map.toList map]
|
mkSetArray map = array (0,Map.size map-1) [(v,k) | (k,v) <- Map.toList map]
|
||||||
|
|
||||||
bug msg = ppbug msg
|
bug msg = ppbug msg
|
||||||
ppbug msg = error . render $ hang "Internal error in GeneratePMCFG:" 4 msg
|
ppbug msg = error completeMsg
|
||||||
|
where
|
||||||
|
originalMsg = render $ hang "Internal error in GeneratePMCFG:" 4 msg
|
||||||
|
completeMsg =
|
||||||
|
case render msg of -- the error message for pattern matching a runtime string
|
||||||
|
"descend (CStr 0,CNil,CProj (LIdent (Id {rawId2utf8 = \"s\"})) CNil)"
|
||||||
|
-> unlines [originalMsg -- add more helpful output
|
||||||
|
,""
|
||||||
|
,"1) Check that you are not trying to pattern match a /runtime string/."
|
||||||
|
," These are illegal:"
|
||||||
|
," lin Test foo = case foo.s of {"
|
||||||
|
," \"str\" => … } ; <- explicit matching argument of a lin"
|
||||||
|
," lin Test foo = opThatMatches foo <- calling an oper that pattern matches"
|
||||||
|
,""
|
||||||
|
,"2) Not about pattern matching? Submit a bug report and we update the error message."
|
||||||
|
," https://github.com/GrammaticalFramework/gf-core/issues"
|
||||||
|
]
|
||||||
|
_ -> originalMsg -- any other message: just print it as is
|
||||||
|
|
||||||
ppU = ppTerm Unqualified
|
ppU = ppTerm Unqualified
|
||||||
|
|||||||
@@ -6,30 +6,35 @@ module GF.Compile.GrammarToCanonical(
|
|||||||
) where
|
) where
|
||||||
import Data.List(nub,partition)
|
import Data.List(nub,partition)
|
||||||
import qualified Data.Map as M
|
import qualified Data.Map as M
|
||||||
|
import Data.Maybe(fromMaybe)
|
||||||
import qualified Data.Set as S
|
import qualified Data.Set as S
|
||||||
import GF.Data.ErrM
|
import GF.Data.ErrM
|
||||||
import GF.Text.Pretty
|
import GF.Text.Pretty
|
||||||
import GF.Grammar.Grammar
|
import GF.Grammar.Grammar as G
|
||||||
import GF.Grammar.Lookup(lookupOrigInfo,allOrigInfos,allParamValues)
|
import GF.Grammar.Lookup(lookupOrigInfo,allOrigInfos,allParamValues)
|
||||||
import GF.Grammar.Macros(typeForm,collectOp,collectPattOp,mkAbs,mkApp,term2patt)
|
import GF.Grammar.Macros(typeForm,collectOp,collectPattOp,composSafeOp,mkAbs,mkApp,term2patt,sortRec)
|
||||||
import GF.Grammar.Lockfield(isLockLabel)
|
import GF.Grammar.Lockfield(isLockLabel)
|
||||||
import GF.Grammar.Predef(cPredef,cInts)
|
import GF.Grammar.Predef(cPredef,cInts)
|
||||||
import GF.Compile.Compute.Predef(predef)
|
import GF.Compile.Compute.Predef(predef)
|
||||||
import GF.Compile.Compute.Value(Predefined(..))
|
import GF.Compile.Compute.Value(Predefined(..))
|
||||||
import GF.Infra.Ident(ModuleName(..),Ident,prefixIdent,showIdent,isWildIdent)
|
import GF.Infra.Ident(ModuleName(..),Ident,ident2raw,rawIdentS,showIdent,isWildIdent)
|
||||||
import GF.Infra.Option(optionsPGF)
|
import GF.Infra.Option(Options,optionsPGF)
|
||||||
import PGF.Internal(Literal(..))
|
import PGF.Internal(Literal(..))
|
||||||
import GF.Compile.Compute.ConcreteNew(normalForm,resourceValues)
|
import GF.Compile.Compute.Concrete(GlobalEnv,normalForm,resourceValues)
|
||||||
import GF.Grammar.Canonical as C
|
import GF.Grammar.Canonical as C
|
||||||
import Debug.Trace
|
import System.FilePath ((</>), (<.>))
|
||||||
|
import qualified Debug.Trace as T
|
||||||
|
|
||||||
|
|
||||||
-- | Generate Canonical code for the named abstract syntax and all associated
|
-- | Generate Canonical code for the named abstract syntax and all associated
|
||||||
-- concrete syntaxes
|
-- concrete syntaxes
|
||||||
|
grammar2canonical :: Options -> ModuleName -> G.Grammar -> C.Grammar
|
||||||
grammar2canonical opts absname gr =
|
grammar2canonical opts absname gr =
|
||||||
Grammar (abstract2canonical absname gr)
|
Grammar (abstract2canonical absname gr)
|
||||||
(map snd (concretes2canonical opts absname gr))
|
(map snd (concretes2canonical opts absname gr))
|
||||||
|
|
||||||
-- | Generate Canonical code for the named abstract syntax
|
-- | Generate Canonical code for the named abstract syntax
|
||||||
|
abstract2canonical :: ModuleName -> G.Grammar -> Abstract
|
||||||
abstract2canonical absname gr =
|
abstract2canonical absname gr =
|
||||||
Abstract (modId absname) (convFlags gr absname) cats funs
|
Abstract (modId absname) (convFlags gr absname) cats funs
|
||||||
where
|
where
|
||||||
@@ -44,6 +49,7 @@ abstract2canonical absname gr =
|
|||||||
convHypo (bt,name,t) =
|
convHypo (bt,name,t) =
|
||||||
case typeForm t of
|
case typeForm t of
|
||||||
([],(_,cat),[]) -> gId cat -- !!
|
([],(_,cat),[]) -> gId cat -- !!
|
||||||
|
tf -> error $ "abstract2canonical convHypo: " ++ show tf
|
||||||
|
|
||||||
convType t =
|
convType t =
|
||||||
case typeForm t of
|
case typeForm t of
|
||||||
@@ -54,23 +60,24 @@ abstract2canonical absname gr =
|
|||||||
|
|
||||||
convHypo' (bt,name,t) = TypeBinding (gId name) (convType t)
|
convHypo' (bt,name,t) = TypeBinding (gId name) (convType t)
|
||||||
|
|
||||||
|
|
||||||
-- | Generate Canonical code for the all concrete syntaxes associated with
|
-- | Generate Canonical code for the all concrete syntaxes associated with
|
||||||
-- the named abstract syntax in given the grammar.
|
-- the named abstract syntax in given the grammar.
|
||||||
|
concretes2canonical :: Options -> ModuleName -> G.Grammar -> [(FilePath, Concrete)]
|
||||||
concretes2canonical opts absname gr =
|
concretes2canonical opts absname gr =
|
||||||
[(cncname,concrete2canonical gr cenv absname cnc cncmod)
|
[(cncname,concrete2canonical gr cenv absname cnc cncmod)
|
||||||
| let cenv = resourceValues opts gr,
|
| let cenv = resourceValues opts gr,
|
||||||
cnc<-allConcretes gr absname,
|
cnc<-allConcretes gr absname,
|
||||||
let cncname = "canonical/"++render cnc ++ ".gf" :: FilePath
|
let cncname = "canonical" </> render cnc <.> "gf"
|
||||||
Ok cncmod = lookupModule gr cnc
|
Ok cncmod = lookupModule gr cnc
|
||||||
]
|
]
|
||||||
|
|
||||||
-- | Generate Canonical GF for the given concrete module.
|
-- | Generate Canonical GF for the given concrete module.
|
||||||
|
concrete2canonical :: G.Grammar -> GlobalEnv -> ModuleName -> ModuleName -> ModuleInfo -> Concrete
|
||||||
concrete2canonical gr cenv absname cnc modinfo =
|
concrete2canonical gr cenv absname cnc modinfo =
|
||||||
Concrete (modId cnc) (modId absname) (convFlags gr cnc)
|
Concrete (modId cnc) (modId absname) (convFlags gr cnc)
|
||||||
(neededParamTypes S.empty (params defs))
|
(neededParamTypes S.empty (params defs))
|
||||||
[lincat|(_,Left lincat)<-defs]
|
[lincat | (_,Left lincat) <- defs]
|
||||||
[lin|(_,Right lin)<-defs]
|
[lin | (_,Right lin) <- defs]
|
||||||
where
|
where
|
||||||
defs = concatMap (toCanonical gr absname cenv) .
|
defs = concatMap (toCanonical gr absname cenv) .
|
||||||
M.toList $
|
M.toList $
|
||||||
@@ -85,6 +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 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 _ ->
|
||||||
@@ -97,7 +105,8 @@ toCanonical gr absname cenv (name,jment) =
|
|||||||
where
|
where
|
||||||
tts = tableTypes gr [e']
|
tts = tableTypes gr [e']
|
||||||
|
|
||||||
e' = unAbs (length params) $
|
e' = cleanupRecordFields lincat $
|
||||||
|
unAbs (length params) $
|
||||||
nf loc (mkAbs params (mkApp def (map Vr args)))
|
nf loc (mkAbs params (mkApp def (map Vr args)))
|
||||||
params = [(b,x)|(b,x,_)<-ctx]
|
params = [(b,x)|(b,x,_)<-ctx]
|
||||||
args = map snd params
|
args = map snd params
|
||||||
@@ -108,12 +117,12 @@ toCanonical gr absname cenv (name,jment) =
|
|||||||
_ -> []
|
_ -> []
|
||||||
where
|
where
|
||||||
nf loc = normalForm cenv (L loc name)
|
nf loc = normalForm cenv (L loc name)
|
||||||
-- aId n = prefixIdent "A." (gId n)
|
|
||||||
|
|
||||||
unAbs 0 t = t
|
unAbs 0 t = t
|
||||||
unAbs n (Abs _ _ t) = unAbs (n-1) t
|
unAbs n (Abs _ _ t) = unAbs (n-1) t
|
||||||
unAbs _ t = t
|
unAbs _ t = t
|
||||||
|
|
||||||
|
tableTypes :: G.Grammar -> [Term] -> S.Set QIdent
|
||||||
tableTypes gr ts = S.unions (map tabtys ts)
|
tableTypes gr ts = S.unions (map tabtys ts)
|
||||||
where
|
where
|
||||||
tabtys t =
|
tabtys t =
|
||||||
@@ -122,6 +131,7 @@ tableTypes gr ts = S.unions (map tabtys ts)
|
|||||||
T (TTyped t) cs -> S.union (paramTypes gr t) (tableTypes gr (map snd cs))
|
T (TTyped t) cs -> S.union (paramTypes gr t) (tableTypes gr (map snd cs))
|
||||||
_ -> collectOp tabtys t
|
_ -> collectOp tabtys t
|
||||||
|
|
||||||
|
paramTypes :: G.Grammar -> G.Type -> S.Set QIdent
|
||||||
paramTypes gr t =
|
paramTypes gr t =
|
||||||
case t of
|
case t of
|
||||||
RecType fs -> S.unions (map (paramTypes gr.snd) fs)
|
RecType fs -> S.unions (map (paramTypes gr.snd) fs)
|
||||||
@@ -140,11 +150,26 @@ paramTypes gr t =
|
|||||||
Ok (_,ResParam {}) -> S.singleton q
|
Ok (_,ResParam {}) -> S.singleton q
|
||||||
_ -> ignore
|
_ -> ignore
|
||||||
|
|
||||||
ignore = trace ("Ignore: "++show t) S.empty
|
ignore = T.trace ("Ignore: " ++ show t) S.empty
|
||||||
|
|
||||||
|
-- | Filter out record fields from definitions which don't appear in lincat.
|
||||||
|
cleanupRecordFields :: G.Type -> Term -> Term
|
||||||
|
cleanupRecordFields (RecType ls) (R as) =
|
||||||
|
let defnFields = M.fromList ls
|
||||||
|
in R
|
||||||
|
[ (lbl, (mty, t'))
|
||||||
|
| (lbl, (mty, t)) <- as
|
||||||
|
, M.member lbl defnFields
|
||||||
|
, let Just ty = M.lookup lbl defnFields
|
||||||
|
, let t' = cleanupRecordFields ty t
|
||||||
|
]
|
||||||
|
cleanupRecordFields ty t@(FV _) = composSafeOp (cleanupRecordFields ty) t
|
||||||
|
cleanupRecordFields _ t = t
|
||||||
|
|
||||||
|
convert :: G.Grammar -> Term -> LinValue
|
||||||
convert gr = convert' gr []
|
convert gr = convert' gr []
|
||||||
|
|
||||||
|
convert' :: G.Grammar -> [Ident] -> Term -> LinValue
|
||||||
convert' gr vs = ppT
|
convert' gr vs = ppT
|
||||||
where
|
where
|
||||||
ppT0 = convert' gr vs
|
ppT0 = convert' gr vs
|
||||||
@@ -162,20 +187,20 @@ convert' gr vs = ppT
|
|||||||
S t p -> selection (ppT t) (ppT p)
|
S t p -> selection (ppT t) (ppT p)
|
||||||
C t1 t2 -> concatValue (ppT t1) (ppT t2)
|
C t1 t2 -> concatValue (ppT t1) (ppT t2)
|
||||||
App f a -> ap (ppT f) (ppT a)
|
App f a -> ap (ppT f) (ppT a)
|
||||||
R r -> RecordValue (fields r)
|
R r -> RecordValue (fields (sortRec r))
|
||||||
P t l -> projection (ppT t) (lblId l)
|
P t l -> projection (ppT t) (lblId l)
|
||||||
Vr x -> VarValue (gId x)
|
Vr x -> VarValue (gId x)
|
||||||
Cn x -> VarValue (gId x) -- hmm
|
Cn x -> VarValue (gId x) -- hmm
|
||||||
Con c -> ParamConstant (Param (gId c) [])
|
Con c -> ParamConstant (Param (gId c) [])
|
||||||
Sort k -> VarValue (gId k)
|
Sort k -> VarValue (gId k)
|
||||||
EInt n -> LiteralValue (IntConstant n)
|
EInt n -> LiteralValue (IntConstant n)
|
||||||
Q (m,n) -> if m==cPredef then ppPredef n else VarValue ((gQId m n))
|
Q (m,n) -> if m==cPredef then ppPredef n else VarValue (gQId m n)
|
||||||
QC (m,n) -> ParamConstant (Param ((gQId m n)) [])
|
QC (m,n) -> ParamConstant (Param (gQId m n) [])
|
||||||
K s -> LiteralValue (StrConstant s)
|
K s -> LiteralValue (StrConstant s)
|
||||||
Empty -> LiteralValue (StrConstant "")
|
Empty -> LiteralValue (StrConstant "")
|
||||||
FV ts -> VariantValue (map ppT ts)
|
FV ts -> VariantValue (map ppT ts)
|
||||||
Alts t' vs -> alts vs (ppT t')
|
Alts t' vs -> alts vs (ppT t')
|
||||||
_ -> error $ "convert' "++show t
|
_ -> error $ "convert' ppT: " ++ show t
|
||||||
|
|
||||||
ppCase (p,t) = TableRow (ppP p) (ppTv (patVars p++vs) t)
|
ppCase (p,t) = TableRow (ppP p) (ppTv (patVars p++vs) t)
|
||||||
|
|
||||||
@@ -188,12 +213,12 @@ convert' gr vs = ppT
|
|||||||
Ok ALL_CAPIT -> p "ALL_CAPIT"
|
Ok ALL_CAPIT -> p "ALL_CAPIT"
|
||||||
_ -> VarValue (gQId cPredef n) -- hmm
|
_ -> VarValue (gQId cPredef n) -- hmm
|
||||||
where
|
where
|
||||||
p = PredefValue . PredefId
|
p = PredefValue . PredefId . rawIdentS
|
||||||
|
|
||||||
ppP p =
|
ppP p =
|
||||||
case p of
|
case p of
|
||||||
PC c ps -> ParamPattern (Param (gId c) (map ppP ps))
|
PC c ps -> ParamPattern (Param (gId c) (map ppP ps))
|
||||||
PP (m,c) ps -> ParamPattern (Param ((gQId m c)) (map ppP ps))
|
PP (m,c) ps -> ParamPattern (Param (gQId m c) (map ppP ps))
|
||||||
PR r -> RecordPattern (fields r) {-
|
PR r -> RecordPattern (fields r) {-
|
||||||
PW -> WildPattern
|
PW -> WildPattern
|
||||||
PV x -> VarP x
|
PV x -> VarP x
|
||||||
@@ -202,6 +227,7 @@ convert' gr vs = ppT
|
|||||||
PFloat x -> Lit (show x)
|
PFloat x -> Lit (show x)
|
||||||
PT _ p -> ppP p
|
PT _ p -> ppP p
|
||||||
PAs x p -> AsP x (ppP p) -}
|
PAs x p -> AsP x (ppP p) -}
|
||||||
|
_ -> error $ "convert' ppP: " ++ show p
|
||||||
where
|
where
|
||||||
fields = map field . filter (not.isLockLabel.fst)
|
fields = map field . filter (not.isLockLabel.fst)
|
||||||
field (l,p) = RecordRow (lblId l) (ppP p)
|
field (l,p) = RecordRow (lblId l) (ppP p)
|
||||||
@@ -218,12 +244,12 @@ convert' gr vs = ppT
|
|||||||
pre Empty = [""] -- Empty == K ""
|
pre Empty = [""] -- Empty == K ""
|
||||||
pre (Strs ts) = concatMap pre ts
|
pre (Strs ts) = concatMap pre ts
|
||||||
pre (EPatt p) = pat p
|
pre (EPatt p) = pat p
|
||||||
pre t = error $ "pre "++show t
|
pre t = error $ "convert' alts pre: " ++ show t
|
||||||
|
|
||||||
pat (PString s) = [s]
|
pat (PString s) = [s]
|
||||||
pat (PAlt p1 p2) = pat p1++pat p2
|
pat (PAlt p1 p2) = pat p1++pat p2
|
||||||
pat (PSeq p1 p2) = [s1++s2 | s1<-pat p1, s2<-pat p2]
|
pat (PSeq p1 p2) = [s1++s2 | s1<-pat p1, s2<-pat p2]
|
||||||
pat p = error $ "pat "++show p
|
pat p = error $ "convert' alts pat: "++show p
|
||||||
|
|
||||||
fields = map field . filter (not.isLockLabel.fst)
|
fields = map field . filter (not.isLockLabel.fst)
|
||||||
field (l,(_,t)) = RecordRow (lblId l) (ppT t)
|
field (l,(_,t)) = RecordRow (lblId l) (ppT t)
|
||||||
@@ -236,6 +262,7 @@ convert' gr vs = ppT
|
|||||||
ParamConstant (Param p (ps++[a]))
|
ParamConstant (Param p (ps++[a]))
|
||||||
_ -> error $ "convert' ap: "++render (ppA f <+> ppA a)
|
_ -> error $ "convert' ap: "++render (ppA f <+> ppA a)
|
||||||
|
|
||||||
|
concatValue :: LinValue -> LinValue -> LinValue
|
||||||
concatValue v1 v2 =
|
concatValue v1 v2 =
|
||||||
case (v1,v2) of
|
case (v1,v2) of
|
||||||
(LiteralValue (StrConstant ""),_) -> v2
|
(LiteralValue (StrConstant ""),_) -> v2
|
||||||
@@ -243,21 +270,24 @@ concatValue v1 v2 =
|
|||||||
_ -> ConcatValue v1 v2
|
_ -> ConcatValue v1 v2
|
||||||
|
|
||||||
-- | Smart constructor for projections
|
-- | Smart constructor for projections
|
||||||
projection r l = maybe (Projection r l) id (proj r l)
|
projection :: LinValue -> LabelId -> LinValue
|
||||||
|
projection r l = fromMaybe (Projection r l) (proj r l)
|
||||||
|
|
||||||
|
proj :: LinValue -> LabelId -> Maybe LinValue
|
||||||
proj r l =
|
proj r l =
|
||||||
case r of
|
case r of
|
||||||
RecordValue r -> case [v|RecordRow l' v<-r,l'==l] of
|
RecordValue r -> case [v | RecordRow l' v <- r, l'==l] of
|
||||||
[v] -> Just v
|
[v] -> Just v
|
||||||
_ -> Nothing
|
_ -> Nothing
|
||||||
_ -> Nothing
|
_ -> Nothing
|
||||||
|
|
||||||
-- | Smart constructor for selections
|
-- | Smart constructor for selections
|
||||||
|
selection :: LinValue -> LinValue -> LinValue
|
||||||
selection t v =
|
selection t v =
|
||||||
-- Note: impossible cases can become possible after grammar transformation
|
-- Note: impossible cases can become possible after grammar transformation
|
||||||
case t of
|
case t of
|
||||||
TableValue tt r ->
|
TableValue tt r ->
|
||||||
case nub [rv|TableRow _ rv<-keep] of
|
case nub [rv | TableRow _ rv <- keep] of
|
||||||
[rv] -> rv
|
[rv] -> rv
|
||||||
_ -> Selection (TableValue tt r') v
|
_ -> Selection (TableValue tt r') v
|
||||||
where
|
where
|
||||||
@@ -276,13 +306,16 @@ selection t v =
|
|||||||
(keep,discard) = partition (mightMatchRow v) r
|
(keep,discard) = partition (mightMatchRow v) r
|
||||||
_ -> Selection t v
|
_ -> Selection t v
|
||||||
|
|
||||||
|
impossible :: LinValue -> LinValue
|
||||||
impossible = CommentedValue "impossible"
|
impossible = CommentedValue "impossible"
|
||||||
|
|
||||||
|
mightMatchRow :: LinValue -> TableRow rhs -> Bool
|
||||||
mightMatchRow v (TableRow p _) =
|
mightMatchRow v (TableRow p _) =
|
||||||
case p of
|
case p of
|
||||||
WildPattern -> True
|
WildPattern -> True
|
||||||
_ -> mightMatch v p
|
_ -> mightMatch v p
|
||||||
|
|
||||||
|
mightMatch :: LinValue -> LinPattern -> Bool
|
||||||
mightMatch v p =
|
mightMatch v p =
|
||||||
case v of
|
case v of
|
||||||
ConcatValue _ _ -> False
|
ConcatValue _ _ -> False
|
||||||
@@ -294,16 +327,18 @@ mightMatch v p =
|
|||||||
RecordValue rv ->
|
RecordValue rv ->
|
||||||
case p of
|
case p of
|
||||||
RecordPattern rp ->
|
RecordPattern rp ->
|
||||||
and [maybe False (flip mightMatch p) (proj v l) | RecordRow l p<-rp]
|
and [maybe False (`mightMatch` p) (proj v l) | RecordRow l p<-rp]
|
||||||
_ -> False
|
_ -> False
|
||||||
_ -> True
|
_ -> True
|
||||||
|
|
||||||
|
patVars :: Patt -> [Ident]
|
||||||
patVars p =
|
patVars p =
|
||||||
case p of
|
case p of
|
||||||
PV x -> [x]
|
PV x -> [x]
|
||||||
PAs x p -> x:patVars p
|
PAs x p -> x:patVars p
|
||||||
_ -> collectPattOp patVars p
|
_ -> collectPattOp patVars p
|
||||||
|
|
||||||
|
convType :: Term -> LinType
|
||||||
convType = ppT
|
convType = ppT
|
||||||
where
|
where
|
||||||
ppT t =
|
ppT t =
|
||||||
@@ -315,9 +350,9 @@ convType = ppT
|
|||||||
Sort k -> convSort k
|
Sort k -> convSort k
|
||||||
-- EInt n -> tcon0 (identS ("({-"++show n++"-})")) -- type level numeric literal
|
-- EInt n -> tcon0 (identS ("({-"++show n++"-})")) -- type level numeric literal
|
||||||
FV (t:ts) -> ppT t -- !!
|
FV (t:ts) -> ppT t -- !!
|
||||||
QC (m,n) -> ParamType (ParamTypeId ((gQId m n)))
|
QC (m,n) -> ParamType (ParamTypeId (gQId m n))
|
||||||
Q (m,n) -> ParamType (ParamTypeId ((gQId m n)))
|
Q (m,n) -> ParamType (ParamTypeId (gQId m n))
|
||||||
_ -> error $ "Missing case in convType for: "++show t
|
_ -> error $ "convType ppT: " ++ show t
|
||||||
|
|
||||||
convFields = map convField . filter (not.isLockLabel.fst)
|
convFields = map convField . filter (not.isLockLabel.fst)
|
||||||
convField (l,r) = RecordRow (lblId l) (ppT r)
|
convField (l,r) = RecordRow (lblId l) (ppT r)
|
||||||
@@ -326,15 +361,20 @@ convType = ppT
|
|||||||
"Float" -> FloatType
|
"Float" -> FloatType
|
||||||
"Int" -> IntType
|
"Int" -> IntType
|
||||||
"Str" -> StrType
|
"Str" -> StrType
|
||||||
_ -> error ("convSort "++show k)
|
_ -> error $ "convType convSort: " ++ show k
|
||||||
|
|
||||||
|
toParamType :: Term -> ParamType
|
||||||
toParamType t = case convType t of
|
toParamType t = case convType t of
|
||||||
ParamType pt -> pt
|
ParamType pt -> pt
|
||||||
_ -> error ("toParamType "++show t)
|
_ -> error $ "toParamType: " ++ show t
|
||||||
|
|
||||||
|
toParamId :: Term -> ParamId
|
||||||
toParamId t = case toParamType t of
|
toParamId t = case toParamType t of
|
||||||
ParamTypeId p -> p
|
ParamTypeId p -> p
|
||||||
|
|
||||||
|
paramType :: G.Grammar
|
||||||
|
-> (ModuleName, Ident)
|
||||||
|
-> ((S.Set (ModuleName, Ident), S.Set QIdent), [ParamDef])
|
||||||
paramType gr q@(_,n) =
|
paramType gr q@(_,n) =
|
||||||
case lookupOrigInfo gr q of
|
case lookupOrigInfo gr q of
|
||||||
Ok (m,ResParam (Just (L _ ps)) _)
|
Ok (m,ResParam (Just (L _ ps)) _)
|
||||||
@@ -342,7 +382,7 @@ paramType gr q@(_,n) =
|
|||||||
((S.singleton (m,n),argTypes ps),
|
((S.singleton (m,n),argTypes ps),
|
||||||
[ParamDef name (map (param m) ps)]
|
[ParamDef name (map (param m) ps)]
|
||||||
)
|
)
|
||||||
where name = (gQId m n)
|
where name = gQId m n
|
||||||
Ok (m,ResOper _ (Just (L _ t)))
|
Ok (m,ResOper _ (Just (L _ t)))
|
||||||
| m==cPredef && n==cInts ->
|
| m==cPredef && n==cInts ->
|
||||||
((S.empty,S.empty),[]) {-
|
((S.empty,S.empty),[]) {-
|
||||||
@@ -350,36 +390,46 @@ paramType gr q@(_,n) =
|
|||||||
[Type (ConAp ((gQId m n)) [identS "n"]) (TId (identS "Int"))])-}
|
[Type (ConAp ((gQId m n)) [identS "n"]) (TId (identS "Int"))])-}
|
||||||
| otherwise ->
|
| otherwise ->
|
||||||
((S.singleton (m,n),paramTypes gr t),
|
((S.singleton (m,n),paramTypes gr t),
|
||||||
[ParamAliasDef ((gQId m n)) (convType t)])
|
[ParamAliasDef (gQId m n) (convType t)])
|
||||||
_ -> ((S.empty,S.empty),[])
|
_ -> ((S.empty,S.empty),[])
|
||||||
where
|
where
|
||||||
param m (n,ctx) = Param ((gQId m n)) [toParamId t|(_,_,t)<-ctx]
|
param m (n,ctx) = Param (gQId m n) [toParamId t|(_,_,t)<-ctx]
|
||||||
argTypes = S.unions . map argTypes1
|
argTypes = S.unions . map argTypes1
|
||||||
argTypes1 (n,ctx) = S.unions [paramTypes gr t|(_,_,t)<-ctx]
|
argTypes1 (n,ctx) = S.unions [paramTypes gr t|(_,_,t)<-ctx]
|
||||||
|
|
||||||
lblId = LabelId . render -- hmm
|
lblId :: Label -> C.LabelId
|
||||||
modId (MN m) = ModId (showIdent m)
|
lblId (LIdent ri) = LabelId ri
|
||||||
|
lblId (LVar i) = LabelId (rawIdentS (show i)) -- hmm
|
||||||
|
|
||||||
class FromIdent i where gId :: Ident -> i
|
modId :: ModuleName -> C.ModId
|
||||||
|
modId (MN m) = ModId (ident2raw m)
|
||||||
|
|
||||||
|
class FromIdent i where
|
||||||
|
gId :: Ident -> i
|
||||||
|
|
||||||
instance FromIdent VarId where
|
instance FromIdent VarId where
|
||||||
gId i = if isWildIdent i then Anonymous else VarId (showIdent i)
|
gId i = if isWildIdent i then Anonymous else VarId (ident2raw i)
|
||||||
|
|
||||||
instance FromIdent C.FunId where gId = C.FunId . showIdent
|
instance FromIdent C.FunId where gId = C.FunId . ident2raw
|
||||||
instance FromIdent CatId where gId = CatId . showIdent
|
instance FromIdent CatId where gId = CatId . ident2raw
|
||||||
instance FromIdent ParamId where gId = ParamId . unqual
|
instance FromIdent ParamId where gId = ParamId . unqual
|
||||||
instance FromIdent VarValueId where gId = VarValueId . unqual
|
instance FromIdent VarValueId where gId = VarValueId . unqual
|
||||||
|
|
||||||
class FromIdent i => QualIdent i where gQId :: ModuleName -> Ident -> i
|
class FromIdent i => QualIdent i where
|
||||||
|
gQId :: ModuleName -> Ident -> i
|
||||||
|
|
||||||
instance QualIdent ParamId where gQId m n = ParamId (qual m n)
|
instance QualIdent ParamId where gQId m n = ParamId (qual m n)
|
||||||
instance QualIdent VarValueId where gQId m n = VarValueId (qual m n)
|
instance QualIdent VarValueId where gQId m n = VarValueId (qual m n)
|
||||||
|
|
||||||
qual m n = Qual (modId m) (showIdent n)
|
qual :: ModuleName -> Ident -> QualId
|
||||||
unqual n = Unqual (showIdent n)
|
qual m n = Qual (modId m) (ident2raw n)
|
||||||
|
|
||||||
|
unqual :: Ident -> QualId
|
||||||
|
unqual n = Unqual (ident2raw n)
|
||||||
|
|
||||||
|
convFlags :: G.Grammar -> ModuleName -> Flags
|
||||||
convFlags gr mn =
|
convFlags gr mn =
|
||||||
Flags [(n,convLit v) |
|
Flags [(rawIdentS n,convLit v) |
|
||||||
(n,v)<-err (const []) (optionsPGF.mflags) (lookupModule gr mn)]
|
(n,v)<-err (const []) (optionsPGF.mflags) (lookupModule gr mn)]
|
||||||
where
|
where
|
||||||
convLit l =
|
convLit l =
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
{-# LANGUAGE BangPatterns, FlexibleContexts, MagicHash #-}
|
{-# LANGUAGE BangPatterns, FlexibleContexts #-}
|
||||||
module GF.Compile.GrammarToPGF (mkCanon2pgf) where
|
module GF.Compile.GrammarToPGF (mkCanon2pgf) where
|
||||||
|
|
||||||
--import GF.Compile.Export
|
--import GF.Compile.Export
|
||||||
@@ -8,16 +8,13 @@ import GF.Compile.GenerateBC
|
|||||||
import PGF(CId,mkCId,utf8CId)
|
import PGF(CId,mkCId,utf8CId)
|
||||||
import PGF.Internal(fidInt,fidFloat,fidString,fidVar)
|
import PGF.Internal(fidInt,fidFloat,fidString,fidVar)
|
||||||
import PGF.Internal(updateProductionIndices)
|
import PGF.Internal(updateProductionIndices)
|
||||||
--import qualified PGF.Macros as CM
|
|
||||||
import qualified PGF.Internal as C
|
import qualified PGF.Internal as C
|
||||||
import qualified PGF.Internal as D
|
import qualified PGF.Internal as D
|
||||||
import GF.Grammar.Predef
|
import GF.Grammar.Predef
|
||||||
--import GF.Grammar.Printer
|
|
||||||
import GF.Grammar.Grammar
|
import GF.Grammar.Grammar
|
||||||
import qualified GF.Grammar.Lookup as Look
|
import qualified GF.Grammar.Lookup as Look
|
||||||
import qualified GF.Grammar as A
|
import qualified GF.Grammar as A
|
||||||
import qualified GF.Grammar.Macros as GM
|
import qualified GF.Grammar.Macros as GM
|
||||||
--import GF.Compile.GeneratePMCFG
|
|
||||||
|
|
||||||
import GF.Infra.Ident
|
import GF.Infra.Ident
|
||||||
import GF.Infra.Option
|
import GF.Infra.Option
|
||||||
@@ -30,9 +27,6 @@ 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.Char
|
|
||||||
import GHC.Prim
|
|
||||||
import GHC.Base(getTag)
|
|
||||||
|
|
||||||
mkCanon2pgf :: Options -> SourceGrammar -> ModuleName -> IOE D.PGF
|
mkCanon2pgf :: Options -> SourceGrammar -> ModuleName -> IOE D.PGF
|
||||||
mkCanon2pgf opts gr am = do
|
mkCanon2pgf opts gr am = do
|
||||||
@@ -65,7 +59,7 @@ mkCanon2pgf opts gr am = do
|
|||||||
mkConcr cm = do
|
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 = compareCaseInsensitve
|
| otherwise = C.compareCaseInsensitve
|
||||||
|
|
||||||
(ex_seqs,cdefs) <- addMissingPMCFGs
|
(ex_seqs,cdefs) <- addMissingPMCFGs
|
||||||
Map.empty
|
Map.empty
|
||||||
@@ -74,7 +68,7 @@ mkCanon2pgf opts gr am = do
|
|||||||
|
|
||||||
let flags = Map.fromList [(mkCId f,x) | (f,x) <- optionsPGF cflags]
|
let flags = Map.fromList [(mkCId f,x) | (f,x) <- optionsPGF cflags]
|
||||||
|
|
||||||
seqs = (mkArray . sortNubBy ciCmp . concat) $
|
seqs = (mkArray . C.sortNubBy ciCmp . concat) $
|
||||||
(Map.keys ex_seqs : [maybe [] elems (mseqs mi) | (m,mi) <- allExtends gr cm])
|
(Map.keys ex_seqs : [maybe [] elems (mseqs mi) | (m,mi) <- allExtends gr cm])
|
||||||
|
|
||||||
ex_seqs_arr = mkMapArray ex_seqs :: Array SeqId Sequence
|
ex_seqs_arr = mkMapArray ex_seqs :: Array SeqId Sequence
|
||||||
@@ -312,119 +306,3 @@ genPrintNames cdefs =
|
|||||||
|
|
||||||
mkArray lst = listArray (0,length lst-1) lst
|
mkArray lst = listArray (0,length lst-1) lst
|
||||||
mkMapArray map = array (0,Map.size map-1) [(v,k) | (k,v) <- Map.toList map]
|
mkMapArray map = array (0,Map.size map-1) [(v,k) | (k,v) <- Map.toList map]
|
||||||
|
|
||||||
-- 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.
|
|
||||||
compareCaseInsensitve s1 s2 =
|
|
||||||
compareSeq (elems s1) (elems s2)
|
|
||||||
where
|
|
||||||
compareSeq [] [] = EQ
|
|
||||||
compareSeq [] _ = LT
|
|
||||||
compareSeq _ [] = GT
|
|
||||||
compareSeq (x:xs) (y:ys) =
|
|
||||||
case compareSym x y of
|
|
||||||
EQ -> compareSeq xs ys
|
|
||||||
x -> x
|
|
||||||
|
|
||||||
compareSym s1 s2 =
|
|
||||||
case s1 of
|
|
||||||
D.SymCat d1 r1
|
|
||||||
-> case s2 of
|
|
||||||
D.SymCat d2 r2
|
|
||||||
-> case compare d1 d2 of
|
|
||||||
EQ -> r1 `compare` r2
|
|
||||||
x -> x
|
|
||||||
_ -> LT
|
|
||||||
D.SymLit d1 r1
|
|
||||||
-> case s2 of
|
|
||||||
D.SymCat {} -> GT
|
|
||||||
D.SymLit d2 r2
|
|
||||||
-> case compare d1 d2 of
|
|
||||||
EQ -> r1 `compare` r2
|
|
||||||
x -> x
|
|
||||||
_ -> LT
|
|
||||||
D.SymVar d1 r1
|
|
||||||
-> if tagToEnum# (getTag s2 ># 2#)
|
|
||||||
then LT
|
|
||||||
else case s2 of
|
|
||||||
D.SymVar d2 r2
|
|
||||||
-> case compare d1 d2 of
|
|
||||||
EQ -> r1 `compare` r2
|
|
||||||
x -> x
|
|
||||||
_ -> GT
|
|
||||||
D.SymKS t1
|
|
||||||
-> if tagToEnum# (getTag s2 ># 3#)
|
|
||||||
then LT
|
|
||||||
else case s2 of
|
|
||||||
D.SymKS t2 -> t1 `compareToken` t2
|
|
||||||
_ -> GT
|
|
||||||
D.SymKP a1 b1
|
|
||||||
-> if tagToEnum# (getTag s2 ># 4#)
|
|
||||||
then LT
|
|
||||||
else case s2 of
|
|
||||||
D.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
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import GF.Grammar.Printer
|
|||||||
import GF.Grammar.Macros
|
import GF.Grammar.Macros
|
||||||
import GF.Grammar.Lookup
|
import GF.Grammar.Lookup
|
||||||
import GF.Grammar.Predef
|
import GF.Grammar.Predef
|
||||||
import GF.Compile.Compute.ConcreteNew(GlobalEnv,normalForm,resourceValues)
|
import GF.Compile.Compute.Concrete(GlobalEnv,normalForm,resourceValues)
|
||||||
import GF.Data.Operations
|
import GF.Data.Operations
|
||||||
import GF.Infra.Option
|
import GF.Infra.Option
|
||||||
|
|
||||||
|
|||||||
@@ -22,10 +22,11 @@ import PGF.Internal
|
|||||||
import GF.Data.Operations
|
import GF.Data.Operations
|
||||||
import GF.Infra.Option
|
import GF.Infra.Option
|
||||||
|
|
||||||
import Data.List --(isPrefixOf, find, intersperse)
|
import Data.List(isPrefixOf,find,intercalate,intersperse,groupBy,sortBy)
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
|
|
||||||
type Prefix = String -> String
|
type Prefix = String -> String
|
||||||
|
type DerivingClause = String
|
||||||
|
|
||||||
-- | the main function
|
-- | the main function
|
||||||
grammar2haskell :: Options
|
grammar2haskell :: Options
|
||||||
@@ -33,30 +34,40 @@ grammar2haskell :: Options
|
|||||||
-> PGF
|
-> PGF
|
||||||
-> String
|
-> String
|
||||||
grammar2haskell opts name gr = foldr (++++) [] $
|
grammar2haskell opts name gr = foldr (++++) [] $
|
||||||
pragmas ++ haskPreamble gadt name ++ [types, gfinstances gId lexical gr'] ++ compos
|
pragmas ++ haskPreamble gadt name derivingClause (extraImports ++ pgfImports) ++
|
||||||
|
[types, gfinstances gId lexical gr'] ++ compos
|
||||||
where gr' = hSkeleton gr
|
where gr' = hSkeleton gr
|
||||||
gadt = haskellOption opts HaskellGADT
|
gadt = haskellOption opts HaskellGADT
|
||||||
|
dataExt = haskellOption opts HaskellData
|
||||||
|
pgf2 = haskellOption opts HaskellPGF2
|
||||||
lexical cat = haskellOption opts HaskellLexical && isLexicalCat opts cat
|
lexical cat = haskellOption opts HaskellLexical && isLexicalCat opts cat
|
||||||
gId | haskellOption opts HaskellNoPrefix = id
|
gId | haskellOption opts HaskellNoPrefix = rmForbiddenChars
|
||||||
| otherwise = ("G"++)
|
| otherwise = ("G"++) . rmForbiddenChars
|
||||||
pragmas | gadt = ["{-# OPTIONS_GHC -fglasgow-exts #-}","{-# LANGUAGE GADTs #-}"]
|
-- GF grammars allow weird identifier names inside '', e.g. 'VP/Object'
|
||||||
|
rmForbiddenChars = filter (`notElem` "'!#$%&*+./<=>?@\\^|-~")
|
||||||
|
pragmas | gadt = ["{-# LANGUAGE GADTs, FlexibleInstances, KindSignatures, RankNTypes, TypeSynonymInstances #-}"]
|
||||||
|
| dataExt = ["{-# LANGUAGE DeriveDataTypeable #-}"]
|
||||||
| otherwise = []
|
| otherwise = []
|
||||||
|
derivingClause
|
||||||
|
| dataExt = "deriving (Show,Data)"
|
||||||
|
| otherwise = "deriving Show"
|
||||||
|
extraImports | gadt = ["import Control.Monad.Identity", "import Data.Monoid"]
|
||||||
|
| dataExt = ["import Data.Data"]
|
||||||
|
| otherwise = []
|
||||||
|
pgfImports | pgf2 = ["import PGF2 hiding (Tree)", "", "showCId :: CId -> String", "showCId = id"]
|
||||||
|
| otherwise = ["import PGF hiding (Tree)"]
|
||||||
types | gadt = datatypesGADT gId lexical gr'
|
types | gadt = datatypesGADT gId lexical gr'
|
||||||
| otherwise = datatypes gId lexical gr'
|
| otherwise = datatypes gId derivingClause lexical gr'
|
||||||
compos | gadt = prCompos gId lexical gr' ++ composClass
|
compos | gadt = prCompos gId lexical gr' ++ composClass
|
||||||
| otherwise = []
|
| otherwise = []
|
||||||
|
|
||||||
haskPreamble gadt name =
|
haskPreamble :: Bool -> String -> String -> [String] -> [String]
|
||||||
|
haskPreamble gadt name derivingClause imports =
|
||||||
[
|
[
|
||||||
"module " ++ name ++ " where",
|
"module " ++ name ++ " where",
|
||||||
""
|
""
|
||||||
] ++
|
] ++ imports ++ [
|
||||||
(if gadt then [
|
"",
|
||||||
"import Control.Monad.Identity",
|
|
||||||
"import Data.Monoid"
|
|
||||||
] else []) ++
|
|
||||||
[
|
|
||||||
"import PGF hiding (Tree)",
|
|
||||||
"----------------------------------------------------",
|
"----------------------------------------------------",
|
||||||
"-- automatic translation from GF to Haskell",
|
"-- automatic translation from GF to Haskell",
|
||||||
"----------------------------------------------------",
|
"----------------------------------------------------",
|
||||||
@@ -65,11 +76,11 @@ haskPreamble gadt name =
|
|||||||
" gf :: a -> Expr",
|
" gf :: a -> Expr",
|
||||||
" fg :: Expr -> a",
|
" fg :: Expr -> a",
|
||||||
"",
|
"",
|
||||||
predefInst gadt "GString" "String" "unStr" "mkStr",
|
predefInst gadt derivingClause "GString" "String" "unStr" "mkStr",
|
||||||
"",
|
"",
|
||||||
predefInst gadt "GInt" "Int" "unInt" "mkInt",
|
predefInst gadt derivingClause "GInt" "Int" "unInt" "mkInt",
|
||||||
"",
|
"",
|
||||||
predefInst gadt "GFloat" "Double" "unFloat" "mkFloat",
|
predefInst gadt derivingClause "GFloat" "Double" "unFloat" "mkFloat",
|
||||||
"",
|
"",
|
||||||
"----------------------------------------------------",
|
"----------------------------------------------------",
|
||||||
"-- below this line machine-generated",
|
"-- below this line machine-generated",
|
||||||
@@ -77,10 +88,11 @@ haskPreamble gadt name =
|
|||||||
""
|
""
|
||||||
]
|
]
|
||||||
|
|
||||||
predefInst gadt gtyp typ destr consr =
|
predefInst :: Bool -> String -> String -> String -> String -> String -> String
|
||||||
|
predefInst gadt derivingClause gtyp typ destr consr =
|
||||||
(if gadt
|
(if gadt
|
||||||
then []
|
then []
|
||||||
else ("newtype" +++ gtyp +++ "=" +++ gtyp +++ typ +++ " deriving Show\n\n")
|
else "newtype" +++ gtyp +++ "=" +++ gtyp +++ typ +++ derivingClause ++ "\n\n"
|
||||||
)
|
)
|
||||||
++
|
++
|
||||||
"instance Gf" +++ gtyp +++ "where" ++++
|
"instance Gf" +++ gtyp +++ "where" ++++
|
||||||
@@ -94,24 +106,24 @@ type OIdent = String
|
|||||||
|
|
||||||
type HSkeleton = [(OIdent, [(OIdent, [OIdent])])]
|
type HSkeleton = [(OIdent, [(OIdent, [OIdent])])]
|
||||||
|
|
||||||
datatypes :: Prefix -> (OIdent -> Bool) -> (String,HSkeleton) -> String
|
datatypes :: Prefix -> DerivingClause -> (OIdent -> Bool) -> (String,HSkeleton) -> String
|
||||||
datatypes gId lexical = (foldr (+++++) "") . (filter (/="")) . (map (hDatatype gId lexical)) . snd
|
datatypes gId derivingClause lexical = foldr (+++++) "" . filter (/="") . map (hDatatype gId derivingClause lexical) . snd
|
||||||
|
|
||||||
gfinstances :: Prefix -> (OIdent -> Bool) -> (String,HSkeleton) -> String
|
gfinstances :: Prefix -> (OIdent -> Bool) -> (String,HSkeleton) -> String
|
||||||
gfinstances gId lexical (m,g) = (foldr (+++++) "") $ (filter (/="")) $ (map (gfInstance gId lexical m)) g
|
gfinstances gId lexical (m,g) = foldr (+++++) "" $ filter (/="") $ map (gfInstance gId lexical m) g
|
||||||
|
|
||||||
|
|
||||||
hDatatype :: Prefix -> (OIdent -> Bool) -> (OIdent, [(OIdent, [OIdent])]) -> String
|
hDatatype :: Prefix -> DerivingClause -> (OIdent -> Bool) -> (OIdent, [(OIdent, [OIdent])]) -> String
|
||||||
hDatatype _ _ ("Cn",_) = "" ---
|
hDatatype _ _ _ ("Cn",_) = "" ---
|
||||||
hDatatype gId _ (cat,[]) = "data" +++ gId cat
|
hDatatype gId _ _ (cat,[]) = "data" +++ gId cat
|
||||||
hDatatype gId _ (cat,rules) | isListCat (cat,rules) =
|
hDatatype gId derivingClause _ (cat,rules) | isListCat (cat,rules) =
|
||||||
"newtype" +++ gId cat +++ "=" +++ gId cat +++ "[" ++ gId (elemCat cat) ++ "]"
|
"newtype" +++ gId cat +++ "=" +++ gId cat +++ "[" ++ gId (elemCat cat) ++ "]"
|
||||||
+++ "deriving Show"
|
+++ derivingClause
|
||||||
hDatatype gId lexical (cat,rules) =
|
hDatatype gId derivingClause lexical (cat,rules) =
|
||||||
"data" +++ gId cat +++ "=" ++
|
"data" +++ gId cat +++ "=" ++
|
||||||
(if length rules == 1 then "" else "\n ") +++
|
(if length rules == 1 then "" else "\n ") +++
|
||||||
foldr1 (\x y -> x ++ "\n |" +++ y) constructors ++++
|
foldr1 (\x y -> x ++ "\n |" +++ y) constructors ++++
|
||||||
" deriving Show"
|
" " +++ derivingClause
|
||||||
where
|
where
|
||||||
constructors = [gId f +++ foldr (+++) "" (map (gId) xx) | (f,xx) <- nonLexicalRules (lexical cat) rules]
|
constructors = [gId f +++ foldr (+++) "" (map (gId) xx) | (f,xx) <- nonLexicalRules (lexical cat) rules]
|
||||||
++ if lexical cat then [lexicalConstructor cat +++ "String"] else []
|
++ if lexical cat then [lexicalConstructor cat +++ "String"] else []
|
||||||
@@ -123,6 +135,7 @@ nonLexicalRules True rules = [r | r@(f,t) <- rules, not (null t)]
|
|||||||
lexicalConstructor :: OIdent -> String
|
lexicalConstructor :: OIdent -> String
|
||||||
lexicalConstructor cat = "Lex" ++ cat
|
lexicalConstructor cat = "Lex" ++ cat
|
||||||
|
|
||||||
|
predefTypeSkel :: HSkeleton
|
||||||
predefTypeSkel = [(c,[]) | c <- ["String", "Int", "Float"]]
|
predefTypeSkel = [(c,[]) | c <- ["String", "Int", "Float"]]
|
||||||
|
|
||||||
-- GADT version of data types
|
-- GADT version of data types
|
||||||
@@ -195,11 +208,12 @@ prCompos gId lexical (_,catrules) =
|
|||||||
prRec f (v,c)
|
prRec f (v,c)
|
||||||
| isList f = "`a` foldr (a . a (r (:)) . f) (r [])" +++ v
|
| isList f = "`a` foldr (a . a (r (:)) . f) (r [])" +++ v
|
||||||
| otherwise = "`a`" +++ "f" +++ v
|
| otherwise = "`a`" +++ "f" +++ v
|
||||||
isList f = (gId "List") `isPrefixOf` f
|
isList f = gId "List" `isPrefixOf` f
|
||||||
|
|
||||||
gfInstance :: Prefix -> (OIdent -> Bool) -> String -> (OIdent, [(OIdent, [OIdent])]) -> String
|
gfInstance :: Prefix -> (OIdent -> Bool) -> String -> (OIdent, [(OIdent, [OIdent])]) -> String
|
||||||
gfInstance gId lexical m crs = hInstance gId lexical m crs ++++ fInstance gId lexical m crs
|
gfInstance gId lexical m crs = hInstance gId lexical m crs ++++ fInstance gId lexical m crs
|
||||||
|
|
||||||
|
hInstance :: (String -> String) -> (String -> Bool) -> String -> (String, [(OIdent, [OIdent])]) -> String
|
||||||
----hInstance m ("Cn",_) = "" --- seems to belong to an old applic. AR 18/5/2004
|
----hInstance m ("Cn",_) = "" --- seems to belong to an old applic. AR 18/5/2004
|
||||||
hInstance gId _ m (cat,[]) = unlines [
|
hInstance gId _ m (cat,[]) = unlines [
|
||||||
"instance Show" +++ gId cat,
|
"instance Show" +++ gId cat,
|
||||||
@@ -211,7 +225,7 @@ hInstance gId _ m (cat,[]) = unlines [
|
|||||||
hInstance gId lexical m (cat,rules)
|
hInstance gId lexical m (cat,rules)
|
||||||
| isListCat (cat,rules) =
|
| isListCat (cat,rules) =
|
||||||
"instance Gf" +++ gId cat +++ "where" ++++
|
"instance Gf" +++ gId cat +++ "where" ++++
|
||||||
" gf (" ++ gId cat +++ "[" ++ concat (intersperse "," baseVars) ++ "])"
|
" gf (" ++ gId cat +++ "[" ++ intercalate "," baseVars ++ "])"
|
||||||
+++ "=" +++ mkRHS ("Base"++ec) baseVars ++++
|
+++ "=" +++ mkRHS ("Base"++ec) baseVars ++++
|
||||||
" gf (" ++ gId cat +++ "(x:xs)) = "
|
" gf (" ++ gId cat +++ "(x:xs)) = "
|
||||||
++ mkRHS ("Cons"++ec) ["x",prParenth (gId cat+++"xs")]
|
++ mkRHS ("Cons"++ec) ["x",prParenth (gId cat+++"xs")]
|
||||||
@@ -225,12 +239,15 @@ hInstance gId lexical m (cat,rules)
|
|||||||
ec = elemCat cat
|
ec = elemCat cat
|
||||||
baseVars = mkVars (baseSize (cat,rules))
|
baseVars = mkVars (baseSize (cat,rules))
|
||||||
mkInst f xx = let xx' = mkVars (length xx) in " gf " ++
|
mkInst f xx = let xx' = mkVars (length xx) in " gf " ++
|
||||||
(if length xx == 0 then gId f else prParenth (gId f +++ foldr1 (+++) xx')) +++
|
(if null xx then gId f else prParenth (gId f +++ foldr1 (+++) xx')) +++
|
||||||
"=" +++ mkRHS f xx'
|
"=" +++ mkRHS f xx'
|
||||||
mkRHS f vars = "mkApp (mkCId \"" ++ f ++ "\")" +++
|
mkRHS f vars = "mkApp (mkCId \"" ++ f ++ "\")" +++
|
||||||
"[" ++ prTList ", " ["gf" +++ x | x <- vars] ++ "]"
|
"[" ++ prTList ", " ["gf" +++ x | x <- vars] ++ "]"
|
||||||
|
|
||||||
|
mkVars :: Int -> [String]
|
||||||
mkVars = mkSVars "x"
|
mkVars = mkSVars "x"
|
||||||
|
|
||||||
|
mkSVars :: String -> Int -> [String]
|
||||||
mkSVars s n = [s ++ show i | i <- [1..n]]
|
mkSVars s n = [s ++ show i | i <- [1..n]]
|
||||||
|
|
||||||
----fInstance m ("Cn",_) = "" ---
|
----fInstance m ("Cn",_) = "" ---
|
||||||
@@ -249,7 +266,8 @@ fInstance gId lexical m (cat,rules) =
|
|||||||
" Just (i," ++
|
" Just (i," ++
|
||||||
"[" ++ prTList "," xx' ++ "])" +++
|
"[" ++ prTList "," xx' ++ "])" +++
|
||||||
"| i == mkCId \"" ++ f ++ "\" ->" +++ mkRHS f xx'
|
"| i == mkCId \"" ++ f ++ "\" ->" +++ mkRHS f xx'
|
||||||
where xx' = ["x" ++ show i | (_,i) <- zip xx [1..]]
|
where
|
||||||
|
xx' = ["x" ++ show i | (_,i) <- zip xx [1..]]
|
||||||
mkRHS f vars
|
mkRHS f vars
|
||||||
| isList =
|
| isList =
|
||||||
if "Base" `isPrefixOf` f
|
if "Base" `isPrefixOf` f
|
||||||
@@ -266,7 +284,7 @@ hSkeleton gr =
|
|||||||
let fs =
|
let fs =
|
||||||
[(showCId c, [(showCId f, map showCId cs) | (f, (cs,_)) <- fs]) |
|
[(showCId c, [(showCId f, map showCId cs) | (f, (cs,_)) <- fs]) |
|
||||||
fs@((_, (_,c)):_) <- fns]
|
fs@((_, (_,c)):_) <- fns]
|
||||||
in fs ++ [(sc, []) | c <- cts, let sc = showCId c, notElem sc (["Int", "Float", "String"] ++ map fst fs)]
|
in fs ++ [(sc, []) | c <- cts, let sc = showCId c, sc `notElem` (["Int", "Float", "String"] ++ map fst fs)]
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
cts = Map.keys (cats (abstract gr))
|
cts = Map.keys (cats (abstract gr))
|
||||||
@@ -284,7 +302,8 @@ updateSkeleton cat skel rule =
|
|||||||
isListCat :: (OIdent, [(OIdent, [OIdent])]) -> Bool
|
isListCat :: (OIdent, [(OIdent, [OIdent])]) -> Bool
|
||||||
isListCat (cat,rules) = "List" `isPrefixOf` cat && length rules == 2
|
isListCat (cat,rules) = "List" `isPrefixOf` cat && length rules == 2
|
||||||
&& ("Base"++c) `elem` fs && ("Cons"++c) `elem` fs
|
&& ("Base"++c) `elem` fs && ("Cons"++c) `elem` fs
|
||||||
where c = elemCat cat
|
where
|
||||||
|
c = elemCat cat
|
||||||
fs = map fst rules
|
fs = map fst rules
|
||||||
|
|
||||||
-- | Gets the element category of a list category.
|
-- | Gets the element category of a list category.
|
||||||
@@ -329,4 +348,3 @@ composClass =
|
|||||||
"",
|
"",
|
||||||
"newtype C b a = C { unC :: b }"
|
"newtype C b a = C { unC :: b }"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ import GF.Data.Operations
|
|||||||
|
|
||||||
import Control.Monad
|
import Control.Monad
|
||||||
import Data.List (nub,(\\))
|
import Data.List (nub,(\\))
|
||||||
|
import qualified Data.List as L
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
import Data.Maybe(mapMaybe)
|
import Data.Maybe(mapMaybe)
|
||||||
import GF.Text.Pretty
|
import GF.Text.Pretty
|
||||||
@@ -105,7 +106,26 @@ renameIdentTerm' env@(act,imps) t0 =
|
|||||||
ts@(t:_) -> do checkWarn ("atomic term" <+> ppTerm Qualified 0 t0 $$
|
ts@(t:_) -> do checkWarn ("atomic term" <+> ppTerm Qualified 0 t0 $$
|
||||||
"conflict" <+> hsep (punctuate ',' (map (ppTerm Qualified 0) ts)) $$
|
"conflict" <+> hsep (punctuate ',' (map (ppTerm Qualified 0) ts)) $$
|
||||||
"given" <+> fsep (punctuate ',' (map fst qualifs)))
|
"given" <+> fsep (punctuate ',' (map fst qualifs)))
|
||||||
return t
|
return (bestTerm ts) -- Heuristic for resource grammar. Returns t for all others.
|
||||||
|
where
|
||||||
|
-- Hotfix for https://github.com/GrammaticalFramework/gf-core/issues/56
|
||||||
|
-- Real bug is probably somewhere deeper in recognising excluded functions. /IL 2020-06-06
|
||||||
|
notFromCommonModule :: Term -> Bool
|
||||||
|
notFromCommonModule term =
|
||||||
|
let t = render $ ppTerm Qualified 0 term :: String
|
||||||
|
in not $ any (\moduleName -> moduleName `L.isPrefixOf` t)
|
||||||
|
["CommonX", "ConstructX", "ExtendFunctor"
|
||||||
|
,"MarkHTMLX", "ParamX", "TenseX", "TextX"]
|
||||||
|
|
||||||
|
-- If one of the terms comes from the common modules,
|
||||||
|
-- we choose the other one, because that's defined in the grammar.
|
||||||
|
bestTerm :: [Term] -> Term
|
||||||
|
bestTerm [] = error "constant not found" -- not reached: bestTerm is only called for case ts@(t:_)
|
||||||
|
bestTerm ts@(t:_) =
|
||||||
|
let notCommon = [t | t <- ts, notFromCommonModule t]
|
||||||
|
in case notCommon of
|
||||||
|
[] -> t -- All terms are from common modules, return first of original list
|
||||||
|
(u:_) -> u -- ≥1 terms are not from common modules, return first of those
|
||||||
|
|
||||||
info2status :: Maybe ModuleName -> Ident -> Info -> StatusInfo
|
info2status :: Maybe ModuleName -> Ident -> Info -> StatusInfo
|
||||||
info2status mq c i = case i of
|
info2status mq c i = case i of
|
||||||
@@ -236,7 +256,7 @@ renamePattern :: Status -> Patt -> Check (Patt,[Ident])
|
|||||||
renamePattern env patt =
|
renamePattern env patt =
|
||||||
do r@(p',vs) <- renp patt
|
do r@(p',vs) <- renp patt
|
||||||
let dupl = vs \\ nub vs
|
let dupl = vs \\ nub vs
|
||||||
unless (null dupl) $ checkError (hang ("[C.4.13] Pattern is not linear:") 4
|
unless (null dupl) $ checkError (hang ("[C.4.13] Pattern is not linear. All variable names on the left-hand side must be distinct.") 4
|
||||||
patt)
|
patt)
|
||||||
return r
|
return r
|
||||||
where
|
where
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
{-# LANGUAGE PatternGuards #-}
|
{-# LANGUAGE PatternGuards #-}
|
||||||
module GF.Compile.TypeCheck.Concrete( {-checkLType, inferLType, computeLType, ppType-} ) where
|
module GF.Compile.TypeCheck.Concrete( checkLType, inferLType, computeLType, ppType ) where
|
||||||
{-
|
import Prelude hiding ((<>)) -- GHC 8.4.1 clash with Text.PrettyPrint
|
||||||
|
|
||||||
import GF.Infra.CheckM
|
import GF.Infra.CheckM
|
||||||
import GF.Data.Operations
|
import GF.Data.Operations
|
||||||
|
|
||||||
@@ -22,10 +23,16 @@ computeLType gr g0 t = comp (reverse [(b,x, Vr x) | (b,x,_) <- g0] ++ g0) t
|
|||||||
_ | Just _ <- isTypeInts ty -> return ty ---- shouldn't be needed
|
_ | Just _ <- isTypeInts ty -> return ty ---- shouldn't be needed
|
||||||
| isPredefConstant ty -> return ty ---- shouldn't be needed
|
| isPredefConstant ty -> return ty ---- shouldn't be needed
|
||||||
|
|
||||||
Q (m,ident) -> checkIn (text "module" <+> ppIdent m) $ do
|
Q (m,ident) -> checkIn ("module" <+> m) $ do
|
||||||
ty' <- lookupResDef gr (m,ident)
|
ty' <- lookupResDef gr (m,ident)
|
||||||
if ty' == ty then return ty else comp g ty' --- is this necessary to test?
|
if ty' == ty then return ty else comp g ty' --- is this necessary to test?
|
||||||
|
|
||||||
|
AdHocOverload ts -> do
|
||||||
|
over <- getOverload gr g (Just typeType) t
|
||||||
|
case over of
|
||||||
|
Just (tr,_) -> return tr
|
||||||
|
_ -> checkError ("unresolved overloading of constants" <+> ppTerm Qualified 0 t)
|
||||||
|
|
||||||
Vr ident -> checkLookup ident g -- never needed to compute!
|
Vr ident -> checkLookup ident g -- never needed to compute!
|
||||||
|
|
||||||
App f a -> do
|
App f a -> do
|
||||||
@@ -62,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
|
||||||
|
|
||||||
@@ -73,26 +79,26 @@ inferLType gr g trm = case trm of
|
|||||||
|
|
||||||
Q (m,ident) | isPredef m -> termWith trm $ case typPredefined ident of
|
Q (m,ident) | isPredef m -> termWith trm $ case typPredefined ident of
|
||||||
Just ty -> return ty
|
Just ty -> return ty
|
||||||
Nothing -> checkError (text "unknown in Predef:" <+> ppIdent ident)
|
Nothing -> checkError ("unknown in Predef:" <+> ident)
|
||||||
|
|
||||||
Q ident -> checks [
|
Q ident -> checks [
|
||||||
termWith trm $ lookupResType gr ident >>= computeLType gr g
|
termWith trm $ lookupResType gr ident >>= computeLType gr g
|
||||||
,
|
,
|
||||||
lookupResDef gr ident >>= inferLType gr g
|
lookupResDef gr ident >>= inferLType gr g
|
||||||
,
|
,
|
||||||
checkError (text "cannot infer type of constant" <+> ppTerm Unqualified 0 trm)
|
checkError ("cannot infer type of constant" <+> ppTerm Unqualified 0 trm)
|
||||||
]
|
]
|
||||||
|
|
||||||
QC (m,ident) | isPredef m -> termWith trm $ case typPredefined ident of
|
QC (m,ident) | isPredef m -> termWith trm $ case typPredefined ident of
|
||||||
Just ty -> return ty
|
Just ty -> return ty
|
||||||
Nothing -> checkError (text "unknown in Predef:" <+> ppIdent ident)
|
Nothing -> checkError ("unknown in Predef:" <+> ident)
|
||||||
|
|
||||||
QC ident -> checks [
|
QC ident -> checks [
|
||||||
termWith trm $ lookupResType gr ident >>= computeLType gr g
|
termWith trm $ lookupResType gr ident >>= computeLType gr g
|
||||||
,
|
,
|
||||||
lookupResDef gr ident >>= inferLType gr g
|
lookupResDef gr ident >>= inferLType gr g
|
||||||
,
|
,
|
||||||
checkError (text "cannot infer type of canonical constant" <+> ppTerm Unqualified 0 trm)
|
checkError ("cannot infer type of canonical constant" <+> ppTerm Unqualified 0 trm)
|
||||||
]
|
]
|
||||||
|
|
||||||
Vr ident -> termWith trm $ checkLookup ident g
|
Vr ident -> termWith trm $ checkLookup ident g
|
||||||
@@ -100,7 +106,12 @@ inferLType gr g trm = case trm of
|
|||||||
Typed e t -> do
|
Typed e t -> do
|
||||||
t' <- computeLType gr g t
|
t' <- computeLType gr g t
|
||||||
checkLType gr g e t'
|
checkLType gr g e t'
|
||||||
return (e,t')
|
|
||||||
|
AdHocOverload ts -> do
|
||||||
|
over <- getOverload gr g Nothing trm
|
||||||
|
case over of
|
||||||
|
Just trty -> return trty
|
||||||
|
_ -> checkError ("unresolved overloading of constants" <+> ppTerm Qualified 0 trm)
|
||||||
|
|
||||||
App f a -> do
|
App f a -> do
|
||||||
over <- getOverload gr g Nothing trm
|
over <- getOverload gr g Nothing trm
|
||||||
@@ -116,7 +127,11 @@ inferLType gr g trm = case trm of
|
|||||||
then return val
|
then return val
|
||||||
else substituteLType [(bt,z,a')] val
|
else substituteLType [(bt,z,a')] val
|
||||||
return (App f' a',ty)
|
return (App f' a',ty)
|
||||||
_ -> checkError (text "A function type is expected for" <+> ppTerm Unqualified 0 f <+> text "instead of type" <+> ppType fty)
|
_ ->
|
||||||
|
let term = ppTerm Unqualified 0 f
|
||||||
|
funName = pp . head . words .render $ term
|
||||||
|
in checkError ("A function type is expected for" <+> term <+> "instead of type" <+> ppType fty $$
|
||||||
|
"\n ** Maybe you gave too many arguments to" <+> funName <+> "\n")
|
||||||
|
|
||||||
S f x -> do
|
S f x -> do
|
||||||
(f', fty) <- inferLType gr g f
|
(f', fty) <- inferLType gr g f
|
||||||
@@ -124,7 +139,7 @@ inferLType gr g trm = case trm of
|
|||||||
Table arg val -> do
|
Table arg val -> do
|
||||||
x'<- justCheck g x arg
|
x'<- justCheck g x arg
|
||||||
return (S f' x', val)
|
return (S f' x', val)
|
||||||
_ -> checkError (text "table lintype expected for the table in" $$ nest 2 (ppTerm Unqualified 0 trm))
|
_ -> checkError ("table lintype expected for the table in" $$ nest 2 (ppTerm Unqualified 0 trm))
|
||||||
|
|
||||||
P t i -> do
|
P t i -> do
|
||||||
(t',ty) <- inferLType gr g t --- ??
|
(t',ty) <- inferLType gr g t --- ??
|
||||||
@@ -132,16 +147,16 @@ inferLType gr g trm = case trm of
|
|||||||
let tr2 = P t' i
|
let tr2 = P t' i
|
||||||
termWith tr2 $ case ty' of
|
termWith tr2 $ case ty' of
|
||||||
RecType ts -> case lookup i ts of
|
RecType ts -> case lookup i ts of
|
||||||
Nothing -> checkError (text "unknown label" <+> ppLabel i <+> text "in" $$ nest 2 (ppTerm Unqualified 0 ty'))
|
Nothing -> checkError ("unknown label" <+> i <+> "in" $$ nest 2 (ppTerm Unqualified 0 ty'))
|
||||||
Just x -> return x
|
Just x -> return x
|
||||||
_ -> checkError (text "record type expected for:" <+> ppTerm Unqualified 0 t $$
|
_ -> checkError ("record type expected for:" <+> ppTerm Unqualified 0 t $$
|
||||||
text " instead of the inferred:" <+> ppTerm Unqualified 0 ty')
|
" instead of the inferred:" <+> ppTerm Unqualified 0 ty')
|
||||||
|
|
||||||
R r -> do
|
R r -> do
|
||||||
let (ls,fs) = unzip r
|
let (ls,fs) = unzip r
|
||||||
fsts <- mapM inferM fs
|
fsts <- mapM inferM fs
|
||||||
let ts = [ty | (Just ty,_) <- fsts]
|
let ts = [ty | (Just ty,_) <- fsts]
|
||||||
checkCond (text "cannot infer type of record" $$ nest 2 (ppTerm Unqualified 0 trm)) (length ts == length fsts)
|
checkCond ("cannot infer type of record" $$ nest 2 (ppTerm Unqualified 0 trm)) (length ts == length fsts)
|
||||||
return $ (R (zip ls fsts), RecType (zip ls ts))
|
return $ (R (zip ls fsts), RecType (zip ls ts))
|
||||||
|
|
||||||
T (TTyped arg) pts -> do
|
T (TTyped arg) pts -> do
|
||||||
@@ -153,7 +168,7 @@ inferLType gr g trm = case trm of
|
|||||||
T ti pts -> do -- tries to guess: good in oper type inference
|
T ti pts -> do -- tries to guess: good in oper type inference
|
||||||
let pts' = [pt | pt@(p,_) <- pts, isConstPatt p]
|
let pts' = [pt | pt@(p,_) <- pts, isConstPatt p]
|
||||||
case pts' of
|
case pts' of
|
||||||
[] -> checkError (text "cannot infer table type of" <+> ppTerm Unqualified 0 trm)
|
[] -> checkError ("cannot infer table type of" <+> ppTerm Unqualified 0 trm)
|
||||||
---- PInt k : _ -> return $ Ints $ max [i | PInt i <- pts']
|
---- PInt k : _ -> return $ Ints $ max [i | PInt i <- pts']
|
||||||
_ -> do
|
_ -> do
|
||||||
(arg,val) <- checks $ map (inferCase Nothing) pts'
|
(arg,val) <- checks $ map (inferCase Nothing) pts'
|
||||||
@@ -187,7 +202,7 @@ inferLType gr g trm = case trm of
|
|||||||
|
|
||||||
---- hack from Rename.identRenameTerm, to live with files with naming conflicts 18/6/2007
|
---- hack from Rename.identRenameTerm, to live with files with naming conflicts 18/6/2007
|
||||||
Strs (Cn c : ts) | c == cConflict -> do
|
Strs (Cn c : ts) | c == cConflict -> do
|
||||||
checkWarn (text "unresolved constant, could be any of" <+> hcat (map (ppTerm Unqualified 0) ts))
|
checkWarn ("unresolved constant, could be any of" <+> hcat (map (ppTerm Unqualified 0) ts))
|
||||||
inferLType gr g (head ts)
|
inferLType gr g (head ts)
|
||||||
|
|
||||||
Strs ts -> do
|
Strs ts -> do
|
||||||
@@ -208,19 +223,25 @@ inferLType gr g trm = case trm of
|
|||||||
return (RecType (zip ls ts'), typeType)
|
return (RecType (zip ls ts'), typeType)
|
||||||
|
|
||||||
ExtR r s -> do
|
ExtR r s -> do
|
||||||
(r',rT) <- inferLType gr g r
|
|
||||||
|
--- over <- getOverload gr g Nothing r
|
||||||
|
--- let r1 = maybe r fst over
|
||||||
|
let r1 = r ---
|
||||||
|
|
||||||
|
(r',rT) <- inferLType gr g r1
|
||||||
rT' <- computeLType gr g rT
|
rT' <- computeLType gr g rT
|
||||||
|
|
||||||
(s',sT) <- inferLType gr g s
|
(s',sT) <- inferLType gr g s
|
||||||
sT' <- computeLType gr g sT
|
sT' <- computeLType gr g sT
|
||||||
|
|
||||||
let trm' = ExtR r' s'
|
let trm' = ExtR r' s'
|
||||||
---- trm' <- plusRecord r' s'
|
|
||||||
case (rT', sT') of
|
case (rT', sT') of
|
||||||
(RecType rs, RecType ss) -> do
|
(RecType rs, RecType ss) -> do
|
||||||
rt <- plusRecType rT' sT'
|
let rt = RecType ([field | field@(l,_) <- rs, notElem l (map fst ss)] ++ ss) -- select types of later fields
|
||||||
checkLType gr g trm' rt ---- return (trm', rt)
|
checkLType gr g trm' rt ---- return (trm', rt)
|
||||||
_ | rT' == typeType && sT' == typeType -> return (trm', typeType)
|
_ | rT' == typeType && sT' == typeType -> do
|
||||||
_ -> checkError (text "records or record types expected in" <+> ppTerm Unqualified 0 trm)
|
return (trm', typeType)
|
||||||
|
_ -> checkError ("records or record types expected in" <+> ppTerm Unqualified 0 trm)
|
||||||
|
|
||||||
Sort _ ->
|
Sort _ ->
|
||||||
termWith trm $ return typeType
|
termWith trm $ return typeType
|
||||||
@@ -252,7 +273,7 @@ inferLType gr g trm = case trm of
|
|||||||
ty' <- lockRecType c ty ---- lookup c; remove lock AR 20/6/2009
|
ty' <- lockRecType c ty ---- lookup c; remove lock AR 20/6/2009
|
||||||
return $ (ELin c trm', ty')
|
return $ (ELin c trm', ty')
|
||||||
|
|
||||||
_ -> checkError (text "cannot infer lintype of" <+> ppTerm Unqualified 0 trm)
|
_ -> checkError ("cannot infer lintype of" <+> ppTerm Unqualified 0 trm)
|
||||||
|
|
||||||
where
|
where
|
||||||
isPredef m = elem m [cPredef,cPredefAbs]
|
isPredef m = elem m [cPredef,cPredefAbs]
|
||||||
@@ -299,7 +320,6 @@ inferLType gr g trm = case trm of
|
|||||||
PChars _ -> return $ typeStr
|
PChars _ -> return $ typeStr
|
||||||
_ -> inferLType gr g (patt2term p) >>= return . snd
|
_ -> inferLType gr g (patt2term p) >>= return . snd
|
||||||
|
|
||||||
|
|
||||||
-- type inference: Nothing, type checking: Just t
|
-- type inference: Nothing, type checking: Just t
|
||||||
-- the latter permits matching with value type
|
-- the latter permits matching with value type
|
||||||
getOverload :: SourceGrammar -> Context -> Maybe Type -> Term -> Check (Maybe (Term,Type))
|
getOverload :: SourceGrammar -> Context -> Maybe Type -> Term -> Check (Maybe (Term,Type))
|
||||||
@@ -310,8 +330,21 @@ getOverload gr g mt ot = case appForm ot of
|
|||||||
v <- matchOverload f typs ttys
|
v <- matchOverload f typs ttys
|
||||||
return $ Just v
|
return $ Just v
|
||||||
_ -> return Nothing
|
_ -> return Nothing
|
||||||
|
(AdHocOverload cs@(f:_), ts) -> do --- the function name f is only used in error messages
|
||||||
|
let typs = concatMap collectOverloads cs
|
||||||
|
ttys <- mapM (inferLType gr g) ts
|
||||||
|
v <- matchOverload f typs ttys
|
||||||
|
return $ Just v
|
||||||
_ -> return Nothing
|
_ -> return Nothing
|
||||||
|
|
||||||
where
|
where
|
||||||
|
collectOverloads tr@(Q c) = case lookupOverload gr c of
|
||||||
|
Ok typs -> typs
|
||||||
|
_ -> case lookupResType gr c of
|
||||||
|
Ok ty -> let (args,val) = typeFormCnc ty in [(map (\(b,x,t) -> t) args,(val,tr))]
|
||||||
|
_ -> []
|
||||||
|
collectOverloads _ = [] --- constructors QC
|
||||||
|
|
||||||
matchOverload f typs ttys = do
|
matchOverload f typs ttys = do
|
||||||
let (tts,tys) = unzip ttys
|
let (tts,tys) = unzip ttys
|
||||||
let vfs = lookupOverloadInstance tys typs
|
let vfs = lookupOverloadInstance tys typs
|
||||||
@@ -329,25 +362,26 @@ getOverload gr g mt ot = case appForm ot of
|
|||||||
case ([vf | (vf,True) <- matches],[vf | (vf,False) <- matches]) of
|
case ([vf | (vf,True) <- matches],[vf | (vf,False) <- matches]) of
|
||||||
([(_,val,fun)],_) -> return (mkApp fun tts, val)
|
([(_,val,fun)],_) -> return (mkApp fun tts, val)
|
||||||
([],[(pre,val,fun)]) -> do
|
([],[(pre,val,fun)]) -> do
|
||||||
checkWarn $ text "ignoring lock fields in resolving" <+> ppTerm Unqualified 0 ot $$
|
checkWarn $ "ignoring lock fields in resolving" <+> ppTerm Unqualified 0 ot $$
|
||||||
text "for" $$
|
"for" $$
|
||||||
nest 2 (showTypes tys) $$
|
nest 2 (showTypes tys) $$
|
||||||
text "using" $$
|
"using" $$
|
||||||
nest 2 (showTypes pre)
|
nest 2 (showTypes pre)
|
||||||
return (mkApp fun tts, val)
|
return (mkApp fun tts, val)
|
||||||
([],[]) -> do
|
([],[]) -> do
|
||||||
checkError $ text "no overload instance of" <+> ppTerm Unqualified 0 f $$
|
checkError $ "no overload instance of" <+> ppTerm Qualified 0 f $$
|
||||||
text "for" $$
|
maybe empty (\x -> "with value type" <+> ppType x) mt $$
|
||||||
|
"for argument list" $$
|
||||||
nest 2 stysError $$
|
nest 2 stysError $$
|
||||||
text "among" $$
|
"among alternatives" $$
|
||||||
nest 2 (vcat stypsError) $$
|
nest 2 (vcat stypsError)
|
||||||
maybe empty (\x -> text "with value type" <+> ppType x) mt
|
|
||||||
|
|
||||||
(vfs1,vfs2) -> case (noProds vfs1,noProds vfs2) of
|
(vfs1,vfs2) -> case (noProds vfs1,noProds vfs2) of
|
||||||
([(val,fun)],_) -> do
|
([(val,fun)],_) -> do
|
||||||
return (mkApp fun tts, val)
|
return (mkApp fun tts, val)
|
||||||
([],[(val,fun)]) -> do
|
([],[(val,fun)]) -> do
|
||||||
checkWarn (text "ignoring lock fields in resolving" <+> ppTerm Unqualified 0 ot)
|
checkWarn ("ignoring lock fields in resolving" <+> ppTerm Unqualified 0 ot)
|
||||||
return (mkApp fun tts, val)
|
return (mkApp fun tts, val)
|
||||||
|
|
||||||
----- unsafely exclude irritating warning AR 24/5/2008
|
----- unsafely exclude irritating warning AR 24/5/2008
|
||||||
@@ -355,16 +389,22 @@ getOverload gr g mt ot = case appForm ot of
|
|||||||
----- "resolved by excluding partial applications:" ++++
|
----- "resolved by excluding partial applications:" ++++
|
||||||
----- unlines [prtType env ty | (ty,_) <- vfs', not (noProd ty)]
|
----- unlines [prtType env ty | (ty,_) <- vfs', not (noProd ty)]
|
||||||
|
|
||||||
|
--- now forgiving ambiguity with a warning AR 1/2/2014
|
||||||
_ -> checkError $ text "ambiguous overloading of" <+> ppTerm Unqualified 0 f <+>
|
-- This gives ad hoc overloading the same behaviour as the choice of the first match in renaming did before.
|
||||||
text "for" <+> hsep (map ppType tys) $$
|
-- But it also gives a chance to ambiguous overloadings that were banned before.
|
||||||
text "with alternatives" $$
|
(nps1,nps2) -> do
|
||||||
nest 2 (vcat [ppType ty | (_,ty,_) <- if null vfs1 then vfs2 else vfs2])
|
checkWarn $ "ambiguous overloading of" <+> ppTerm Unqualified 0 f <+>
|
||||||
|
---- "with argument types" <+> hsep (map (ppTerm Qualified 0) tys) $$
|
||||||
|
"resolved by selecting the first of the alternatives" $$
|
||||||
|
nest 2 (vcat [ppTerm Qualified 0 fun | (_,ty,fun) <- vfs1 ++ if null vfs1 then vfs2 else []])
|
||||||
|
case [(mkApp fun tts,val) | (val,fun) <- nps1 ++ nps2] of
|
||||||
|
[] -> checkError $ "no alternatives left when resolving" <+> ppTerm Unqualified 0 f
|
||||||
|
h:_ -> return h
|
||||||
|
|
||||||
matchVal mt v = elem mt [Nothing,Just v,Just (unlocked v)]
|
matchVal mt v = elem mt [Nothing,Just v,Just (unlocked v)]
|
||||||
|
|
||||||
unlocked v = case v of
|
unlocked v = case v of
|
||||||
RecType fs -> RecType $ filter (not . isLockLabel . fst) fs
|
RecType fs -> RecType $ filter (not . isLockLabel . fst) (sortRec fs)
|
||||||
_ -> v
|
_ -> v
|
||||||
---- TODO: accept subtypes
|
---- TODO: accept subtypes
|
||||||
---- TODO: use a trie
|
---- TODO: use a trie
|
||||||
@@ -385,7 +425,6 @@ getOverload gr g mt ot = case appForm ot of
|
|||||||
|
|
||||||
checkLType :: SourceGrammar -> Context -> Term -> Type -> Check (Term, Type)
|
checkLType :: SourceGrammar -> Context -> Term -> Type -> Check (Term, Type)
|
||||||
checkLType gr g trm typ0 = do
|
checkLType gr g trm typ0 = do
|
||||||
|
|
||||||
typ <- computeLType gr g typ0
|
typ <- computeLType gr g typ0
|
||||||
|
|
||||||
case trm of
|
case trm of
|
||||||
@@ -395,10 +434,12 @@ checkLType gr g trm typ0 = do
|
|||||||
Prod bt' z a b -> do
|
Prod bt' z a b -> do
|
||||||
(c',b') <- if isWildIdent z
|
(c',b') <- if isWildIdent z
|
||||||
then checkLType gr ((bt,x,a):g) c b
|
then checkLType gr ((bt,x,a):g) c b
|
||||||
else do b' <- checkIn (text "abs") $ substituteLType [(bt',z,Vr x)] b
|
else do b' <- checkIn (pp "abs") $ substituteLType [(bt',z,Vr x)] b
|
||||||
checkLType gr ((bt,x,a):g) c b'
|
checkLType gr ((bt,x,a):g) c b'
|
||||||
return $ (Abs bt x c', Prod bt' x a b')
|
return $ (Abs bt x c', Prod bt' z a b')
|
||||||
_ -> checkError $ text "function type expected instead of" <+> ppType typ
|
_ -> checkError $ "function type expected instead of" <+> ppType typ $$
|
||||||
|
"\n ** Double-check that the type signature of the operation" $$
|
||||||
|
"matches the number of arguments given to it.\n"
|
||||||
|
|
||||||
App f a -> do
|
App f a -> do
|
||||||
over <- getOverload gr g (Just typ) trm
|
over <- getOverload gr g (Just typ) trm
|
||||||
@@ -408,6 +449,12 @@ checkLType gr g trm typ0 = do
|
|||||||
(trm',ty') <- inferLType gr g trm
|
(trm',ty') <- inferLType gr g trm
|
||||||
termWith trm' $ checkEqLType gr g typ ty' trm'
|
termWith trm' $ checkEqLType gr g typ ty' trm'
|
||||||
|
|
||||||
|
AdHocOverload ts -> do
|
||||||
|
over <- getOverload gr g Nothing trm
|
||||||
|
case over of
|
||||||
|
Just trty -> return trty
|
||||||
|
_ -> checkError ("unresolved overloading of constants" <+> ppTerm Qualified 0 trm)
|
||||||
|
|
||||||
Q _ -> do
|
Q _ -> do
|
||||||
over <- getOverload gr g (Just typ) trm
|
over <- getOverload gr g (Just typ) trm
|
||||||
case over of
|
case over of
|
||||||
@@ -417,7 +464,7 @@ checkLType gr g trm typ0 = do
|
|||||||
termWith trm' $ checkEqLType gr g typ ty' trm'
|
termWith trm' $ checkEqLType gr g typ ty' trm'
|
||||||
|
|
||||||
T _ [] ->
|
T _ [] ->
|
||||||
checkError (text "found empty table in type" <+> ppTerm Unqualified 0 typ)
|
checkError ("found empty table in type" <+> ppTerm Unqualified 0 typ)
|
||||||
T _ cs -> case typ of
|
T _ cs -> case typ of
|
||||||
Table arg val -> do
|
Table arg val -> do
|
||||||
case allParamValues gr arg of
|
case allParamValues gr arg of
|
||||||
@@ -426,12 +473,12 @@ checkLType gr g trm typ0 = do
|
|||||||
ps <- testOvershadow ps0 vs
|
ps <- testOvershadow ps0 vs
|
||||||
if null ps
|
if null ps
|
||||||
then return ()
|
then return ()
|
||||||
else checkWarn (text "patterns never reached:" $$
|
else checkWarn ("patterns never reached:" $$
|
||||||
nest 2 (vcat (map (ppPatt Unqualified 0) ps)))
|
nest 2 (vcat (map (ppPatt Unqualified 0) ps)))
|
||||||
_ -> return () -- happens with variable types
|
_ -> return () -- happens with variable types
|
||||||
cs' <- mapM (checkCase arg val) cs
|
cs' <- mapM (checkCase arg val) cs
|
||||||
return (T (TTyped arg) cs', typ)
|
return (T (TTyped arg) cs', typ)
|
||||||
_ -> checkError $ text "table type expected for table instead of" $$ nest 2 (ppType typ)
|
_ -> checkError $ "table type expected for table instead of" $$ nest 2 (ppType typ)
|
||||||
V arg0 vs ->
|
V arg0 vs ->
|
||||||
case typ of
|
case typ of
|
||||||
Table arg1 val ->
|
Table arg1 val ->
|
||||||
@@ -439,51 +486,54 @@ checkLType gr g trm typ0 = do
|
|||||||
vs1 <- allParamValues gr arg1
|
vs1 <- allParamValues gr arg1
|
||||||
if length vs1 == length vs
|
if length vs1 == length vs
|
||||||
then return ()
|
then return ()
|
||||||
else checkError $ text "wrong number of values in table" <+> ppTerm Unqualified 0 trm
|
else checkError $ "wrong number of values in table" <+> ppTerm Unqualified 0 trm
|
||||||
vs' <- map fst `fmap` sequence [checkLType gr g v val|v<-vs]
|
vs' <- map fst `fmap` sequence [checkLType gr g v val|v<-vs]
|
||||||
return (V arg' vs',typ)
|
return (V arg' vs',typ)
|
||||||
|
|
||||||
R r -> case typ of --- why needed? because inference may be too difficult
|
R r -> case typ of --- why needed? because inference may be too difficult
|
||||||
RecType rr -> do
|
RecType rr -> do
|
||||||
let (ls,_) = unzip rr -- labels of expected type
|
--let (ls,_) = unzip rr -- labels of expected type
|
||||||
fsts <- mapM (checkM r) rr -- check that they are found in the record
|
fsts <- mapM (checkM r) rr -- check that they are found in the record
|
||||||
return $ (R fsts, typ) -- normalize record
|
return $ (R fsts, typ) -- normalize record
|
||||||
|
|
||||||
_ -> checkError (text "record type expected in type checking instead of" $$ nest 2 (ppTerm Unqualified 0 typ))
|
_ -> checkError ("record type expected in type checking instead of" $$ nest 2 (ppTerm Unqualified 0 typ))
|
||||||
|
|
||||||
ExtR r s -> case typ of
|
ExtR r s -> case typ of
|
||||||
_ | typ == typeType -> do
|
_ | typ == typeType -> do
|
||||||
trm' <- computeLType gr g trm
|
trm' <- computeLType gr g trm
|
||||||
case trm' of
|
case trm' of
|
||||||
RecType _ -> termWith trm $ return typeType
|
RecType _ -> termWith trm' $ return typeType
|
||||||
ExtR (Vr _) (RecType _) -> termWith trm $ return typeType
|
ExtR (Vr _) (RecType _) -> termWith trm' $ return typeType
|
||||||
-- ext t = t ** ...
|
-- ext t = t ** ...
|
||||||
_ -> checkError (text "invalid record type extension" <+> nest 2 (ppTerm Unqualified 0 trm))
|
_ -> checkError ("invalid record type extension" <+> nest 2 (ppTerm Unqualified 0 trm))
|
||||||
|
|
||||||
RecType rr -> do
|
RecType rr -> do
|
||||||
(r',ty,s') <- checks [
|
|
||||||
do (r',ty) <- inferLType gr g r
|
|
||||||
return (r',ty,s)
|
|
||||||
,
|
|
||||||
do (s',ty) <- inferLType gr g s
|
|
||||||
return (s',ty,r)
|
|
||||||
]
|
|
||||||
|
|
||||||
case ty of
|
ll2 <- case s of
|
||||||
RecType rr1 -> do
|
R ss -> return $ map fst ss
|
||||||
let (rr0,rr2) = recParts rr rr1
|
_ -> do
|
||||||
r2 <- justCheck g r' rr0
|
(s',typ2) <- inferLType gr g s
|
||||||
s2 <- justCheck g s' rr2
|
case typ2 of
|
||||||
return $ (ExtR r2 s2, typ)
|
RecType ss -> return $ map fst ss
|
||||||
_ -> checkError (text "record type expected in extension of" <+> ppTerm Unqualified 0 r $$
|
_ -> checkError ("cannot get labels from" $$ nest 2 (ppTerm Unqualified 0 typ2))
|
||||||
text "but found" <+> ppTerm Unqualified 0 ty)
|
let ll1 = [l | (l,_) <- rr, notElem l ll2]
|
||||||
|
|
||||||
|
--- over <- getOverload gr g Nothing r --- this would solve #66 but fail ParadigmsAra. AR 6/7/2020
|
||||||
|
--- let r1 = maybe r fst over
|
||||||
|
let r1 = r ---
|
||||||
|
|
||||||
|
(r',_) <- checkLType gr g r1 (RecType [field | field@(l,_) <- rr, elem l ll1])
|
||||||
|
(s',_) <- checkLType gr g s (RecType [field | field@(l,_) <- rr, elem l ll2])
|
||||||
|
|
||||||
|
let rec = R ([(l,(Nothing,P r' l)) | l <- ll1] ++ [(l,(Nothing,P s' l)) | l <- ll2])
|
||||||
|
return (rec, typ)
|
||||||
|
|
||||||
ExtR ty ex -> do
|
ExtR ty ex -> do
|
||||||
r' <- justCheck g r ty
|
r' <- justCheck g r ty
|
||||||
s' <- justCheck g s ex
|
s' <- justCheck g s ex
|
||||||
return $ (ExtR r' s', typ) --- is this all? it assumes the same division in trm and typ
|
return $ (ExtR r' s', typ) --- is this all? it assumes the same division in trm and typ
|
||||||
|
|
||||||
_ -> checkError (text "record extension not meaningful for" <+> ppTerm Unqualified 0 typ)
|
_ -> checkError ("record extension not meaningful for" <+> ppTerm Unqualified 0 typ)
|
||||||
|
|
||||||
FV vs -> do
|
FV vs -> do
|
||||||
ttys <- mapM (flip (checkLType gr g) typ) vs
|
ttys <- mapM (flip (checkLType gr g) typ) vs
|
||||||
@@ -498,7 +548,7 @@ checkLType gr g trm typ0 = do
|
|||||||
(arg',val) <- checkLType gr g arg p
|
(arg',val) <- checkLType gr g arg p
|
||||||
checkEqLType gr g typ t trm
|
checkEqLType gr g typ t trm
|
||||||
return (S tab' arg', t)
|
return (S tab' arg', t)
|
||||||
_ -> checkError (text "table type expected for applied table instead of" <+> ppType ty')
|
_ -> checkError ("table type expected for applied table instead of" <+> ppType ty')
|
||||||
, do
|
, do
|
||||||
(arg',ty) <- inferLType gr g arg
|
(arg',ty) <- inferLType gr g arg
|
||||||
ty' <- computeLType gr g ty
|
ty' <- computeLType gr g ty
|
||||||
@@ -507,7 +557,8 @@ checkLType gr g trm typ0 = do
|
|||||||
]
|
]
|
||||||
Let (x,(mty,def)) body -> case mty of
|
Let (x,(mty,def)) body -> case mty of
|
||||||
Just ty -> do
|
Just ty -> do
|
||||||
(def',ty') <- checkLType gr g def ty
|
(ty0,_) <- checkLType gr g ty typeType
|
||||||
|
(def',ty') <- checkLType gr g def ty0
|
||||||
body' <- justCheck ((Explicit,x,ty'):g) body typ
|
body' <- justCheck ((Explicit,x,ty'):g) body typ
|
||||||
return (Let (x,(Just ty',def')) body', typ)
|
return (Let (x,(Just ty',def')) body', typ)
|
||||||
_ -> do
|
_ -> do
|
||||||
@@ -523,10 +574,10 @@ checkLType gr g trm typ0 = do
|
|||||||
termWith trm' $ checkEqLType gr g typ ty' trm'
|
termWith trm' $ checkEqLType gr g typ ty' trm'
|
||||||
where
|
where
|
||||||
justCheck g ty te = checkLType gr g ty te >>= return . fst
|
justCheck g ty te = checkLType gr g ty te >>= return . fst
|
||||||
|
{-
|
||||||
recParts rr t = (RecType rr1,RecType rr2) where
|
recParts rr t = (RecType rr1,RecType rr2) where
|
||||||
(rr1,rr2) = partition (flip elem (map fst t) . fst) rr
|
(rr1,rr2) = partition (flip elem (map fst t) . fst) rr
|
||||||
|
-}
|
||||||
checkM rms (l,ty) = case lookup l rms of
|
checkM rms (l,ty) = case lookup l rms of
|
||||||
Just (Just ty0,t) -> do
|
Just (Just ty0,t) -> do
|
||||||
checkEqLType gr g ty ty0 t
|
checkEqLType gr g ty ty0 t
|
||||||
@@ -538,9 +589,9 @@ checkLType gr g trm typ0 = do
|
|||||||
_ -> checkError $
|
_ -> checkError $
|
||||||
if isLockLabel l
|
if isLockLabel l
|
||||||
then let cat = drop 5 (showIdent (label2ident l))
|
then let cat = drop 5 (showIdent (label2ident l))
|
||||||
in ppTerm Unqualified 0 (R rms) <+> text "is not in the lincat of" <+> text cat <>
|
in ppTerm Unqualified 0 (R rms) <+> "is not in the lincat of" <+> cat <>
|
||||||
text "; try wrapping it with lin" <+> text cat
|
"; try wrapping it with lin" <+> cat
|
||||||
else text "cannot find value for label" <+> ppLabel l <+> text "in" <+> ppTerm Unqualified 0 (R rms)
|
else "cannot find value for label" <+> l <+> "in" <+> ppTerm Unqualified 0 (R rms)
|
||||||
|
|
||||||
checkCase arg val (p,t) = do
|
checkCase arg val (p,t) = do
|
||||||
cont <- pattContext gr g arg p
|
cont <- pattContext gr g arg p
|
||||||
@@ -553,7 +604,7 @@ pattContext env g typ p = case p of
|
|||||||
PP (q,c) ps | q /= cPredef -> do ---- why this /=? AR 6/1/2006
|
PP (q,c) ps | q /= cPredef -> do ---- why this /=? AR 6/1/2006
|
||||||
t <- lookupResType env (q,c)
|
t <- lookupResType env (q,c)
|
||||||
let (cont,v) = typeFormCnc t
|
let (cont,v) = typeFormCnc t
|
||||||
checkCond (text "wrong number of arguments for constructor in" <+> ppPatt Unqualified 0 p)
|
checkCond ("wrong number of arguments for constructor in" <+> ppPatt Unqualified 0 p)
|
||||||
(length cont == length ps)
|
(length cont == length ps)
|
||||||
checkEqLType env g typ v (patt2term p)
|
checkEqLType env g typ v (patt2term p)
|
||||||
mapM (\((_,_,ty),p) -> pattContext env g ty p) (zip cont ps) >>= return . concat
|
mapM (\((_,_,ty),p) -> pattContext env g ty p) (zip cont ps) >>= return . concat
|
||||||
@@ -564,7 +615,7 @@ pattContext env g typ p = case p of
|
|||||||
let pts = [(ty,tr) | (l,tr) <- r, Just ty <- [lookup l t]]
|
let pts = [(ty,tr) | (l,tr) <- r, Just ty <- [lookup l t]]
|
||||||
----- checkWarn $ prt p ++++ show pts ----- debug
|
----- checkWarn $ prt p ++++ show pts ----- debug
|
||||||
mapM (uncurry (pattContext env g)) pts >>= return . concat
|
mapM (uncurry (pattContext env g)) pts >>= return . concat
|
||||||
_ -> checkError (text "record type expected for pattern instead of" <+> ppTerm Unqualified 0 typ')
|
_ -> checkError ("record type expected for pattern instead of" <+> ppTerm Unqualified 0 typ')
|
||||||
PT t p' -> do
|
PT t p' -> do
|
||||||
checkEqLType env g typ t (patt2term p')
|
checkEqLType env g typ t (patt2term p')
|
||||||
pattContext env g typ p'
|
pattContext env g typ p'
|
||||||
@@ -578,9 +629,9 @@ pattContext env g typ p = case p of
|
|||||||
g2 <- pattContext env g typ q
|
g2 <- pattContext env g typ q
|
||||||
let pts = nub ([x | pt@(_,x,_) <- g1, notElem pt g2] ++ [x | pt@(_,x,_) <- g2, notElem pt g1])
|
let pts = nub ([x | pt@(_,x,_) <- g1, notElem pt g2] ++ [x | pt@(_,x,_) <- g2, notElem pt g1])
|
||||||
checkCond
|
checkCond
|
||||||
(text "incompatible bindings of" <+>
|
("incompatible bindings of" <+>
|
||||||
fsep (map ppIdent pts) <+>
|
fsep pts <+>
|
||||||
text "in pattern alterantives" <+> ppPatt Unqualified 0 p) (null pts)
|
"in pattern alterantives" <+> ppPatt Unqualified 0 p) (null pts)
|
||||||
return g1 -- must be g1 == g2
|
return g1 -- must be g1 == g2
|
||||||
PSeq p q -> do
|
PSeq p q -> do
|
||||||
g1 <- pattContext env g typ p
|
g1 <- pattContext env g typ p
|
||||||
@@ -594,7 +645,7 @@ pattContext env g typ p = case p of
|
|||||||
noBind typ p' = do
|
noBind typ p' = do
|
||||||
co <- pattContext env g typ p'
|
co <- pattContext env g typ p'
|
||||||
if not (null co)
|
if not (null co)
|
||||||
then checkWarn (text "no variable bound inside pattern" <+> ppPatt Unqualified 0 p)
|
then checkWarn ("no variable bound inside pattern" <+> ppPatt Unqualified 0 p)
|
||||||
>> return []
|
>> return []
|
||||||
else return []
|
else return []
|
||||||
|
|
||||||
@@ -603,9 +654,31 @@ checkEqLType gr g t u trm = do
|
|||||||
(b,t',u',s) <- checkIfEqLType gr g t u trm
|
(b,t',u',s) <- checkIfEqLType gr g t u trm
|
||||||
case b of
|
case b of
|
||||||
True -> return t'
|
True -> return t'
|
||||||
False -> checkError $ text s <+> text "type of" <+> ppTerm Unqualified 0 trm $$
|
False ->
|
||||||
text "expected:" <+> ppType t $$
|
let inferredType = ppTerm Qualified 0 u
|
||||||
text "inferred:" <+> ppType u
|
expectedType = ppTerm Qualified 0 t
|
||||||
|
term = ppTerm Unqualified 0 trm
|
||||||
|
funName = pp . head . words .render $ term
|
||||||
|
helpfulMsg =
|
||||||
|
case (arrows inferredType, arrows expectedType) of
|
||||||
|
(0,0) -> pp "" -- None of the types is a function
|
||||||
|
_ -> "\n **" <+>
|
||||||
|
if expectedType `isLessApplied` inferredType
|
||||||
|
then "Maybe you gave too few arguments to" <+> funName
|
||||||
|
else pp "Double-check that type signature and number of arguments match."
|
||||||
|
in checkError $ s <+> "type of" <+> term $$
|
||||||
|
"expected:" <+> expectedType $$ -- ppqType t u $$
|
||||||
|
"inferred:" <+> inferredType $$ -- ppqType u t
|
||||||
|
helpfulMsg
|
||||||
|
where
|
||||||
|
-- count the number of arrows in the prettyprinted term
|
||||||
|
arrows :: Doc -> Int
|
||||||
|
arrows = length . filter (=="->") . words . render
|
||||||
|
|
||||||
|
-- If prettyprinted type t has fewer arrows then prettyprinted type u,
|
||||||
|
-- then t is "less applied", and we can print out more helpful error msg.
|
||||||
|
isLessApplied :: Doc -> Doc -> Bool
|
||||||
|
isLessApplied t u = arrows t < arrows u
|
||||||
|
|
||||||
checkIfEqLType :: SourceGrammar -> Context -> Type -> Type -> Term -> Check (Bool,Type,Type,String)
|
checkIfEqLType :: SourceGrammar -> Context -> Type -> Type -> Term -> Check (Bool,Type,Type,String)
|
||||||
checkIfEqLType gr g t u trm = do
|
checkIfEqLType gr g t u trm = do
|
||||||
@@ -617,13 +690,13 @@ checkIfEqLType gr g t u trm = do
|
|||||||
--- better: use a flag to forgive? (AR 31/1/2006)
|
--- better: use a flag to forgive? (AR 31/1/2006)
|
||||||
_ -> case missingLock [] t' u' of
|
_ -> case missingLock [] t' u' of
|
||||||
Ok lo -> do
|
Ok lo -> do
|
||||||
checkWarn $ text "missing lock field" <+> fsep (map ppLabel lo)
|
checkWarn $ "missing lock field" <+> fsep lo
|
||||||
return (True,t',u',[])
|
return (True,t',u',[])
|
||||||
Bad s -> return (False,t',u',s)
|
Bad s -> return (False,t',u',s)
|
||||||
|
|
||||||
where
|
where
|
||||||
|
|
||||||
-- t is a subtype of u
|
-- check that u is a subtype of t
|
||||||
--- quick hack version of TC.eqVal
|
--- quick hack version of TC.eqVal
|
||||||
alpha g t u = case (t,u) of
|
alpha g t u = case (t,u) of
|
||||||
|
|
||||||
@@ -635,12 +708,13 @@ checkIfEqLType gr g t u trm = do
|
|||||||
|
|
||||||
-- record subtyping
|
-- record subtyping
|
||||||
(RecType rs, RecType ts) -> all (\ (l,a) ->
|
(RecType rs, RecType ts) -> all (\ (l,a) ->
|
||||||
any (\ (k,b) -> alpha g a b && l == k) ts) rs
|
any (\ (k,b) -> l == k && alpha g a b) ts) rs
|
||||||
(ExtR r s, ExtR r' s') -> alpha g r r' && alpha g s s'
|
(ExtR r s, ExtR r' s') -> alpha g r r' && alpha g s s'
|
||||||
(ExtR r s, t) -> alpha g r t || alpha g s t
|
(ExtR r s, t) -> alpha g r t || alpha g s t
|
||||||
|
|
||||||
-- the following say that Ints n is a subset of Int and of Ints m >= n
|
-- the following say that Ints n is a subset of Int and of Ints m >= n
|
||||||
(t,u) | Just m <- isTypeInts t, Just n <- isTypeInts t -> m >= n
|
-- But why does it also allow Int as a subtype of Ints m? /TH 2014-04-04
|
||||||
|
(t,u) | Just m <- isTypeInts t, Just n <- isTypeInts u -> m >= n
|
||||||
| Just _ <- isTypeInts t, u == typeInt -> True ---- check size!
|
| Just _ <- isTypeInts t, u == typeInt -> True ---- check size!
|
||||||
| t == typeInt, Just _ <- isTypeInts u -> True ---- why this ???? AR 11/12/2005
|
| t == typeInt, Just _ <- isTypeInts u -> True ---- why this ???? AR 11/12/2005
|
||||||
|
|
||||||
@@ -655,7 +729,8 @@ checkIfEqLType gr g t u trm = do
|
|||||||
(Q (m,a), QC (n,b)) | a == b -> elem m (allExtendsPlus gr n)
|
(Q (m,a), QC (n,b)) | a == b -> elem m (allExtendsPlus gr n)
|
||||||
|| elem n (allExtendsPlus gr m)
|
|| elem n (allExtendsPlus gr m)
|
||||||
|
|
||||||
(Table a b, Table c d) -> alpha g a c && alpha g b d
|
-- contravariance
|
||||||
|
(Table a b, Table c d) -> alpha g c a && alpha g b d
|
||||||
(Vr x, Vr y) -> x == y || elem (x,y) g || elem (y,x) g
|
(Vr x, Vr y) -> x == y || elem (x,y) g || elem (y,x) g
|
||||||
_ -> t == u
|
_ -> t == u
|
||||||
--- the following should be one-way coercions only. AR 4/1/2001
|
--- the following should be one-way coercions only. AR 4/1/2001
|
||||||
@@ -670,7 +745,7 @@ checkIfEqLType gr g t u trm = do
|
|||||||
not (any (\ (k,b) -> alpha g a b && l == k) ts)]
|
not (any (\ (k,b) -> alpha g a b && l == k) ts)]
|
||||||
(locks,others) = partition isLockLabel ls
|
(locks,others) = partition isLockLabel ls
|
||||||
in case others of
|
in case others of
|
||||||
_:_ -> Bad $ render (text "missing record fields:" <+> fsep (punctuate comma (map ppLabel others)))
|
_:_ -> Bad $ render ("missing record fields:" <+> fsep (punctuate ',' (others)))
|
||||||
_ -> return locks
|
_ -> return locks
|
||||||
-- contravariance
|
-- contravariance
|
||||||
(Prod _ x a b, Prod _ y c d) -> do
|
(Prod _ x a b, Prod _ y c d) -> do
|
||||||
@@ -708,14 +783,18 @@ ppType :: Type -> Doc
|
|||||||
ppType ty =
|
ppType ty =
|
||||||
case ty of
|
case ty of
|
||||||
RecType fs -> case filter isLockLabel $ map fst fs of
|
RecType fs -> case filter isLockLabel $ map fst fs of
|
||||||
[lock] -> text (drop 5 (showIdent (label2ident lock)))
|
[lock] -> pp (drop 5 (showIdent (label2ident lock)))
|
||||||
_ -> ppTerm Unqualified 0 ty
|
_ -> ppTerm Unqualified 0 ty
|
||||||
Prod _ x a b -> ppType a <+> text "->" <+> ppType b
|
Prod _ x a b -> ppType a <+> "->" <+> ppType b
|
||||||
_ -> ppTerm Unqualified 0 ty
|
_ -> ppTerm Unqualified 0 ty
|
||||||
|
{-
|
||||||
|
ppqType :: Type -> Type -> Doc
|
||||||
|
ppqType t u = case (ppType t, ppType u) of
|
||||||
|
(pt,pu) | render pt == render pu -> ppTerm Qualified 0 t
|
||||||
|
(pt,_) -> pt
|
||||||
|
-}
|
||||||
checkLookup :: Ident -> Context -> Check Type
|
checkLookup :: Ident -> Context -> Check Type
|
||||||
checkLookup x g =
|
checkLookup x g =
|
||||||
case [ty | (b,y,ty) <- g, x == y] of
|
case [ty | (b,y,ty) <- g, x == y] of
|
||||||
[] -> checkError (text "unknown variable" <+> ppIdent x)
|
[] -> checkError ("unknown variable" <+> x)
|
||||||
(ty:_) -> return ty
|
(ty:_) -> return ty
|
||||||
-}
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
{-# LANGUAGE CPP #-}
|
||||||
module GF.Compile.TypeCheck.ConcreteNew( checkLType, inferLType ) where
|
module GF.Compile.TypeCheck.ConcreteNew( checkLType, inferLType ) where
|
||||||
|
|
||||||
-- The code here is based on the paper:
|
-- The code here is based on the paper:
|
||||||
@@ -9,7 +10,7 @@ import GF.Grammar hiding (Env, VGen, VApp, VRecType)
|
|||||||
import GF.Grammar.Lookup
|
import GF.Grammar.Lookup
|
||||||
import GF.Grammar.Predef
|
import GF.Grammar.Predef
|
||||||
import GF.Grammar.Lockfield
|
import GF.Grammar.Lockfield
|
||||||
import GF.Compile.Compute.ConcreteNew
|
import GF.Compile.Compute.Concrete
|
||||||
import GF.Compile.Compute.Predef(predef,predefName)
|
import GF.Compile.Compute.Predef(predef,predefName)
|
||||||
import GF.Infra.CheckM
|
import GF.Infra.CheckM
|
||||||
import GF.Data.Operations
|
import GF.Data.Operations
|
||||||
@@ -19,6 +20,7 @@ import GF.Text.Pretty
|
|||||||
import Data.List (nub, (\\), tails)
|
import Data.List (nub, (\\), tails)
|
||||||
import qualified Data.IntMap as IntMap
|
import qualified Data.IntMap as IntMap
|
||||||
import Data.Maybe(fromMaybe,isNothing)
|
import Data.Maybe(fromMaybe,isNothing)
|
||||||
|
import qualified Control.Monad.Fail as Fail
|
||||||
|
|
||||||
checkLType :: GlobalEnv -> Term -> Type -> Check (Term, Type)
|
checkLType :: GlobalEnv -> Term -> Type -> Check (Term, Type)
|
||||||
checkLType ge t ty = runTcM $ do
|
checkLType ge t ty = runTcM $ do
|
||||||
@@ -566,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'))
|
||||||
@@ -646,8 +648,16 @@ instance Monad TcM where
|
|||||||
f >>= g = TcM (\ms msgs -> case unTcM f ms msgs of
|
f >>= g = TcM (\ms msgs -> case unTcM f ms msgs of
|
||||||
TcOk x ms msgs -> unTcM (g x) ms msgs
|
TcOk x ms msgs -> unTcM (g x) ms msgs
|
||||||
TcFail msgs -> TcFail msgs)
|
TcFail msgs -> TcFail msgs)
|
||||||
|
|
||||||
|
#if !(MIN_VERSION_base(4,13,0))
|
||||||
|
-- Monad(fail) will be removed in GHC 8.8+
|
||||||
|
fail = Fail.fail
|
||||||
|
#endif
|
||||||
|
|
||||||
|
instance Fail.MonadFail TcM where
|
||||||
fail = tcError . pp
|
fail = tcError . pp
|
||||||
|
|
||||||
|
|
||||||
instance Applicative TcM where
|
instance Applicative TcM where
|
||||||
pure = return
|
pure = return
|
||||||
(<*>) = ap
|
(<*>) = ap
|
||||||
@@ -755,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")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,762 +0,0 @@
|
|||||||
{-# LANGUAGE PatternGuards #-}
|
|
||||||
module GF.Compile.TypeCheck.RConcrete( checkLType, inferLType, computeLType, ppType ) where
|
|
||||||
import Prelude hiding ((<>)) -- GHC 8.4.1 clash with Text.PrettyPrint
|
|
||||||
|
|
||||||
import GF.Infra.CheckM
|
|
||||||
import GF.Data.Operations
|
|
||||||
|
|
||||||
import GF.Grammar
|
|
||||||
import GF.Grammar.Lookup
|
|
||||||
import GF.Grammar.Predef
|
|
||||||
import GF.Grammar.PatternMatch
|
|
||||||
import GF.Grammar.Lockfield (isLockLabel, lockRecType, unlockRecord)
|
|
||||||
import GF.Compile.TypeCheck.Primitives
|
|
||||||
|
|
||||||
import Data.List
|
|
||||||
import Control.Monad
|
|
||||||
import GF.Text.Pretty
|
|
||||||
|
|
||||||
computeLType :: SourceGrammar -> Context -> Type -> Check Type
|
|
||||||
computeLType gr g0 t = comp (reverse [(b,x, Vr x) | (b,x,_) <- g0] ++ g0) t
|
|
||||||
where
|
|
||||||
comp g ty = case ty of
|
|
||||||
_ | Just _ <- isTypeInts ty -> return ty ---- shouldn't be needed
|
|
||||||
| isPredefConstant ty -> return ty ---- shouldn't be needed
|
|
||||||
|
|
||||||
Q (m,ident) -> checkIn ("module" <+> m) $ do
|
|
||||||
ty' <- lookupResDef gr (m,ident)
|
|
||||||
if ty' == ty then return ty else comp g ty' --- is this necessary to test?
|
|
||||||
|
|
||||||
AdHocOverload ts -> do
|
|
||||||
over <- getOverload gr g (Just typeType) t
|
|
||||||
case over of
|
|
||||||
Just (tr,_) -> return tr
|
|
||||||
_ -> checkError ("unresolved overloading of constants" <+> ppTerm Qualified 0 t)
|
|
||||||
|
|
||||||
Vr ident -> checkLookup ident g -- never needed to compute!
|
|
||||||
|
|
||||||
App f a -> do
|
|
||||||
f' <- comp g f
|
|
||||||
a' <- comp g a
|
|
||||||
case f' of
|
|
||||||
Abs b x t -> comp ((b,x,a'):g) t
|
|
||||||
_ -> return $ App f' a'
|
|
||||||
|
|
||||||
Prod bt x a b -> do
|
|
||||||
a' <- comp g a
|
|
||||||
b' <- comp ((bt,x,Vr x) : g) b
|
|
||||||
return $ Prod bt x a' b'
|
|
||||||
|
|
||||||
Abs bt x b -> do
|
|
||||||
b' <- comp ((bt,x,Vr x):g) b
|
|
||||||
return $ Abs bt x b'
|
|
||||||
|
|
||||||
Let (x,(_,a)) b -> comp ((Explicit,x,a):g) b
|
|
||||||
|
|
||||||
ExtR r s -> do
|
|
||||||
r' <- comp g r
|
|
||||||
s' <- comp g s
|
|
||||||
case (r',s') of
|
|
||||||
(RecType rs, RecType ss) -> plusRecType r' s' >>= comp g
|
|
||||||
_ -> return $ ExtR r' s'
|
|
||||||
|
|
||||||
RecType fs -> do
|
|
||||||
let fs' = sortRec fs
|
|
||||||
liftM RecType $ mapPairsM (comp g) fs'
|
|
||||||
|
|
||||||
ELincat c t -> do
|
|
||||||
t' <- comp g t
|
|
||||||
lockRecType c t' ---- locking to be removed AR 20/6/2009
|
|
||||||
|
|
||||||
_ | ty == typeTok -> return typeStr
|
|
||||||
_ | isPredefConstant ty -> return ty
|
|
||||||
|
|
||||||
_ -> composOp (comp g) ty
|
|
||||||
|
|
||||||
-- the underlying algorithms
|
|
||||||
|
|
||||||
inferLType :: SourceGrammar -> Context -> Term -> Check (Term, Type)
|
|
||||||
inferLType gr g trm = case trm of
|
|
||||||
|
|
||||||
Q (m,ident) | isPredef m -> termWith trm $ case typPredefined ident of
|
|
||||||
Just ty -> return ty
|
|
||||||
Nothing -> checkError ("unknown in Predef:" <+> ident)
|
|
||||||
|
|
||||||
Q ident -> checks [
|
|
||||||
termWith trm $ lookupResType gr ident >>= computeLType gr g
|
|
||||||
,
|
|
||||||
lookupResDef gr ident >>= inferLType gr g
|
|
||||||
,
|
|
||||||
checkError ("cannot infer type of constant" <+> ppTerm Unqualified 0 trm)
|
|
||||||
]
|
|
||||||
|
|
||||||
QC (m,ident) | isPredef m -> termWith trm $ case typPredefined ident of
|
|
||||||
Just ty -> return ty
|
|
||||||
Nothing -> checkError ("unknown in Predef:" <+> ident)
|
|
||||||
|
|
||||||
QC ident -> checks [
|
|
||||||
termWith trm $ lookupResType gr ident >>= computeLType gr g
|
|
||||||
,
|
|
||||||
lookupResDef gr ident >>= inferLType gr g
|
|
||||||
,
|
|
||||||
checkError ("cannot infer type of canonical constant" <+> ppTerm Unqualified 0 trm)
|
|
||||||
]
|
|
||||||
|
|
||||||
Vr ident -> termWith trm $ checkLookup ident g
|
|
||||||
|
|
||||||
Typed e t -> do
|
|
||||||
t' <- computeLType gr g t
|
|
||||||
checkLType gr g e t'
|
|
||||||
|
|
||||||
AdHocOverload ts -> do
|
|
||||||
over <- getOverload gr g Nothing trm
|
|
||||||
case over of
|
|
||||||
Just trty -> return trty
|
|
||||||
_ -> checkError ("unresolved overloading of constants" <+> ppTerm Qualified 0 trm)
|
|
||||||
|
|
||||||
App f a -> do
|
|
||||||
over <- getOverload gr g Nothing trm
|
|
||||||
case over of
|
|
||||||
Just trty -> return trty
|
|
||||||
_ -> do
|
|
||||||
(f',fty) <- inferLType gr g f
|
|
||||||
fty' <- computeLType gr g fty
|
|
||||||
case fty' of
|
|
||||||
Prod bt z arg val -> do
|
|
||||||
a' <- justCheck g a arg
|
|
||||||
ty <- if isWildIdent z
|
|
||||||
then return val
|
|
||||||
else substituteLType [(bt,z,a')] val
|
|
||||||
return (App f' a',ty)
|
|
||||||
_ -> checkError ("A function type is expected for" <+> ppTerm Unqualified 0 f <+> "instead of type" <+> ppType fty)
|
|
||||||
|
|
||||||
S f x -> do
|
|
||||||
(f', fty) <- inferLType gr g f
|
|
||||||
case fty of
|
|
||||||
Table arg val -> do
|
|
||||||
x'<- justCheck g x arg
|
|
||||||
return (S f' x', val)
|
|
||||||
_ -> checkError ("table lintype expected for the table in" $$ nest 2 (ppTerm Unqualified 0 trm))
|
|
||||||
|
|
||||||
P t i -> do
|
|
||||||
(t',ty) <- inferLType gr g t --- ??
|
|
||||||
ty' <- computeLType gr g ty
|
|
||||||
let tr2 = P t' i
|
|
||||||
termWith tr2 $ case ty' of
|
|
||||||
RecType ts -> case lookup i ts of
|
|
||||||
Nothing -> checkError ("unknown label" <+> i <+> "in" $$ nest 2 (ppTerm Unqualified 0 ty'))
|
|
||||||
Just x -> return x
|
|
||||||
_ -> checkError ("record type expected for:" <+> ppTerm Unqualified 0 t $$
|
|
||||||
" instead of the inferred:" <+> ppTerm Unqualified 0 ty')
|
|
||||||
|
|
||||||
R r -> do
|
|
||||||
let (ls,fs) = unzip r
|
|
||||||
fsts <- mapM inferM fs
|
|
||||||
let ts = [ty | (Just ty,_) <- fsts]
|
|
||||||
checkCond ("cannot infer type of record" $$ nest 2 (ppTerm Unqualified 0 trm)) (length ts == length fsts)
|
|
||||||
return $ (R (zip ls fsts), RecType (zip ls ts))
|
|
||||||
|
|
||||||
T (TTyped arg) pts -> do
|
|
||||||
(_,val) <- checks $ map (inferCase (Just arg)) pts
|
|
||||||
checkLType gr g trm (Table arg val)
|
|
||||||
T (TComp arg) pts -> do
|
|
||||||
(_,val) <- checks $ map (inferCase (Just arg)) pts
|
|
||||||
checkLType gr g trm (Table arg val)
|
|
||||||
T ti pts -> do -- tries to guess: good in oper type inference
|
|
||||||
let pts' = [pt | pt@(p,_) <- pts, isConstPatt p]
|
|
||||||
case pts' of
|
|
||||||
[] -> checkError ("cannot infer table type of" <+> ppTerm Unqualified 0 trm)
|
|
||||||
---- PInt k : _ -> return $ Ints $ max [i | PInt i <- pts']
|
|
||||||
_ -> do
|
|
||||||
(arg,val) <- checks $ map (inferCase Nothing) pts'
|
|
||||||
checkLType gr g trm (Table arg val)
|
|
||||||
V arg pts -> do
|
|
||||||
(_,val) <- checks $ map (inferLType gr g) pts
|
|
||||||
-- return (trm, Table arg val) -- old, caused issue 68
|
|
||||||
checkLType gr g trm (Table arg val)
|
|
||||||
|
|
||||||
K s -> do
|
|
||||||
if elem ' ' s
|
|
||||||
then do
|
|
||||||
let ss = foldr C Empty (map K (words s))
|
|
||||||
----- removed irritating warning AR 24/5/2008
|
|
||||||
----- checkWarn ("token \"" ++ s ++
|
|
||||||
----- "\" converted to token list" ++ prt ss)
|
|
||||||
return (ss, typeStr)
|
|
||||||
else return (trm, typeStr)
|
|
||||||
|
|
||||||
EInt i -> return (trm, typeInt)
|
|
||||||
|
|
||||||
EFloat i -> return (trm, typeFloat)
|
|
||||||
|
|
||||||
Empty -> return (trm, typeStr)
|
|
||||||
|
|
||||||
C s1 s2 ->
|
|
||||||
check2 (flip (justCheck g) typeStr) C s1 s2 typeStr
|
|
||||||
|
|
||||||
Glue s1 s2 ->
|
|
||||||
check2 (flip (justCheck g) typeStr) Glue s1 s2 typeStr ---- typeTok
|
|
||||||
|
|
||||||
---- hack from Rename.identRenameTerm, to live with files with naming conflicts 18/6/2007
|
|
||||||
Strs (Cn c : ts) | c == cConflict -> do
|
|
||||||
checkWarn ("unresolved constant, could be any of" <+> hcat (map (ppTerm Unqualified 0) ts))
|
|
||||||
inferLType gr g (head ts)
|
|
||||||
|
|
||||||
Strs ts -> do
|
|
||||||
ts' <- mapM (\t -> justCheck g t typeStr) ts
|
|
||||||
return (Strs ts', typeStrs)
|
|
||||||
|
|
||||||
Alts t aa -> do
|
|
||||||
t' <- justCheck g t typeStr
|
|
||||||
aa' <- flip mapM aa (\ (c,v) -> do
|
|
||||||
c' <- justCheck g c typeStr
|
|
||||||
v' <- checks $ map (justCheck g v) [typeStrs, EPattType typeStr]
|
|
||||||
return (c',v'))
|
|
||||||
return (Alts t' aa', typeStr)
|
|
||||||
|
|
||||||
RecType r -> do
|
|
||||||
let (ls,ts) = unzip r
|
|
||||||
ts' <- mapM (flip (justCheck g) typeType) ts
|
|
||||||
return (RecType (zip ls ts'), typeType)
|
|
||||||
|
|
||||||
ExtR r s -> do
|
|
||||||
(r',rT) <- inferLType gr g r
|
|
||||||
rT' <- computeLType gr g rT
|
|
||||||
(s',sT) <- inferLType gr g s
|
|
||||||
sT' <- computeLType gr g sT
|
|
||||||
|
|
||||||
let trm' = ExtR r' s'
|
|
||||||
case (rT', sT') of
|
|
||||||
(RecType rs, RecType ss) -> do
|
|
||||||
let rt = RecType ([field | field@(l,_) <- rs, notElem l (map fst ss)] ++ ss) -- select types of later fields
|
|
||||||
checkLType gr g trm' rt ---- return (trm', rt)
|
|
||||||
_ | rT' == typeType && sT' == typeType -> do
|
|
||||||
return (trm', typeType)
|
|
||||||
_ -> checkError ("records or record types expected in" <+> ppTerm Unqualified 0 trm)
|
|
||||||
|
|
||||||
Sort _ ->
|
|
||||||
termWith trm $ return typeType
|
|
||||||
|
|
||||||
Prod bt x a b -> do
|
|
||||||
a' <- justCheck g a typeType
|
|
||||||
b' <- justCheck ((bt,x,a'):g) b typeType
|
|
||||||
return (Prod bt x a' b', typeType)
|
|
||||||
|
|
||||||
Table p t -> do
|
|
||||||
p' <- justCheck g p typeType --- check p partype!
|
|
||||||
t' <- justCheck g t typeType
|
|
||||||
return $ (Table p' t', typeType)
|
|
||||||
|
|
||||||
FV vs -> do
|
|
||||||
(_,ty) <- checks $ map (inferLType gr g) vs
|
|
||||||
--- checkIfComplexVariantType trm ty
|
|
||||||
checkLType gr g trm ty
|
|
||||||
|
|
||||||
EPattType ty -> do
|
|
||||||
ty' <- justCheck g ty typeType
|
|
||||||
return (EPattType ty',typeType)
|
|
||||||
EPatt p -> do
|
|
||||||
ty <- inferPatt p
|
|
||||||
return (trm, EPattType ty)
|
|
||||||
|
|
||||||
ELin c trm -> do
|
|
||||||
(trm',ty) <- inferLType gr g trm
|
|
||||||
ty' <- lockRecType c ty ---- lookup c; remove lock AR 20/6/2009
|
|
||||||
return $ (ELin c trm', ty')
|
|
||||||
|
|
||||||
_ -> checkError ("cannot infer lintype of" <+> ppTerm Unqualified 0 trm)
|
|
||||||
|
|
||||||
where
|
|
||||||
isPredef m = elem m [cPredef,cPredefAbs]
|
|
||||||
|
|
||||||
justCheck g ty te = checkLType gr g ty te >>= return . fst
|
|
||||||
|
|
||||||
-- for record fields, which may be typed
|
|
||||||
inferM (mty, t) = do
|
|
||||||
(t', ty') <- case mty of
|
|
||||||
Just ty -> checkLType gr g t ty
|
|
||||||
_ -> inferLType gr g t
|
|
||||||
return (Just ty',t')
|
|
||||||
|
|
||||||
inferCase mty (patt,term) = do
|
|
||||||
arg <- maybe (inferPatt patt) return mty
|
|
||||||
cont <- pattContext gr g arg patt
|
|
||||||
(_,val) <- inferLType gr (reverse cont ++ g) term
|
|
||||||
return (arg,val)
|
|
||||||
isConstPatt p = case p of
|
|
||||||
PC _ ps -> True --- all isConstPatt ps
|
|
||||||
PP _ ps -> True --- all isConstPatt ps
|
|
||||||
PR ps -> all (isConstPatt . snd) ps
|
|
||||||
PT _ p -> isConstPatt p
|
|
||||||
PString _ -> True
|
|
||||||
PInt _ -> True
|
|
||||||
PFloat _ -> True
|
|
||||||
PChar -> True
|
|
||||||
PChars _ -> True
|
|
||||||
PSeq p q -> isConstPatt p && isConstPatt q
|
|
||||||
PAlt p q -> isConstPatt p && isConstPatt q
|
|
||||||
PRep p -> isConstPatt p
|
|
||||||
PNeg p -> isConstPatt p
|
|
||||||
PAs _ p -> isConstPatt p
|
|
||||||
_ -> False
|
|
||||||
|
|
||||||
inferPatt p = case p of
|
|
||||||
PP (q,c) ps | q /= cPredef -> liftM valTypeCnc (lookupResType gr (q,c))
|
|
||||||
PAs _ p -> inferPatt p
|
|
||||||
PNeg p -> inferPatt p
|
|
||||||
PAlt p q -> checks [inferPatt p, inferPatt q]
|
|
||||||
PSeq _ _ -> return $ typeStr
|
|
||||||
PRep _ -> return $ typeStr
|
|
||||||
PChar -> return $ typeStr
|
|
||||||
PChars _ -> return $ typeStr
|
|
||||||
_ -> inferLType gr g (patt2term p) >>= return . snd
|
|
||||||
|
|
||||||
-- type inference: Nothing, type checking: Just t
|
|
||||||
-- the latter permits matching with value type
|
|
||||||
getOverload :: SourceGrammar -> Context -> Maybe Type -> Term -> Check (Maybe (Term,Type))
|
|
||||||
getOverload gr g mt ot = case appForm ot of
|
|
||||||
(f@(Q c), ts) -> case lookupOverload gr c of
|
|
||||||
Ok typs -> do
|
|
||||||
ttys <- mapM (inferLType gr g) ts
|
|
||||||
v <- matchOverload f typs ttys
|
|
||||||
return $ Just v
|
|
||||||
_ -> return Nothing
|
|
||||||
(AdHocOverload cs@(f:_), ts) -> do --- the function name f is only used in error messages
|
|
||||||
let typs = concatMap collectOverloads cs
|
|
||||||
ttys <- mapM (inferLType gr g) ts
|
|
||||||
v <- matchOverload f typs ttys
|
|
||||||
return $ Just v
|
|
||||||
_ -> return Nothing
|
|
||||||
|
|
||||||
where
|
|
||||||
collectOverloads tr@(Q c) = case lookupOverload gr c of
|
|
||||||
Ok typs -> typs
|
|
||||||
_ -> case lookupResType gr c of
|
|
||||||
Ok ty -> let (args,val) = typeFormCnc ty in [(map (\(b,x,t) -> t) args,(val,tr))]
|
|
||||||
_ -> []
|
|
||||||
collectOverloads _ = [] --- constructors QC
|
|
||||||
|
|
||||||
matchOverload f typs ttys = do
|
|
||||||
let (tts,tys) = unzip ttys
|
|
||||||
let vfs = lookupOverloadInstance tys typs
|
|
||||||
let matches = [vf | vf@((_,v,_),_) <- vfs, matchVal mt v]
|
|
||||||
let showTypes ty = hsep (map ppType ty)
|
|
||||||
|
|
||||||
|
|
||||||
let (stys,styps) = (showTypes tys, [showTypes ty | (ty,_) <- typs])
|
|
||||||
|
|
||||||
-- to avoid strange error msg e.g. in case of unmatch record extension, show whole types if needed AR 28/1/2013
|
|
||||||
let (stysError,stypsError) = if elem (render stys) (map render styps)
|
|
||||||
then (hsep (map (ppTerm Unqualified 0) tys), [hsep (map (ppTerm Unqualified 0) ty) | (ty,_) <- typs])
|
|
||||||
else (stys,styps)
|
|
||||||
|
|
||||||
case ([vf | (vf,True) <- matches],[vf | (vf,False) <- matches]) of
|
|
||||||
([(_,val,fun)],_) -> return (mkApp fun tts, val)
|
|
||||||
([],[(pre,val,fun)]) -> do
|
|
||||||
checkWarn $ "ignoring lock fields in resolving" <+> ppTerm Unqualified 0 ot $$
|
|
||||||
"for" $$
|
|
||||||
nest 2 (showTypes tys) $$
|
|
||||||
"using" $$
|
|
||||||
nest 2 (showTypes pre)
|
|
||||||
return (mkApp fun tts, val)
|
|
||||||
([],[]) -> do
|
|
||||||
checkError $ "no overload instance of" <+> ppTerm Qualified 0 f $$
|
|
||||||
maybe empty (\x -> "with value type" <+> ppType x) mt $$
|
|
||||||
"for argument list" $$
|
|
||||||
nest 2 stysError $$
|
|
||||||
"among alternatives" $$
|
|
||||||
nest 2 (vcat stypsError)
|
|
||||||
|
|
||||||
|
|
||||||
(vfs1,vfs2) -> case (noProds vfs1,noProds vfs2) of
|
|
||||||
([(val,fun)],_) -> do
|
|
||||||
return (mkApp fun tts, val)
|
|
||||||
([],[(val,fun)]) -> do
|
|
||||||
checkWarn ("ignoring lock fields in resolving" <+> ppTerm Unqualified 0 ot)
|
|
||||||
return (mkApp fun tts, val)
|
|
||||||
|
|
||||||
----- unsafely exclude irritating warning AR 24/5/2008
|
|
||||||
----- checkWarn $ "overloading of" +++ prt f +++
|
|
||||||
----- "resolved by excluding partial applications:" ++++
|
|
||||||
----- unlines [prtType env ty | (ty,_) <- vfs', not (noProd ty)]
|
|
||||||
|
|
||||||
--- now forgiving ambiguity with a warning AR 1/2/2014
|
|
||||||
-- This gives ad hoc overloading the same behaviour as the choice of the first match in renaming did before.
|
|
||||||
-- But it also gives a chance to ambiguous overloadings that were banned before.
|
|
||||||
(nps1,nps2) -> do
|
|
||||||
checkWarn $ "ambiguous overloading of" <+> ppTerm Unqualified 0 f <+>
|
|
||||||
---- "with argument types" <+> hsep (map (ppTerm Qualified 0) tys) $$
|
|
||||||
"resolved by selecting the first of the alternatives" $$
|
|
||||||
nest 2 (vcat [ppTerm Qualified 0 fun | (_,ty,fun) <- vfs1 ++ if null vfs1 then vfs2 else []])
|
|
||||||
case [(mkApp fun tts,val) | (val,fun) <- nps1 ++ nps2] of
|
|
||||||
[] -> checkError $ "no alternatives left when resolving" <+> ppTerm Unqualified 0 f
|
|
||||||
h:_ -> return h
|
|
||||||
|
|
||||||
matchVal mt v = elem mt [Nothing,Just v,Just (unlocked v)]
|
|
||||||
|
|
||||||
unlocked v = case v of
|
|
||||||
RecType fs -> RecType $ filter (not . isLockLabel . fst) fs
|
|
||||||
_ -> v
|
|
||||||
---- TODO: accept subtypes
|
|
||||||
---- TODO: use a trie
|
|
||||||
lookupOverloadInstance tys typs =
|
|
||||||
[((pre,mkFunType rest val, t),isExact) |
|
|
||||||
let lt = length tys,
|
|
||||||
(ty,(val,t)) <- typs, length ty >= lt,
|
|
||||||
let (pre,rest) = splitAt lt ty,
|
|
||||||
let isExact = pre == tys,
|
|
||||||
isExact || map unlocked pre == map unlocked tys
|
|
||||||
]
|
|
||||||
|
|
||||||
noProds vfs = [(v,f) | (_,v,f) <- vfs, noProd v]
|
|
||||||
|
|
||||||
noProd ty = case ty of
|
|
||||||
Prod _ _ _ _ -> False
|
|
||||||
_ -> True
|
|
||||||
|
|
||||||
checkLType :: SourceGrammar -> Context -> Term -> Type -> Check (Term, Type)
|
|
||||||
checkLType gr g trm typ0 = do
|
|
||||||
typ <- computeLType gr g typ0
|
|
||||||
|
|
||||||
case trm of
|
|
||||||
|
|
||||||
Abs bt x c -> do
|
|
||||||
case typ of
|
|
||||||
Prod bt' z a b -> do
|
|
||||||
(c',b') <- if isWildIdent z
|
|
||||||
then checkLType gr ((bt,x,a):g) c b
|
|
||||||
else do b' <- checkIn (pp "abs") $ substituteLType [(bt',z,Vr x)] b
|
|
||||||
checkLType gr ((bt,x,a):g) c b'
|
|
||||||
return $ (Abs bt x c', Prod bt' z a b')
|
|
||||||
_ -> checkError $ "function type expected instead of" <+> ppType typ
|
|
||||||
|
|
||||||
App f a -> do
|
|
||||||
over <- getOverload gr g (Just typ) trm
|
|
||||||
case over of
|
|
||||||
Just trty -> return trty
|
|
||||||
_ -> do
|
|
||||||
(trm',ty') <- inferLType gr g trm
|
|
||||||
termWith trm' $ checkEqLType gr g typ ty' trm'
|
|
||||||
|
|
||||||
AdHocOverload ts -> do
|
|
||||||
over <- getOverload gr g Nothing trm
|
|
||||||
case over of
|
|
||||||
Just trty -> return trty
|
|
||||||
_ -> checkError ("unresolved overloading of constants" <+> ppTerm Qualified 0 trm)
|
|
||||||
|
|
||||||
Q _ -> do
|
|
||||||
over <- getOverload gr g (Just typ) trm
|
|
||||||
case over of
|
|
||||||
Just trty -> return trty
|
|
||||||
_ -> do
|
|
||||||
(trm',ty') <- inferLType gr g trm
|
|
||||||
termWith trm' $ checkEqLType gr g typ ty' trm'
|
|
||||||
|
|
||||||
T _ [] ->
|
|
||||||
checkError ("found empty table in type" <+> ppTerm Unqualified 0 typ)
|
|
||||||
T _ cs -> case typ of
|
|
||||||
Table arg val -> do
|
|
||||||
case allParamValues gr arg of
|
|
||||||
Ok vs -> do
|
|
||||||
let ps0 = map fst cs
|
|
||||||
ps <- testOvershadow ps0 vs
|
|
||||||
if null ps
|
|
||||||
then return ()
|
|
||||||
else checkWarn ("patterns never reached:" $$
|
|
||||||
nest 2 (vcat (map (ppPatt Unqualified 0) ps)))
|
|
||||||
_ -> return () -- happens with variable types
|
|
||||||
cs' <- mapM (checkCase arg val) cs
|
|
||||||
return (T (TTyped arg) cs', typ)
|
|
||||||
_ -> checkError $ "table type expected for table instead of" $$ nest 2 (ppType typ)
|
|
||||||
V arg0 vs ->
|
|
||||||
case typ of
|
|
||||||
Table arg1 val ->
|
|
||||||
do arg' <- checkEqLType gr g arg0 arg1 trm
|
|
||||||
vs1 <- allParamValues gr arg1
|
|
||||||
if length vs1 == length vs
|
|
||||||
then return ()
|
|
||||||
else checkError $ "wrong number of values in table" <+> ppTerm Unqualified 0 trm
|
|
||||||
vs' <- map fst `fmap` sequence [checkLType gr g v val|v<-vs]
|
|
||||||
return (V arg' vs',typ)
|
|
||||||
|
|
||||||
R r -> case typ of --- why needed? because inference may be too difficult
|
|
||||||
RecType rr -> do
|
|
||||||
--let (ls,_) = unzip rr -- labels of expected type
|
|
||||||
fsts <- mapM (checkM r) rr -- check that they are found in the record
|
|
||||||
return $ (R fsts, typ) -- normalize record
|
|
||||||
|
|
||||||
_ -> checkError ("record type expected in type checking instead of" $$ nest 2 (ppTerm Unqualified 0 typ))
|
|
||||||
|
|
||||||
ExtR r s -> case typ of
|
|
||||||
_ | typ == typeType -> do
|
|
||||||
trm' <- computeLType gr g trm
|
|
||||||
case trm' of
|
|
||||||
RecType _ -> termWith trm' $ return typeType
|
|
||||||
ExtR (Vr _) (RecType _) -> termWith trm' $ return typeType
|
|
||||||
-- ext t = t ** ...
|
|
||||||
_ -> checkError ("invalid record type extension" <+> nest 2 (ppTerm Unqualified 0 trm))
|
|
||||||
|
|
||||||
RecType rr -> do
|
|
||||||
|
|
||||||
ll2 <- case s of
|
|
||||||
R ss -> return $ map fst ss
|
|
||||||
_ -> do
|
|
||||||
(s',typ2) <- inferLType gr g s
|
|
||||||
case typ2 of
|
|
||||||
RecType ss -> return $ map fst ss
|
|
||||||
_ -> checkError ("cannot get labels from" $$ nest 2 (ppTerm Unqualified 0 typ2))
|
|
||||||
let ll1 = [l | (l,_) <- rr, notElem l ll2]
|
|
||||||
(r',_) <- checkLType gr g r (RecType [field | field@(l,_) <- rr, elem l ll1])
|
|
||||||
(s',_) <- checkLType gr g s (RecType [field | field@(l,_) <- rr, elem l ll2])
|
|
||||||
|
|
||||||
let rec = R ([(l,(Nothing,P r' l)) | l <- ll1] ++ [(l,(Nothing,P s' l)) | l <- ll2])
|
|
||||||
return (rec, typ)
|
|
||||||
|
|
||||||
ExtR ty ex -> do
|
|
||||||
r' <- justCheck g r ty
|
|
||||||
s' <- justCheck g s ex
|
|
||||||
return $ (ExtR r' s', typ) --- is this all? it assumes the same division in trm and typ
|
|
||||||
|
|
||||||
_ -> checkError ("record extension not meaningful for" <+> ppTerm Unqualified 0 typ)
|
|
||||||
|
|
||||||
FV vs -> do
|
|
||||||
ttys <- mapM (flip (checkLType gr g) typ) vs
|
|
||||||
--- checkIfComplexVariantType trm typ
|
|
||||||
return (FV (map fst ttys), typ) --- typ' ?
|
|
||||||
|
|
||||||
S tab arg -> checks [ do
|
|
||||||
(tab',ty) <- inferLType gr g tab
|
|
||||||
ty' <- computeLType gr g ty
|
|
||||||
case ty' of
|
|
||||||
Table p t -> do
|
|
||||||
(arg',val) <- checkLType gr g arg p
|
|
||||||
checkEqLType gr g typ t trm
|
|
||||||
return (S tab' arg', t)
|
|
||||||
_ -> checkError ("table type expected for applied table instead of" <+> ppType ty')
|
|
||||||
, do
|
|
||||||
(arg',ty) <- inferLType gr g arg
|
|
||||||
ty' <- computeLType gr g ty
|
|
||||||
(tab',_) <- checkLType gr g tab (Table ty' typ)
|
|
||||||
return (S tab' arg', typ)
|
|
||||||
]
|
|
||||||
Let (x,(mty,def)) body -> case mty of
|
|
||||||
Just ty -> do
|
|
||||||
(ty0,_) <- checkLType gr g ty typeType
|
|
||||||
(def',ty') <- checkLType gr g def ty0
|
|
||||||
body' <- justCheck ((Explicit,x,ty'):g) body typ
|
|
||||||
return (Let (x,(Just ty',def')) body', typ)
|
|
||||||
_ -> do
|
|
||||||
(def',ty) <- inferLType gr g def -- tries to infer type of local constant
|
|
||||||
checkLType gr g (Let (x,(Just ty,def')) body) typ
|
|
||||||
|
|
||||||
ELin c tr -> do
|
|
||||||
tr1 <- unlockRecord c tr
|
|
||||||
checkLType gr g tr1 typ
|
|
||||||
|
|
||||||
_ -> do
|
|
||||||
(trm',ty') <- inferLType gr g trm
|
|
||||||
termWith trm' $ checkEqLType gr g typ ty' trm'
|
|
||||||
where
|
|
||||||
justCheck g ty te = checkLType gr g ty te >>= return . fst
|
|
||||||
{-
|
|
||||||
recParts rr t = (RecType rr1,RecType rr2) where
|
|
||||||
(rr1,rr2) = partition (flip elem (map fst t) . fst) rr
|
|
||||||
-}
|
|
||||||
checkM rms (l,ty) = case lookup l rms of
|
|
||||||
Just (Just ty0,t) -> do
|
|
||||||
checkEqLType gr g ty ty0 t
|
|
||||||
(t',ty') <- checkLType gr g t ty
|
|
||||||
return (l,(Just ty',t'))
|
|
||||||
Just (_,t) -> do
|
|
||||||
(t',ty') <- checkLType gr g t ty
|
|
||||||
return (l,(Just ty',t'))
|
|
||||||
_ -> checkError $
|
|
||||||
if isLockLabel l
|
|
||||||
then let cat = drop 5 (showIdent (label2ident l))
|
|
||||||
in ppTerm Unqualified 0 (R rms) <+> "is not in the lincat of" <+> cat <>
|
|
||||||
"; try wrapping it with lin" <+> cat
|
|
||||||
else "cannot find value for label" <+> l <+> "in" <+> ppTerm Unqualified 0 (R rms)
|
|
||||||
|
|
||||||
checkCase arg val (p,t) = do
|
|
||||||
cont <- pattContext gr g arg p
|
|
||||||
t' <- justCheck (reverse cont ++ g) t val
|
|
||||||
return (p,t')
|
|
||||||
|
|
||||||
pattContext :: SourceGrammar -> Context -> Type -> Patt -> Check Context
|
|
||||||
pattContext env g typ p = case p of
|
|
||||||
PV x -> return [(Explicit,x,typ)]
|
|
||||||
PP (q,c) ps | q /= cPredef -> do ---- why this /=? AR 6/1/2006
|
|
||||||
t <- lookupResType env (q,c)
|
|
||||||
let (cont,v) = typeFormCnc t
|
|
||||||
checkCond ("wrong number of arguments for constructor in" <+> ppPatt Unqualified 0 p)
|
|
||||||
(length cont == length ps)
|
|
||||||
checkEqLType env g typ v (patt2term p)
|
|
||||||
mapM (\((_,_,ty),p) -> pattContext env g ty p) (zip cont ps) >>= return . concat
|
|
||||||
PR r -> do
|
|
||||||
typ' <- computeLType env g typ
|
|
||||||
case typ' of
|
|
||||||
RecType t -> do
|
|
||||||
let pts = [(ty,tr) | (l,tr) <- r, Just ty <- [lookup l t]]
|
|
||||||
----- checkWarn $ prt p ++++ show pts ----- debug
|
|
||||||
mapM (uncurry (pattContext env g)) pts >>= return . concat
|
|
||||||
_ -> checkError ("record type expected for pattern instead of" <+> ppTerm Unqualified 0 typ')
|
|
||||||
PT t p' -> do
|
|
||||||
checkEqLType env g typ t (patt2term p')
|
|
||||||
pattContext env g typ p'
|
|
||||||
|
|
||||||
PAs x p -> do
|
|
||||||
g' <- pattContext env g typ p
|
|
||||||
return ((Explicit,x,typ):g')
|
|
||||||
|
|
||||||
PAlt p' q -> do
|
|
||||||
g1 <- pattContext env g typ p'
|
|
||||||
g2 <- pattContext env g typ q
|
|
||||||
let pts = nub ([x | pt@(_,x,_) <- g1, notElem pt g2] ++ [x | pt@(_,x,_) <- g2, notElem pt g1])
|
|
||||||
checkCond
|
|
||||||
("incompatible bindings of" <+>
|
|
||||||
fsep pts <+>
|
|
||||||
"in pattern alterantives" <+> ppPatt Unqualified 0 p) (null pts)
|
|
||||||
return g1 -- must be g1 == g2
|
|
||||||
PSeq p q -> do
|
|
||||||
g1 <- pattContext env g typ p
|
|
||||||
g2 <- pattContext env g typ q
|
|
||||||
return $ g1 ++ g2
|
|
||||||
PRep p' -> noBind typeStr p'
|
|
||||||
PNeg p' -> noBind typ p'
|
|
||||||
|
|
||||||
_ -> return [] ---- check types!
|
|
||||||
where
|
|
||||||
noBind typ p' = do
|
|
||||||
co <- pattContext env g typ p'
|
|
||||||
if not (null co)
|
|
||||||
then checkWarn ("no variable bound inside pattern" <+> ppPatt Unqualified 0 p)
|
|
||||||
>> return []
|
|
||||||
else return []
|
|
||||||
|
|
||||||
checkEqLType :: SourceGrammar -> Context -> Type -> Type -> Term -> Check Type
|
|
||||||
checkEqLType gr g t u trm = do
|
|
||||||
(b,t',u',s) <- checkIfEqLType gr g t u trm
|
|
||||||
case b of
|
|
||||||
True -> return t'
|
|
||||||
False -> checkError $ s <+> "type of" <+> ppTerm Unqualified 0 trm $$
|
|
||||||
"expected:" <+> ppTerm Qualified 0 t $$ -- ppqType t u $$
|
|
||||||
"inferred:" <+> ppTerm Qualified 0 u -- ppqType u t
|
|
||||||
|
|
||||||
checkIfEqLType :: SourceGrammar -> Context -> Type -> Type -> Term -> Check (Bool,Type,Type,String)
|
|
||||||
checkIfEqLType gr g t u trm = do
|
|
||||||
t' <- computeLType gr g t
|
|
||||||
u' <- computeLType gr g u
|
|
||||||
case t' == u' || alpha [] t' u' of
|
|
||||||
True -> return (True,t',u',[])
|
|
||||||
-- forgive missing lock fields by only generating a warning.
|
|
||||||
--- better: use a flag to forgive? (AR 31/1/2006)
|
|
||||||
_ -> case missingLock [] t' u' of
|
|
||||||
Ok lo -> do
|
|
||||||
checkWarn $ "missing lock field" <+> fsep lo
|
|
||||||
return (True,t',u',[])
|
|
||||||
Bad s -> return (False,t',u',s)
|
|
||||||
|
|
||||||
where
|
|
||||||
|
|
||||||
-- check that u is a subtype of t
|
|
||||||
--- quick hack version of TC.eqVal
|
|
||||||
alpha g t u = case (t,u) of
|
|
||||||
|
|
||||||
-- error (the empty type!) is subtype of any other type
|
|
||||||
(_,u) | u == typeError -> True
|
|
||||||
|
|
||||||
-- contravariance
|
|
||||||
(Prod _ x a b, Prod _ y c d) -> alpha g c a && alpha ((x,y):g) b d
|
|
||||||
|
|
||||||
-- record subtyping
|
|
||||||
(RecType rs, RecType ts) -> all (\ (l,a) ->
|
|
||||||
any (\ (k,b) -> l == k && alpha g a b) ts) rs
|
|
||||||
(ExtR r s, ExtR r' s') -> alpha g r r' && alpha g s s'
|
|
||||||
(ExtR r s, t) -> alpha g r t || alpha g s t
|
|
||||||
|
|
||||||
-- the following say that Ints n is a subset of Int and of Ints m >= n
|
|
||||||
-- But why does it also allow Int as a subtype of Ints m? /TH 2014-04-04
|
|
||||||
(t,u) | Just m <- isTypeInts t, Just n <- isTypeInts u -> m >= n
|
|
||||||
| Just _ <- isTypeInts t, u == typeInt -> True ---- check size!
|
|
||||||
| t == typeInt, Just _ <- isTypeInts u -> True ---- why this ???? AR 11/12/2005
|
|
||||||
|
|
||||||
---- this should be made in Rename
|
|
||||||
(Q (m,a), Q (n,b)) | a == b -> elem m (allExtendsPlus gr n)
|
|
||||||
|| elem n (allExtendsPlus gr m)
|
|
||||||
|| m == n --- for Predef
|
|
||||||
(QC (m,a), QC (n,b)) | a == b -> elem m (allExtendsPlus gr n)
|
|
||||||
|| elem n (allExtendsPlus gr m)
|
|
||||||
(QC (m,a), Q (n,b)) | a == b -> elem m (allExtendsPlus gr n)
|
|
||||||
|| elem n (allExtendsPlus gr m)
|
|
||||||
(Q (m,a), QC (n,b)) | a == b -> elem m (allExtendsPlus gr n)
|
|
||||||
|| elem n (allExtendsPlus gr m)
|
|
||||||
|
|
||||||
-- contravariance
|
|
||||||
(Table a b, Table c d) -> alpha g c a && alpha g b d
|
|
||||||
(Vr x, Vr y) -> x == y || elem (x,y) g || elem (y,x) g
|
|
||||||
_ -> t == u
|
|
||||||
--- the following should be one-way coercions only. AR 4/1/2001
|
|
||||||
|| elem t sTypes && elem u sTypes
|
|
||||||
|| (t == typeType && u == typePType)
|
|
||||||
|| (u == typeType && t == typePType)
|
|
||||||
|
|
||||||
missingLock g t u = case (t,u) of
|
|
||||||
(RecType rs, RecType ts) ->
|
|
||||||
let
|
|
||||||
ls = [l | (l,a) <- rs,
|
|
||||||
not (any (\ (k,b) -> alpha g a b && l == k) ts)]
|
|
||||||
(locks,others) = partition isLockLabel ls
|
|
||||||
in case others of
|
|
||||||
_:_ -> Bad $ render ("missing record fields:" <+> fsep (punctuate ',' (others)))
|
|
||||||
_ -> return locks
|
|
||||||
-- contravariance
|
|
||||||
(Prod _ x a b, Prod _ y c d) -> do
|
|
||||||
ls1 <- missingLock g c a
|
|
||||||
ls2 <- missingLock g b d
|
|
||||||
return $ ls1 ++ ls2
|
|
||||||
|
|
||||||
_ -> Bad ""
|
|
||||||
|
|
||||||
sTypes = [typeStr, typeTok, typeString]
|
|
||||||
|
|
||||||
-- auxiliaries
|
|
||||||
|
|
||||||
-- | light-weight substitution for dep. types
|
|
||||||
substituteLType :: Context -> Type -> Check Type
|
|
||||||
substituteLType g t = case t of
|
|
||||||
Vr x -> return $ maybe t id $ lookup x [(x,t) | (_,x,t) <- g]
|
|
||||||
_ -> composOp (substituteLType g) t
|
|
||||||
|
|
||||||
termWith :: Term -> Check Type -> Check (Term, Type)
|
|
||||||
termWith t ct = do
|
|
||||||
ty <- ct
|
|
||||||
return (t,ty)
|
|
||||||
|
|
||||||
-- | compositional check\/infer of binary operations
|
|
||||||
check2 :: (Term -> Check Term) -> (Term -> Term -> Term) ->
|
|
||||||
Term -> Term -> Type -> Check (Term,Type)
|
|
||||||
check2 chk con a b t = do
|
|
||||||
a' <- chk a
|
|
||||||
b' <- chk b
|
|
||||||
return (con a' b', t)
|
|
||||||
|
|
||||||
-- printing a type with a lock field lock_C as C
|
|
||||||
ppType :: Type -> Doc
|
|
||||||
ppType ty =
|
|
||||||
case ty of
|
|
||||||
RecType fs -> case filter isLockLabel $ map fst fs of
|
|
||||||
[lock] -> pp (drop 5 (showIdent (label2ident lock)))
|
|
||||||
_ -> ppTerm Unqualified 0 ty
|
|
||||||
Prod _ x a b -> ppType a <+> "->" <+> ppType b
|
|
||||||
_ -> ppTerm Unqualified 0 ty
|
|
||||||
{-
|
|
||||||
ppqType :: Type -> Type -> Doc
|
|
||||||
ppqType t u = case (ppType t, ppType u) of
|
|
||||||
(pt,pu) | render pt == render pu -> ppTerm Qualified 0 t
|
|
||||||
(pt,_) -> pt
|
|
||||||
-}
|
|
||||||
checkLookup :: Ident -> Context -> Check Type
|
|
||||||
checkLookup x g =
|
|
||||||
case [ty | (b,y,ty) <- g, x == y] of
|
|
||||||
[] -> checkError ("unknown variable" <+> x)
|
|
||||||
(ty:_) -> return ty
|
|
||||||
@@ -12,7 +12,8 @@
|
|||||||
-- 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 (
|
||||||
|
AExp(..),
|
||||||
Theory,
|
Theory,
|
||||||
checkExp,
|
checkExp,
|
||||||
inferExp,
|
inferExp,
|
||||||
@@ -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)
|
||||||
|
|
||||||
|
|||||||
@@ -27,13 +27,14 @@ import Data.List
|
|||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
import Control.Monad
|
import Control.Monad
|
||||||
import GF.Text.Pretty
|
import GF.Text.Pretty
|
||||||
|
import qualified Control.Monad.Fail as Fail
|
||||||
|
|
||||||
-- | combine a list of definitions into a balanced binary search tree
|
-- | combine a list of definitions into a balanced binary search tree
|
||||||
buildAnyTree :: Monad m => ModuleName -> [(Ident,Info)] -> m (Map.Map Ident Info)
|
buildAnyTree :: Fail.MonadFail m => ModuleName -> [(Ident,Info)] -> m (Map.Map Ident Info)
|
||||||
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
|
||||||
@@ -109,8 +110,9 @@ rebuildModule cwd gr mo@(i,mi@(ModInfo mt stat fs_ me mw ops_ med_ msrc_ env_ js
|
|||||||
-- add the instance opens to an incomplete module "with" instances
|
-- add the instance opens to an incomplete module "with" instances
|
||||||
Just (ext,incl,ops) -> do
|
Just (ext,incl,ops) -> do
|
||||||
let (infs,insts) = unzip ops
|
let (infs,insts) = unzip ops
|
||||||
let stat' = ifNull MSComplete (const MSIncomplete)
|
let stat' = if all (flip elem infs) is
|
||||||
[i | i <- is, notElem i infs]
|
then MSComplete
|
||||||
|
else MSIncomplete
|
||||||
unless (stat' == MSComplete || stat == MSIncomplete)
|
unless (stat' == MSComplete || stat == MSIncomplete)
|
||||||
(checkError ("module" <+> i <+> "remains incomplete"))
|
(checkError ("module" <+> i <+> "remains incomplete"))
|
||||||
ModInfo mt0 _ fs me' _ ops0 _ fpath _ js <- lookupModule gr ext
|
ModInfo mt0 _ fs me' _ ops0 _ fpath _ js <- lookupModule gr ext
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ import GF.Infra.Ident(moduleNameS)
|
|||||||
import GF.Text.Pretty
|
import GF.Text.Pretty
|
||||||
import GF.System.Console(TermColors(..),getTermColors)
|
import GF.System.Console(TermColors(..),getTermColors)
|
||||||
import qualified Data.ByteString.Lazy as BS
|
import qualified Data.ByteString.Lazy as BS
|
||||||
|
-- Control.Monad.Fail import will become redundant in GHC 8.8+
|
||||||
|
import qualified Control.Monad.Fail as Fail
|
||||||
|
|
||||||
-- | Compile the given grammar files and everything they depend on,
|
-- | Compile the given grammar files and everything they depend on,
|
||||||
-- like 'batchCompile'. This function compiles modules in parallel.
|
-- like 'batchCompile'. This function compiles modules in parallel.
|
||||||
@@ -83,7 +85,7 @@ batchCompile1 lib_dir (opts,filepaths) =
|
|||||||
let rel = relativeTo lib_dir cwd
|
let rel = relativeTo lib_dir cwd
|
||||||
prelude_dir = lib_dir</>"prelude"
|
prelude_dir = lib_dir</>"prelude"
|
||||||
gfoDir = flag optGFODir opts
|
gfoDir = flag optGFODir opts
|
||||||
maybe done (D.createDirectoryIfMissing True) gfoDir
|
maybe (return ()) (D.createDirectoryIfMissing True) gfoDir
|
||||||
{-
|
{-
|
||||||
liftIO $ writeFile (maybe "" id gfoDir</>"paths")
|
liftIO $ writeFile (maybe "" id gfoDir</>"paths")
|
||||||
(unlines . map (unwords . map rel) . nub $ map snd filepaths)
|
(unlines . map (unwords . map rel) . nub $ map snd filepaths)
|
||||||
@@ -241,14 +243,14 @@ instance (Functor m,Monad m) => Applicative (CollectOutput m) where
|
|||||||
(<*>) = ap
|
(<*>) = ap
|
||||||
|
|
||||||
instance Monad m => Monad (CollectOutput m) where
|
instance Monad m => Monad (CollectOutput m) where
|
||||||
return x = CO (return (done,x))
|
return x = CO (return (return (),x))
|
||||||
CO m >>= f = CO $ do (o1,x) <- m
|
CO m >>= f = CO $ do (o1,x) <- m
|
||||||
let CO m2 = f x
|
let CO m2 = f x
|
||||||
(o2,y) <- m2
|
(o2,y) <- m2
|
||||||
return (o1>>o2,y)
|
return (o1>>o2,y)
|
||||||
instance MonadIO m => MonadIO (CollectOutput m) where
|
instance MonadIO m => MonadIO (CollectOutput m) where
|
||||||
liftIO io = CO $ do x <- liftIO io
|
liftIO io = CO $ do x <- liftIO io
|
||||||
return (done,x)
|
return (return (),x)
|
||||||
|
|
||||||
instance Output m => Output (CollectOutput m) where
|
instance Output m => Output (CollectOutput m) where
|
||||||
ePutStr s = CO (return (ePutStr s,()))
|
ePutStr s = CO (return (ePutStr s,()))
|
||||||
@@ -256,6 +258,9 @@ instance Output m => Output (CollectOutput m) where
|
|||||||
putStrLnE s = CO (return (putStrLnE s,()))
|
putStrLnE s = CO (return (putStrLnE s,()))
|
||||||
putStrE s = CO (return (putStrE s,()))
|
putStrE s = CO (return (putStrE s,()))
|
||||||
|
|
||||||
|
instance Fail.MonadFail m => Fail.MonadFail (CollectOutput m) where
|
||||||
|
fail = CO . fail
|
||||||
|
|
||||||
instance ErrorMonad m => ErrorMonad (CollectOutput m) where
|
instance ErrorMonad m => ErrorMonad (CollectOutput m) where
|
||||||
raise e = CO (raise e)
|
raise e = CO (raise e)
|
||||||
handle (CO m) h = CO $ handle m (unCO . h)
|
handle (CO m) h = CO $ handle m (unCO . h)
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import GF.Grammar.Binary(decodeModule,encodeModule)
|
|||||||
import GF.Infra.Option
|
import GF.Infra.Option
|
||||||
import GF.Infra.UseIO(FullPath,IOE,isGFO,gf2gfo,MonadIO(..),Output(..),putPointE)
|
import GF.Infra.UseIO(FullPath,IOE,isGFO,gf2gfo,MonadIO(..),Output(..),putPointE)
|
||||||
import GF.Infra.CheckM(runCheck')
|
import GF.Infra.CheckM(runCheck')
|
||||||
import GF.Data.Operations(ErrorMonad,liftErr,(+++),done)
|
import GF.Data.Operations(ErrorMonad,liftErr,(+++))
|
||||||
|
|
||||||
import GF.System.Directory(doesFileExist,getCurrentDirectory,renameFile)
|
import GF.System.Directory(doesFileExist,getCurrentDirectory,renameFile)
|
||||||
import System.FilePath(makeRelative)
|
import System.FilePath(makeRelative)
|
||||||
@@ -30,12 +30,13 @@ import qualified Data.Map as Map
|
|||||||
import GF.Text.Pretty(render,(<+>),($$)) --Doc,
|
import GF.Text.Pretty(render,(<+>),($$)) --Doc,
|
||||||
import GF.System.Console(TermColors(..),getTermColors)
|
import GF.System.Console(TermColors(..),getTermColors)
|
||||||
import Control.Monad((<=<))
|
import Control.Monad((<=<))
|
||||||
|
import qualified Control.Monad.Fail as Fail
|
||||||
|
|
||||||
type OneOutput = (Maybe FullPath,CompiledModule)
|
type OneOutput = (Maybe FullPath,CompiledModule)
|
||||||
type CompiledModule = Module
|
type CompiledModule = Module
|
||||||
|
|
||||||
compileOne, reuseGFO, useTheSource ::
|
compileOne, reuseGFO, useTheSource ::
|
||||||
(Output m,ErrorMonad m,MonadIO m) =>
|
(Output m,ErrorMonad m,MonadIO m, Fail.MonadFail m) =>
|
||||||
Options -> Grammar -> FullPath -> m OneOutput
|
Options -> Grammar -> FullPath -> m OneOutput
|
||||||
|
|
||||||
-- | Compile a given source file (or just load a .gfo file),
|
-- | Compile a given source file (or just load a .gfo file),
|
||||||
@@ -66,7 +67,7 @@ reuseGFO opts srcgr file =
|
|||||||
|
|
||||||
if flag optTagsOnly opts
|
if flag optTagsOnly opts
|
||||||
then writeTags opts srcgr (gf2gftags opts file) sm1
|
then writeTags opts srcgr (gf2gftags opts file) sm1
|
||||||
else done
|
else return ()
|
||||||
|
|
||||||
return (Just file,sm)
|
return (Just file,sm)
|
||||||
|
|
||||||
@@ -137,7 +138,7 @@ compileSourceModule opts cwd mb_gfFile gr =
|
|||||||
idump opts pass (dump out)
|
idump opts pass (dump out)
|
||||||
return (ret out)
|
return (ret out)
|
||||||
|
|
||||||
maybeM f = maybe done f
|
maybeM f = maybe (return ()) f
|
||||||
|
|
||||||
|
|
||||||
--writeGFO :: Options -> InitPath -> FilePath -> SourceModule -> IOE ()
|
--writeGFO :: Options -> InitPath -> FilePath -> SourceModule -> IOE ()
|
||||||
@@ -158,12 +159,12 @@ writeGFO opts cwd file mo =
|
|||||||
--intermOut :: Options -> Dump -> Doc -> IOE ()
|
--intermOut :: Options -> Dump -> Doc -> IOE ()
|
||||||
intermOut opts d doc
|
intermOut opts d doc
|
||||||
| dump opts d = ePutStrLn (render ("\n\n--#" <+> show d $$ doc))
|
| dump opts d = ePutStrLn (render ("\n\n--#" <+> show d $$ doc))
|
||||||
| otherwise = done
|
| otherwise = return ()
|
||||||
|
|
||||||
idump opts pass = intermOut opts (Dump pass) . ppModule Internal
|
idump opts pass = intermOut opts (Dump pass) . ppModule Internal
|
||||||
|
|
||||||
warnOut opts warnings
|
warnOut opts warnings
|
||||||
| null warnings = done
|
| null warnings = return ()
|
||||||
| otherwise = do t <- getTermColors
|
| otherwise = do t <- getTermColors
|
||||||
ePutStr (blueFg t);ePutStr ws;ePutStrLn (restore t)
|
ePutStr (blueFg t);ePutStr ws;ePutStrLn (restore t)
|
||||||
where
|
where
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
|
|
||||||
{-# LANGUAGE Rank2Types, MultiParamTypeClasses, FlexibleInstances #-}
|
{-# LANGUAGE Rank2Types, MultiParamTypeClasses, FlexibleInstances #-}
|
||||||
|
{-# LANGUAGE CPP #-}
|
||||||
module GF.Data.BacktrackM (
|
module GF.Data.BacktrackM (
|
||||||
-- * the backtracking state monad
|
-- * the backtracking state monad
|
||||||
BacktrackM,
|
BacktrackM,
|
||||||
@@ -32,6 +33,7 @@ import Data.List
|
|||||||
import Control.Applicative
|
import Control.Applicative
|
||||||
import Control.Monad
|
import Control.Monad
|
||||||
import Control.Monad.State.Class
|
import Control.Monad.State.Class
|
||||||
|
import qualified Control.Monad.Fail as Fail
|
||||||
|
|
||||||
----------------------------------------------------------------------
|
----------------------------------------------------------------------
|
||||||
-- Combining endomorphisms and continuations
|
-- Combining endomorphisms and continuations
|
||||||
@@ -69,6 +71,12 @@ 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))
|
||||||
|
fail = Fail.fail
|
||||||
|
#endif
|
||||||
|
|
||||||
|
instance Fail.MonadFail (BacktrackM s) where
|
||||||
fail _ = mzero
|
fail _ = mzero
|
||||||
|
|
||||||
instance Functor (BacktrackM s) where
|
instance Functor (BacktrackM s) where
|
||||||
|
|||||||
@@ -12,10 +12,12 @@
|
|||||||
-- hack for BNFC generated files. AR 21/9/2003
|
-- hack for BNFC generated files. AR 21/9/2003
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
{-# LANGUAGE CPP #-}
|
||||||
module GF.Data.ErrM where
|
module GF.Data.ErrM where
|
||||||
|
|
||||||
import Control.Monad (MonadPlus(..),ap)
|
import Control.Monad (MonadPlus(..),ap)
|
||||||
import Control.Applicative
|
import Control.Applicative
|
||||||
|
import qualified Control.Monad.Fail as Fail
|
||||||
|
|
||||||
-- | Like 'Maybe' type with error msgs
|
-- | Like 'Maybe' type with error msgs
|
||||||
data Err a = Ok a | Bad String
|
data Err a = Ok a | Bad String
|
||||||
@@ -33,10 +35,19 @@ fromErr a = err (const a) id
|
|||||||
|
|
||||||
instance Monad Err where
|
instance Monad Err where
|
||||||
return = Ok
|
return = Ok
|
||||||
fail = Bad
|
|
||||||
Ok a >>= f = f a
|
Ok a >>= f = f a
|
||||||
Bad s >>= f = Bad s
|
Bad s >>= f = Bad s
|
||||||
|
|
||||||
|
#if !(MIN_VERSION_base(4,13,0))
|
||||||
|
-- Monad(fail) will be removed in GHC 8.8+
|
||||||
|
fail = Fail.fail
|
||||||
|
#endif
|
||||||
|
|
||||||
|
instance Fail.MonadFail Err where
|
||||||
|
fail = Bad
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- | added 2\/10\/2003 by PEB
|
-- | added 2\/10\/2003 by PEB
|
||||||
instance Functor Err where
|
instance Functor Err where
|
||||||
fmap f (Ok a) = Ok (f a)
|
fmap f (Ok a) = Ok (f a)
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ module GF.Data.Operations (
|
|||||||
checkUnique, unifyMaybeBy, unifyMaybe,
|
checkUnique, unifyMaybeBy, unifyMaybe,
|
||||||
|
|
||||||
-- ** Monadic operations on lists and pairs
|
-- ** Monadic operations on lists and pairs
|
||||||
mapPairListM, mapPairsM, pairM,
|
mapPairsM, pairM,
|
||||||
|
|
||||||
-- ** Printing
|
-- ** Printing
|
||||||
indent, (+++), (++-), (++++), (+++-), (+++++),
|
indent, (+++), (++-), (++++), (+++-), (+++++),
|
||||||
@@ -39,8 +39,7 @@ module GF.Data.Operations (
|
|||||||
topoTest, topoTest2,
|
topoTest, topoTest2,
|
||||||
|
|
||||||
-- ** Misc
|
-- ** Misc
|
||||||
ifNull,
|
readIntArg,
|
||||||
combinations, done, readIntArg, --singleton,
|
|
||||||
iterFix, chunks,
|
iterFix, chunks,
|
||||||
|
|
||||||
) where
|
) where
|
||||||
@@ -54,15 +53,13 @@ import Control.Monad (liftM,liftM2) --,ap
|
|||||||
|
|
||||||
import GF.Data.ErrM
|
import GF.Data.ErrM
|
||||||
import GF.Data.Relation
|
import GF.Data.Relation
|
||||||
|
import qualified Control.Monad.Fail as Fail
|
||||||
|
|
||||||
infixr 5 +++
|
infixr 5 +++
|
||||||
infixr 5 ++-
|
infixr 5 ++-
|
||||||
infixr 5 ++++
|
infixr 5 ++++
|
||||||
infixr 5 +++++
|
infixr 5 +++++
|
||||||
|
|
||||||
ifNull :: b -> ([a] -> b) -> [a] -> b
|
|
||||||
ifNull b f xs = if null xs then b else f xs
|
|
||||||
|
|
||||||
-- the Error monad
|
-- the Error monad
|
||||||
|
|
||||||
-- | Add msg s to 'Maybe' failures
|
-- | Add msg s to 'Maybe' failures
|
||||||
@@ -70,7 +67,7 @@ maybeErr :: ErrorMonad m => String -> Maybe a -> m a
|
|||||||
maybeErr s = maybe (raise s) return
|
maybeErr s = maybe (raise s) return
|
||||||
|
|
||||||
testErr :: ErrorMonad m => Bool -> String -> m ()
|
testErr :: ErrorMonad m => Bool -> String -> m ()
|
||||||
testErr cond msg = if cond then done else raise msg
|
testErr cond msg = if cond then return () else raise msg
|
||||||
|
|
||||||
errIn :: ErrorMonad m => String -> m a -> m a
|
errIn :: ErrorMonad m => String -> m a -> m a
|
||||||
errIn msg m = handle m (\s -> raise (s ++++ "OCCURRED IN" ++++ msg))
|
errIn msg m = handle m (\s -> raise (s ++++ "OCCURRED IN" ++++ msg))
|
||||||
@@ -78,9 +75,6 @@ errIn msg m = handle m (\s -> raise (s ++++ "OCCURRED IN" ++++ msg))
|
|||||||
lookupErr :: (ErrorMonad m,Eq a,Show a) => a -> [(a,b)] -> m b
|
lookupErr :: (ErrorMonad m,Eq a,Show a) => a -> [(a,b)] -> m b
|
||||||
lookupErr a abs = maybeErr ("Unknown" +++ show a) (lookup a abs)
|
lookupErr a abs = maybeErr ("Unknown" +++ show a) (lookup a abs)
|
||||||
|
|
||||||
mapPairListM :: Monad m => ((a,b) -> m c) -> [(a,b)] -> m [(a,c)]
|
|
||||||
mapPairListM f xys = mapM (\ p@(x,_) -> liftM ((,) x) (f p)) xys
|
|
||||||
|
|
||||||
mapPairsM :: Monad m => (b -> m c) -> [(a,b)] -> m [(a,c)]
|
mapPairsM :: Monad m => (b -> m c) -> [(a,b)] -> m [(a,c)]
|
||||||
mapPairsM f xys = mapM (\ (x,y) -> liftM ((,) x) (f y)) xys
|
mapPairsM f xys = mapM (\ (x,y) -> liftM ((,) x) (f y)) xys
|
||||||
|
|
||||||
@@ -95,10 +89,10 @@ checkUnique ss = ["overloaded" +++ show s | s <- nub overloads] where
|
|||||||
overloaded s = length (filter (==s) ss) > 1
|
overloaded s = length (filter (==s) ss) > 1
|
||||||
|
|
||||||
-- | this is what happens when matching two values in the same module
|
-- | this is what happens when matching two values in the same module
|
||||||
unifyMaybe :: (Eq a, Monad m) => Maybe a -> Maybe a -> m (Maybe a)
|
unifyMaybe :: (Eq a, Fail.MonadFail m) => Maybe a -> Maybe a -> m (Maybe a)
|
||||||
unifyMaybe = unifyMaybeBy id
|
unifyMaybe = unifyMaybeBy id
|
||||||
|
|
||||||
unifyMaybeBy :: (Eq b, Monad m) => (a->b) -> Maybe a -> Maybe a -> m (Maybe a)
|
unifyMaybeBy :: (Eq b, Fail.MonadFail m) => (a->b) -> Maybe a -> Maybe a -> m (Maybe a)
|
||||||
unifyMaybeBy f (Just p1) (Just p2)
|
unifyMaybeBy f (Just p1) (Just p2)
|
||||||
| f p1==f p2 = return (Just p1)
|
| f p1==f p2 = return (Just p1)
|
||||||
| otherwise = fail ""
|
| otherwise = fail ""
|
||||||
@@ -193,21 +187,6 @@ wrapLines n s@(c:cs) =
|
|||||||
l = length w
|
l = length w
|
||||||
_ -> s -- give up!!
|
_ -> s -- give up!!
|
||||||
|
|
||||||
--- optWrapLines = if argFlag "wraplines" True then wrapLines 0 else id
|
|
||||||
|
|
||||||
-- | 'combinations' is the same as 'sequence'!!!
|
|
||||||
-- peb 30\/5-04
|
|
||||||
combinations :: [[a]] -> [[a]]
|
|
||||||
combinations t = case t of
|
|
||||||
[] -> [[]]
|
|
||||||
aa:uu -> [a:u | a <- aa, u <- combinations uu]
|
|
||||||
|
|
||||||
{-
|
|
||||||
-- | 'singleton' is the same as 'return'!!!
|
|
||||||
singleton :: a -> [a]
|
|
||||||
singleton = (:[])
|
|
||||||
-}
|
|
||||||
|
|
||||||
-- | Topological sorting with test of cyclicity
|
-- | Topological sorting with test of cyclicity
|
||||||
topoTest :: Ord a => [(a,[a])] -> Either [a] [[a]]
|
topoTest :: Ord a => [(a,[a])] -> Either [a] [[a]]
|
||||||
topoTest = topologicalSort . mkRel'
|
topoTest = topologicalSort . mkRel'
|
||||||
@@ -247,10 +226,6 @@ chunks sep ws = case span (/= sep) ws of
|
|||||||
readIntArg :: String -> Int
|
readIntArg :: String -> Int
|
||||||
readIntArg n = if (not (null n) && all isDigit n) then read n else 0
|
readIntArg n = if (not (null n) && all isDigit n) then read n else 0
|
||||||
|
|
||||||
-- | @return ()@
|
|
||||||
done :: Monad m => m ()
|
|
||||||
done = return ()
|
|
||||||
|
|
||||||
class (Functor m,Monad m) => ErrorMonad m where
|
class (Functor m,Monad m) => ErrorMonad m where
|
||||||
raise :: String -> m a
|
raise :: String -> m a
|
||||||
handle :: m a -> (String -> m a) -> m a
|
handle :: m a -> (String -> m a) -> m a
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
module GF.Grammar.Canonical where
|
module GF.Grammar.Canonical where
|
||||||
import Prelude hiding ((<>))
|
import Prelude hiding ((<>))
|
||||||
import GF.Text.Pretty
|
import GF.Text.Pretty
|
||||||
|
import GF.Infra.Ident (RawIdent)
|
||||||
|
|
||||||
-- | A Complete grammar
|
-- | A Complete grammar
|
||||||
data Grammar = Grammar Abstract [Concrete] deriving Show
|
data Grammar = Grammar Abstract [Concrete] deriving Show
|
||||||
@@ -126,7 +127,7 @@ data FlagValue = Str String | Int Int | Flt Double deriving Show
|
|||||||
|
|
||||||
-- *** Identifiers
|
-- *** Identifiers
|
||||||
|
|
||||||
type Id = String
|
type Id = RawIdent
|
||||||
data QualId = Qual ModId Id | Unqual Id deriving (Eq,Ord,Show)
|
data QualId = Qual ModId Id | Unqual Id deriving (Eq,Ord,Show)
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
@@ -265,7 +266,6 @@ instance PPA LinPattern where
|
|||||||
RecordPattern r -> block r
|
RecordPattern r -> block r
|
||||||
TuplePattern ps -> "<"<>punctuate "," ps<>">"
|
TuplePattern ps -> "<"<>punctuate "," ps<>">"
|
||||||
WildPattern -> pp "_"
|
WildPattern -> pp "_"
|
||||||
_ -> parens p
|
|
||||||
|
|
||||||
instance RhsSeparator LinPattern where rhsSep _ = pp "="
|
instance RhsSeparator LinPattern where rhsSep _ = pp "="
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import Text.JSON
|
|||||||
import Control.Applicative ((<|>))
|
import Control.Applicative ((<|>))
|
||||||
import Data.Ratio (denominator, numerator)
|
import Data.Ratio (denominator, numerator)
|
||||||
import GF.Grammar.Canonical
|
import GF.Grammar.Canonical
|
||||||
|
import Control.Monad (guard)
|
||||||
|
import GF.Infra.Ident (RawIdent,showRawIdent,rawIdentS)
|
||||||
|
|
||||||
|
|
||||||
encodeJSON :: FilePath -> Grammar -> IO ()
|
encodeJSON :: FilePath -> Grammar -> IO ()
|
||||||
@@ -126,10 +128,10 @@ instance JSON LinType where
|
|||||||
-- records are encoded as records:
|
-- records are encoded as records:
|
||||||
showJSON (RecordType rows) = showJSON rows
|
showJSON (RecordType rows) = showJSON rows
|
||||||
|
|
||||||
readJSON o = do "Str" <- readJSON o; return StrType
|
readJSON o = StrType <$ parseString "Str" o
|
||||||
<|> do "Float" <- readJSON o; return FloatType
|
<|> FloatType <$ parseString "Float" o
|
||||||
<|> do "Int" <- readJSON o; return IntType
|
<|> IntType <$ parseString "Int" o
|
||||||
<|> do ptype <- readJSON o; return (ParamType ptype)
|
<|> ParamType <$> readJSON o
|
||||||
<|> TableType <$> o!".tblarg" <*> o!".tblval"
|
<|> TableType <$> o!".tblarg" <*> o!".tblval"
|
||||||
<|> TupleType <$> o!".tuple"
|
<|> TupleType <$> o!".tuple"
|
||||||
<|> RecordType <$> readJSON o
|
<|> RecordType <$> readJSON o
|
||||||
@@ -186,7 +188,7 @@ instance JSON LinPattern where
|
|||||||
-- and records as records:
|
-- and records as records:
|
||||||
showJSON (RecordPattern r) = showJSON r
|
showJSON (RecordPattern r) = showJSON r
|
||||||
|
|
||||||
readJSON o = do "_" <- readJSON o; return WildPattern
|
readJSON o = do p <- parseString "_" o; return WildPattern
|
||||||
<|> do p <- readJSON o; return (ParamPattern (Param p []))
|
<|> do p <- readJSON o; return (ParamPattern (Param p []))
|
||||||
<|> ParamPattern <$> readJSON o
|
<|> ParamPattern <$> readJSON o
|
||||||
<|> RecordPattern <$> readJSON o
|
<|> RecordPattern <$> readJSON o
|
||||||
@@ -203,12 +205,12 @@ instance JSON a => JSON (RecordRow a) where
|
|||||||
-- record rows and lists of record rows are both encoded as JSON records (i.e., objects)
|
-- record rows and lists of record rows are both encoded as JSON records (i.e., objects)
|
||||||
showJSON row = showJSONs [row]
|
showJSON row = showJSONs [row]
|
||||||
showJSONs rows = makeObj (map toRow rows)
|
showJSONs rows = makeObj (map toRow rows)
|
||||||
where toRow (RecordRow (LabelId lbl) val) = (lbl, showJSON val)
|
where toRow (RecordRow (LabelId lbl) val) = (showRawIdent lbl, showJSON val)
|
||||||
|
|
||||||
readJSON obj = head <$> readJSONs obj
|
readJSON obj = head <$> readJSONs obj
|
||||||
readJSONs obj = mapM fromRow (assocsJSObject obj)
|
readJSONs obj = mapM fromRow (assocsJSObject obj)
|
||||||
where fromRow (lbl, jsvalue) = do value <- readJSON jsvalue
|
where fromRow (lbl, jsvalue) = do value <- readJSON jsvalue
|
||||||
return (RecordRow (LabelId lbl) value)
|
return (RecordRow (LabelId (rawIdentS lbl)) value)
|
||||||
|
|
||||||
instance JSON rhs => JSON (TableRow rhs) where
|
instance JSON rhs => JSON (TableRow rhs) where
|
||||||
showJSON (TableRow l v) = makeObj [(".pattern", showJSON l), (".value", showJSON v)]
|
showJSON (TableRow l v) = makeObj [(".pattern", showJSON l), (".value", showJSON v)]
|
||||||
@@ -237,24 +239,28 @@ instance JSON VarId where
|
|||||||
showJSON Anonymous = showJSON "_"
|
showJSON Anonymous = showJSON "_"
|
||||||
showJSON (VarId x) = showJSON x
|
showJSON (VarId x) = showJSON x
|
||||||
|
|
||||||
readJSON o = do "_" <- readJSON o; return Anonymous
|
readJSON o = do parseString "_" o; return Anonymous
|
||||||
<|> VarId <$> readJSON o
|
<|> VarId <$> readJSON o
|
||||||
|
|
||||||
instance JSON QualId where
|
instance JSON QualId where
|
||||||
showJSON (Qual (ModId m) n) = showJSON (m++"."++n)
|
showJSON (Qual (ModId m) n) = showJSON (showRawIdent m++"."++showRawIdent n)
|
||||||
showJSON (Unqual n) = showJSON n
|
showJSON (Unqual n) = showJSON n
|
||||||
|
|
||||||
readJSON o = do qualid <- readJSON o
|
readJSON o = do qualid <- readJSON o
|
||||||
let (mod, id) = span (/= '.') qualid
|
let (mod, id) = span (/= '.') qualid
|
||||||
return $ if null mod then Unqual id else Qual (ModId mod) id
|
return $ if null mod then Unqual (rawIdentS id) else Qual (ModId (rawIdentS mod)) (rawIdentS id)
|
||||||
|
|
||||||
|
instance JSON RawIdent where
|
||||||
|
showJSON i = showJSON $ showRawIdent i
|
||||||
|
readJSON o = rawIdentS <$> readJSON o
|
||||||
|
|
||||||
instance JSON Flags where
|
instance JSON Flags where
|
||||||
-- flags are encoded directly as JSON records (i.e., objects):
|
-- flags are encoded directly as JSON records (i.e., objects):
|
||||||
showJSON (Flags fs) = makeObj [(f, showJSON v) | (f, v) <- fs]
|
showJSON (Flags fs) = makeObj [(showRawIdent f, showJSON v) | (f, v) <- fs]
|
||||||
|
|
||||||
readJSON obj = Flags <$> mapM fromRow (assocsJSObject obj)
|
readJSON obj = Flags <$> mapM fromRow (assocsJSObject obj)
|
||||||
where fromRow (lbl, jsvalue) = do value <- readJSON jsvalue
|
where fromRow (lbl, jsvalue) = do value <- readJSON jsvalue
|
||||||
return (lbl, value)
|
return (rawIdentS lbl, value)
|
||||||
|
|
||||||
instance JSON FlagValue where
|
instance JSON FlagValue where
|
||||||
-- flag values are encoded as basic JSON types:
|
-- flag values are encoded as basic JSON types:
|
||||||
@@ -268,6 +274,9 @@ instance JSON FlagValue where
|
|||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
-- ** Convenience functions
|
-- ** Convenience functions
|
||||||
|
|
||||||
|
parseString :: String -> JSValue -> Result ()
|
||||||
|
parseString s o = guard . (== s) =<< readJSON o
|
||||||
|
|
||||||
(!) :: JSON a => JSValue -> String -> Result a
|
(!) :: JSON a => JSValue -> String -> Result a
|
||||||
obj ! key = maybe (fail $ "CanonicalJSON.(!): Could not find key: " ++ show key)
|
obj ! key = maybe (fail $ "CanonicalJSON.(!): Could not find key: " ++ show key)
|
||||||
readJSON
|
readJSON
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
-- -*- haskell -*-
|
-- -*- haskell -*-
|
||||||
{
|
{
|
||||||
|
{-# LANGUAGE CPP #-}
|
||||||
module GF.Grammar.Lexer
|
module GF.Grammar.Lexer
|
||||||
( Token(..), Posn(..)
|
( Token(..), Posn(..)
|
||||||
, P, runP, runPartial, token, lexer, getPosn, failLoc
|
, P, runP, runPartial, token, lexer, getPosn, failLoc
|
||||||
@@ -18,6 +19,7 @@ import qualified Data.Map as Map
|
|||||||
import Data.Word(Word8)
|
import Data.Word(Word8)
|
||||||
import Data.Char(readLitChar)
|
import Data.Char(readLitChar)
|
||||||
--import Debug.Trace(trace)
|
--import Debug.Trace(trace)
|
||||||
|
import qualified Control.Monad.Fail as Fail
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -282,8 +284,16 @@ instance Monad P where
|
|||||||
(P m) >>= k = P $ \ s -> case m s of
|
(P m) >>= k = P $ \ s -> case m s of
|
||||||
POk s a -> unP (k a) s
|
POk s a -> unP (k a) s
|
||||||
PFailed posn err -> PFailed posn err
|
PFailed posn err -> PFailed posn err
|
||||||
|
|
||||||
|
#if !(MIN_VERSION_base(4,13,0))
|
||||||
|
-- Monad(fail) will be removed in GHC 8.8+
|
||||||
|
fail = Fail.fail
|
||||||
|
#endif
|
||||||
|
|
||||||
|
instance Fail.MonadFail P where
|
||||||
fail msg = P $ \(_,AI posn _ _) -> PFailed posn msg
|
fail msg = P $ \(_,AI posn _ _) -> PFailed posn msg
|
||||||
|
|
||||||
|
|
||||||
runP :: P a -> BS.ByteString -> Either (Posn,String) a
|
runP :: P a -> BS.ByteString -> Either (Posn,String) a
|
||||||
runP p bs = snd <$> runP' p (Pn 1 0,bs)
|
runP p bs = snd <$> runP' p (Pn 1 0,bs)
|
||||||
|
|
||||||
|
|||||||
@@ -166,11 +166,11 @@ allParamValues cnc ptyp =
|
|||||||
RecType r -> do
|
RecType r -> do
|
||||||
let (ls,tys) = unzip $ sortByFst r
|
let (ls,tys) = unzip $ sortByFst r
|
||||||
tss <- mapM (allParamValues cnc) tys
|
tss <- mapM (allParamValues cnc) tys
|
||||||
return [R (zipAssign ls ts) | ts <- combinations tss]
|
return [R (zipAssign ls ts) | ts <- sequence tss]
|
||||||
Table pt vt -> do
|
Table pt vt -> do
|
||||||
pvs <- allParamValues cnc pt
|
pvs <- allParamValues cnc pt
|
||||||
vvs <- allParamValues cnc vt
|
vvs <- allParamValues cnc vt
|
||||||
return [V pt ts | ts <- combinations (replicate (length pvs) vvs)]
|
return [V pt ts | ts <- sequence (replicate (length pvs) vvs)]
|
||||||
_ -> raise (render ("cannot find parameter values for" <+> ptyp))
|
_ -> raise (render ("cannot find parameter values for" <+> ptyp))
|
||||||
where
|
where
|
||||||
-- to normalize records and record types
|
-- to normalize records and record types
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import Control.Monad (liftM, liftM2, liftM3)
|
|||||||
import Data.List (sortBy,nub)
|
import Data.List (sortBy,nub)
|
||||||
import Data.Monoid
|
import Data.Monoid
|
||||||
import GF.Text.Pretty(render,(<+>),hsep,fsep)
|
import GF.Text.Pretty(render,(<+>),hsep,fsep)
|
||||||
|
import qualified Control.Monad.Fail as Fail
|
||||||
|
|
||||||
-- ** Functions for constructing and analysing source code terms.
|
-- ** Functions for constructing and analysing source code terms.
|
||||||
|
|
||||||
@@ -237,7 +238,7 @@ isPredefConstant t = case t of
|
|||||||
Q (mod,_) | mod == cPredef || mod == cPredefAbs -> True
|
Q (mod,_) | mod == cPredef || mod == cPredefAbs -> True
|
||||||
_ -> False
|
_ -> False
|
||||||
|
|
||||||
checkPredefError :: Monad m => Term -> m Term
|
checkPredefError :: Fail.MonadFail m => Term -> m Term
|
||||||
checkPredefError t =
|
checkPredefError t =
|
||||||
case t of
|
case t of
|
||||||
Error s -> fail ("Error: "++s)
|
Error s -> fail ("Error: "++s)
|
||||||
@@ -554,16 +555,12 @@ strsFromTerm t = case t of
|
|||||||
return [strTok (str2strings def) vars |
|
return [strTok (str2strings def) vars |
|
||||||
def <- d0,
|
def <- d0,
|
||||||
vars <- [[(str2strings v, map sstr c) | (v,c) <- zip vv c0] |
|
vars <- [[(str2strings v, map sstr c) | (v,c) <- zip vv c0] |
|
||||||
vv <- combinations v0]
|
vv <- sequence v0]
|
||||||
]
|
]
|
||||||
FV ts -> mapM strsFromTerm ts >>= return . concat
|
FV ts -> mapM strsFromTerm ts >>= return . concat
|
||||||
Strs ts -> mapM strsFromTerm ts >>= return . concat
|
Strs ts -> mapM strsFromTerm ts >>= return . concat
|
||||||
_ -> raise (render ("cannot get Str from term" <+> ppTerm Unqualified 0 t))
|
_ -> raise (render ("cannot get Str from term" <+> ppTerm Unqualified 0 t))
|
||||||
|
|
||||||
-- | to print an Str-denoting term as a string; if the term is of wrong type, the error msg
|
|
||||||
stringFromTerm :: Term -> String
|
|
||||||
stringFromTerm = err id (ifNull "" (sstr . head)) . strsFromTerm
|
|
||||||
|
|
||||||
getTableType :: TInfo -> Err Type
|
getTableType :: TInfo -> Err Type
|
||||||
getTableType i = case i of
|
getTableType i = case i of
|
||||||
TTyped ty -> return ty
|
TTyped ty -> return ty
|
||||||
@@ -593,7 +590,7 @@ noExist = FV []
|
|||||||
defaultLinType :: Type
|
defaultLinType :: Type
|
||||||
defaultLinType = mkRecType linLabel [typeStr]
|
defaultLinType = mkRecType linLabel [typeStr]
|
||||||
|
|
||||||
-- normalize records and record types; put s first
|
-- | normalize records and record types; put s first
|
||||||
|
|
||||||
sortRec :: [(Label,a)] -> [(Label,a)]
|
sortRec :: [(Label,a)] -> [(Label,a)]
|
||||||
sortRec = sortBy ordLabel where
|
sortRec = sortBy ordLabel where
|
||||||
|
|||||||
@@ -12,7 +12,8 @@
|
|||||||
-- 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 (
|
||||||
|
matchPattern,
|
||||||
testOvershadow,
|
testOvershadow,
|
||||||
findMatch,
|
findMatch,
|
||||||
measurePatt
|
measurePatt
|
||||||
@@ -73,14 +74,13 @@ tryMatch (p,t) = do
|
|||||||
t' <- termForm t
|
t' <- termForm t
|
||||||
trym p t'
|
trym p t'
|
||||||
where
|
where
|
||||||
|
|
||||||
isInConstantFormt = True -- tested already in matchPattern
|
|
||||||
trym p t' =
|
trym p t' =
|
||||||
case (p,t') of
|
case (p,t') of
|
||||||
-- (_,(x,Typed e ty,y)) -> trym p (x,e,y) -- Add this? /TH 2013-09-05
|
-- (_,(x,Typed e ty,y)) -> trym p (x,e,y) -- Add this? /TH 2013-09-05
|
||||||
(_,(x,Empty,y)) -> trym p (x,K [],y) -- because "" = [""] = []
|
(_,(x,Empty,y)) -> trym p (x,K [],y) -- because "" = [""] = []
|
||||||
(PW, _) | isInConstantFormt -> return [] -- optimization with wildcard
|
(PW, _) -> return [] -- optimization with wildcard
|
||||||
(PV x, _) | isInConstantFormt -> return [(x,t)]
|
(PV x,([],K s,[])) -> return [(x,words2term (words s))]
|
||||||
|
(PV x, _) -> return [(x,t)]
|
||||||
(PString s, ([],K i,[])) | s==i -> return []
|
(PString s, ([],K i,[])) | s==i -> return []
|
||||||
(PInt s, ([],EInt i,[])) | s==i -> return []
|
(PInt s, ([],EInt i,[])) | s==i -> return []
|
||||||
(PFloat s,([],EFloat i,[])) | s==i -> return [] --- rounding?
|
(PFloat s,([],EFloat i,[])) | s==i -> return [] --- rounding?
|
||||||
@@ -108,6 +108,10 @@ tryMatch (p,t) = do
|
|||||||
return (concat matches)
|
return (concat matches)
|
||||||
(PT _ p',_) -> trym p' t'
|
(PT _ p',_) -> trym p' t'
|
||||||
|
|
||||||
|
(PAs x p',([],K s,[])) -> do
|
||||||
|
subst <- trym p' t'
|
||||||
|
return $ (x,words2term (words s)) : subst
|
||||||
|
|
||||||
(PAs x p',_) -> do
|
(PAs x p',_) -> do
|
||||||
subst <- trym p' t'
|
subst <- trym p' t'
|
||||||
return $ (x,t) : subst
|
return $ (x,t) : subst
|
||||||
@@ -132,6 +136,11 @@ tryMatch (p,t) = do
|
|||||||
|
|
||||||
_ -> raise (render ("no match in case expr for" <+> t))
|
_ -> raise (render ("no match in case expr for" <+> t))
|
||||||
|
|
||||||
|
words2term [] = Empty
|
||||||
|
words2term [w] = K w
|
||||||
|
words2term (w:ws) = C (K w) (words2term ws)
|
||||||
|
|
||||||
|
|
||||||
matchPMSeq (m1,p1) (m2,p2) s = matchPSeq' m1 p1 m2 p2 s
|
matchPMSeq (m1,p1) (m2,p2) s = matchPSeq' m1 p1 m2 p2 s
|
||||||
--matchPSeq p1 p2 s = matchPSeq' (0,maxBound::Int) p1 (0,maxBound::Int) p2 s
|
--matchPSeq p1 p2 s = matchPSeq' (0,maxBound::Int) p1 (0,maxBound::Int) p2 s
|
||||||
matchPSeq p1 p2 s = matchPSeq' (lengthBounds p1) p1 (lengthBounds p2) p2 s
|
matchPSeq p1 p2 s = matchPSeq' (lengthBounds p1) p1 (lengthBounds p2) p2 s
|
||||||
|
|||||||
@@ -362,4 +362,3 @@ getLet :: Term -> ([LocalDef], Term)
|
|||||||
getLet (Let l e) = let (ls,e') = getLet e
|
getLet (Let l e) = let (ls,e') = getLet e
|
||||||
in (l:ls,e')
|
in (l:ls,e')
|
||||||
getLet e = ([],e)
|
getLet e = ([],e)
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,8 @@
|
|||||||
-- (Description of the module)
|
-- (Description of the module)
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
|
|
||||||
module GF.Grammar.Values (-- ** Values used in TC type checking
|
module GF.Grammar.Values (
|
||||||
|
-- ** Values used in TC type checking
|
||||||
Val(..), Env,
|
Val(..), Env,
|
||||||
-- ** Annotated tree used in editing
|
-- ** Annotated tree used in editing
|
||||||
Binds, Constraints, MetaSubst,
|
Binds, Constraints, MetaSubst,
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import System.FilePath(makeRelative)
|
|||||||
import Control.Parallel.Strategies(parList,rseq,using)
|
import Control.Parallel.Strategies(parList,rseq,using)
|
||||||
import Control.Monad(liftM,ap)
|
import Control.Monad(liftM,ap)
|
||||||
import Control.Applicative(Applicative(..))
|
import Control.Applicative(Applicative(..))
|
||||||
|
import qualified Control.Monad.Fail as Fail
|
||||||
|
|
||||||
type Message = Doc
|
type Message = Doc
|
||||||
type Error = Message
|
type Error = Message
|
||||||
@@ -53,6 +54,9 @@ instance Monad Check where
|
|||||||
(ws,Success x) -> unCheck (g x) {-ctxt-} ws
|
(ws,Success x) -> unCheck (g x) {-ctxt-} ws
|
||||||
(ws,Fail msg) -> (ws,Fail msg)
|
(ws,Fail msg) -> (ws,Fail msg)
|
||||||
|
|
||||||
|
instance Fail.MonadFail Check where
|
||||||
|
fail = raise
|
||||||
|
|
||||||
instance Applicative Check where
|
instance Applicative Check where
|
||||||
pure = return
|
pure = return
|
||||||
(<*>) = ap
|
(<*>) = ap
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ module GF.Infra.Ident (-- ** Identifiers
|
|||||||
-- *** Raw identifiers
|
-- *** Raw identifiers
|
||||||
RawIdent, rawIdentS, rawIdentC, ident2raw, prefixRawIdent,
|
RawIdent, rawIdentS, rawIdentC, ident2raw, prefixRawIdent,
|
||||||
isPrefixOf, showRawIdent
|
isPrefixOf, showRawIdent
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import qualified Data.ByteString.UTF8 as UTF8
|
import qualified Data.ByteString.UTF8 as UTF8
|
||||||
import qualified Data.ByteString.Char8 as BS(append,isPrefixOf)
|
import qualified Data.ByteString.Char8 as BS(append,isPrefixOf)
|
||||||
@@ -77,7 +77,6 @@ instance Binary RawIdent where
|
|||||||
put = put . rawId2utf8
|
put = put . rawId2utf8
|
||||||
get = fmap rawIdentC get
|
get = fmap rawIdentC get
|
||||||
|
|
||||||
|
|
||||||
-- | This function should be used with care, since the returned ByteString is
|
-- | This function should be used with care, since the returned ByteString is
|
||||||
-- UTF-8-encoded.
|
-- UTF-8-encoded.
|
||||||
ident2utf8 :: Ident -> UTF8.ByteString
|
ident2utf8 :: Ident -> UTF8.ByteString
|
||||||
@@ -88,6 +87,7 @@ ident2utf8 i = case i of
|
|||||||
IAV (Id s) b j -> BS.append s (pack ('_':show b ++ '_':show j))
|
IAV (Id s) b j -> BS.append s (pack ('_':show b ++ '_':show j))
|
||||||
IW -> pack "_"
|
IW -> pack "_"
|
||||||
|
|
||||||
|
ident2raw :: Ident -> RawIdent
|
||||||
ident2raw = Id . ident2utf8
|
ident2raw = Id . ident2utf8
|
||||||
|
|
||||||
showIdent :: Ident -> String
|
showIdent :: Ident -> String
|
||||||
@@ -95,13 +95,14 @@ showIdent i = unpack $! ident2utf8 i
|
|||||||
|
|
||||||
instance Pretty Ident where pp = pp . showIdent
|
instance Pretty Ident where pp = pp . showIdent
|
||||||
|
|
||||||
|
instance Pretty RawIdent where pp = pp . showRawIdent
|
||||||
|
|
||||||
identS :: String -> Ident
|
identS :: String -> Ident
|
||||||
identS = identC . rawIdentS
|
identS = identC . rawIdentS
|
||||||
|
|
||||||
identC :: RawIdent -> Ident
|
identC :: RawIdent -> Ident
|
||||||
identW :: Ident
|
identW :: Ident
|
||||||
|
|
||||||
|
|
||||||
prefixIdent :: String -> Ident -> Ident
|
prefixIdent :: String -> Ident -> Ident
|
||||||
prefixIdent pref = identC . Id . BS.append (pack pref) . ident2utf8
|
prefixIdent pref = identC . Id . BS.append (pack pref) . ident2utf8
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ import Data.Set (Set)
|
|||||||
import qualified Data.Set as Set
|
import qualified Data.Set as Set
|
||||||
|
|
||||||
import PGF.Internal(Literal(..))
|
import PGF.Internal(Literal(..))
|
||||||
|
import qualified Control.Monad.Fail as Fail
|
||||||
|
|
||||||
usageHeader :: String
|
usageHeader :: String
|
||||||
usageHeader = unlines
|
usageHeader = unlines
|
||||||
@@ -130,8 +131,13 @@ data CFGTransform = CFGNoLR
|
|||||||
| CFGRemoveCycles
|
| CFGRemoveCycles
|
||||||
deriving (Show,Eq,Ord)
|
deriving (Show,Eq,Ord)
|
||||||
|
|
||||||
data HaskellOption = HaskellNoPrefix | HaskellGADT | HaskellLexical
|
data HaskellOption = HaskellNoPrefix
|
||||||
| HaskellConcrete | HaskellVariants
|
| HaskellGADT
|
||||||
|
| HaskellLexical
|
||||||
|
| HaskellConcrete
|
||||||
|
| HaskellVariants
|
||||||
|
| HaskellData
|
||||||
|
| HaskellPGF2
|
||||||
deriving (Show,Eq,Ord)
|
deriving (Show,Eq,Ord)
|
||||||
|
|
||||||
data Warning = WarnMissingLincat
|
data Warning = WarnMissingLincat
|
||||||
@@ -348,7 +354,7 @@ optDescr =
|
|||||||
"Overrides the value of GF_LIB_PATH.",
|
"Overrides the value of GF_LIB_PATH.",
|
||||||
Option [] ["src","force-recomp"] (NoArg (recomp AlwaysRecomp))
|
Option [] ["src","force-recomp"] (NoArg (recomp AlwaysRecomp))
|
||||||
"Always recompile from source.",
|
"Always recompile from source.",
|
||||||
Option [] ["gfo","recomp-if-newer"] (NoArg (recomp RecompIfNewer))
|
Option [] ["recomp-if-newer"] (NoArg (recomp RecompIfNewer))
|
||||||
"(default) Recompile from source if the source is newer than the .gfo file.",
|
"(default) Recompile from source if the source is newer than the .gfo file.",
|
||||||
Option [] ["gfo","no-recomp"] (NoArg (recomp NeverRecomp))
|
Option [] ["gfo","no-recomp"] (NoArg (recomp NeverRecomp))
|
||||||
"Never recompile from source, if there is already .gfo file.",
|
"Never recompile from source, if there is already .gfo file.",
|
||||||
@@ -530,7 +536,9 @@ haskellOptionNames =
|
|||||||
("gadt", HaskellGADT),
|
("gadt", HaskellGADT),
|
||||||
("lexical", HaskellLexical),
|
("lexical", HaskellLexical),
|
||||||
("concrete", HaskellConcrete),
|
("concrete", HaskellConcrete),
|
||||||
("variants", HaskellVariants)]
|
("variants", HaskellVariants),
|
||||||
|
("data", HaskellData),
|
||||||
|
("pgf2", HaskellPGF2)]
|
||||||
|
|
||||||
-- | This is for bacward compatibility. Since GHC 6.12 we
|
-- | This is for bacward compatibility. Since GHC 6.12 we
|
||||||
-- started using the native Unicode support in GHC but it
|
-- started using the native Unicode support in GHC but it
|
||||||
@@ -547,7 +555,7 @@ lookupShow xs z = fromMaybe "lookupShow" $ lookup z [(y,x) | (x,y) <- xs]
|
|||||||
lookupReadsPrec :: [(String,a)] -> Int -> ReadS a
|
lookupReadsPrec :: [(String,a)] -> Int -> ReadS a
|
||||||
lookupReadsPrec xs _ s = [(z,rest) | (x,rest) <- lex s, (y,z) <- xs, y == x]
|
lookupReadsPrec xs _ s = [(z,rest) | (x,rest) <- lex s, (y,z) <- xs, y == x]
|
||||||
|
|
||||||
onOff :: Monad m => (Bool -> m a) -> Bool -> ArgDescr (m a)
|
onOff :: Fail.MonadFail m => (Bool -> m a) -> Bool -> ArgDescr (m a)
|
||||||
onOff f def = OptArg g "[on,off]"
|
onOff f def = OptArg g "[on,off]"
|
||||||
where g ma = maybe (return def) readOnOff ma >>= f
|
where g ma = maybe (return def) readOnOff ma >>= f
|
||||||
readOnOff x = case map toLower x of
|
readOnOff x = case map toLower x of
|
||||||
@@ -555,7 +563,7 @@ onOff f def = OptArg g "[on,off]"
|
|||||||
"off" -> return False
|
"off" -> return False
|
||||||
_ -> fail $ "Expected [on,off], got: " ++ show x
|
_ -> fail $ "Expected [on,off], got: " ++ show x
|
||||||
|
|
||||||
readOutputFormat :: Monad m => String -> m OutputFormat
|
readOutputFormat :: Fail.MonadFail m => String -> m OutputFormat
|
||||||
readOutputFormat s =
|
readOutputFormat s =
|
||||||
maybe (fail $ "Unknown output format: " ++ show s) return $ lookup s outputFormats
|
maybe (fail $ "Unknown output format: " ++ show s) return $ lookup s outputFormats
|
||||||
|
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ import qualified GF.Command.Importing as GF(importGrammar, importSource)
|
|||||||
#ifdef C_RUNTIME
|
#ifdef C_RUNTIME
|
||||||
import qualified PGF2
|
import qualified PGF2
|
||||||
#endif
|
#endif
|
||||||
|
import qualified Control.Monad.Fail as Fail
|
||||||
|
|
||||||
-- * The SIO monad
|
-- * The SIO monad
|
||||||
|
|
||||||
@@ -58,6 +59,9 @@ instance Monad SIO where
|
|||||||
return x = SIO (const (return x))
|
return x = SIO (const (return x))
|
||||||
SIO m1 >>= xm2 = SIO $ \ h -> m1 h >>= \ x -> unS (xm2 x) h
|
SIO m1 >>= xm2 = SIO $ \ h -> m1 h >>= \ x -> unS (xm2 x) h
|
||||||
|
|
||||||
|
instance Fail.MonadFail SIO where
|
||||||
|
fail = lift0 . fail
|
||||||
|
|
||||||
instance Output SIO where
|
instance Output SIO where
|
||||||
ePutStr = lift0 . ePutStr
|
ePutStr = lift0 . ePutStr
|
||||||
ePutStrLn = lift0 . ePutStrLn
|
ePutStrLn = lift0 . ePutStrLn
|
||||||
|
|||||||
@@ -159,6 +159,9 @@ instance ErrorMonad IO where
|
|||||||
then h (ioeGetErrorString e)
|
then h (ioeGetErrorString e)
|
||||||
else ioError e
|
else ioError e
|
||||||
{-
|
{-
|
||||||
|
-- Control.Monad.Fail import will become redundant in GHC 8.8+
|
||||||
|
import qualified Control.Monad.Fail as Fail
|
||||||
|
|
||||||
instance Functor IOE where fmap = liftM
|
instance Functor IOE where fmap = liftM
|
||||||
|
|
||||||
instance Applicative IOE where
|
instance Applicative IOE where
|
||||||
@@ -170,7 +173,15 @@ instance Monad IOE where
|
|||||||
IOE c >>= f = IOE $ do
|
IOE c >>= f = IOE $ do
|
||||||
x <- c -- Err a
|
x <- c -- Err a
|
||||||
appIOE $ err raise f x -- f :: a -> IOE a
|
appIOE $ err raise f x -- f :: a -> IOE a
|
||||||
|
|
||||||
|
#if !(MIN_VERSION_base(4,13,0))
|
||||||
fail = raise
|
fail = raise
|
||||||
|
#endif
|
||||||
|
|
||||||
|
instance Fail.MonadFail IOE where
|
||||||
|
fail = raise
|
||||||
|
|
||||||
|
|
||||||
-}
|
-}
|
||||||
|
|
||||||
-- | Print the error message and return a default value if the IO operation 'fail's
|
-- | Print the error message and return a default value if the IO operation 'fail's
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import GF.Command.CommandInfo
|
|||||||
import GF.Command.Help(helpCommand)
|
import GF.Command.Help(helpCommand)
|
||||||
import GF.Command.Abstract
|
import GF.Command.Abstract
|
||||||
import GF.Command.Parse(readCommandLine,pCommand)
|
import GF.Command.Parse(readCommandLine,pCommand)
|
||||||
import GF.Data.Operations (Err(..),done)
|
import GF.Data.Operations (Err(..))
|
||||||
import GF.Data.Utilities(whenM,repeatM)
|
import GF.Data.Utilities(whenM,repeatM)
|
||||||
import GF.Grammar hiding (Ident,isPrefixOf)
|
import GF.Grammar hiding (Ident,isPrefixOf)
|
||||||
import GF.Infra.UseIO(ioErrorText,putStrLnE)
|
import GF.Infra.UseIO(ioErrorText,putStrLnE)
|
||||||
@@ -38,6 +38,8 @@ import GF.Server(server)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
import GF.Command.Messages(welcome)
|
import GF.Command.Messages(welcome)
|
||||||
|
-- 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 ()
|
||||||
@@ -53,6 +55,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
|
||||||
@@ -162,7 +165,7 @@ execute1' s0 =
|
|||||||
do execute . lines =<< lift (restricted (readFile w))
|
do execute . lines =<< lift (restricted (readFile w))
|
||||||
continue
|
continue
|
||||||
where
|
where
|
||||||
execute [] = done
|
execute [] = return ()
|
||||||
execute (line:lines) = whenM (execute1' line) (execute lines)
|
execute (line:lines) = whenM (execute1' line) (execute lines)
|
||||||
|
|
||||||
execute_history _ =
|
execute_history _ =
|
||||||
@@ -288,7 +291,7 @@ importInEnv opts files =
|
|||||||
if (verbAtLeast opts Normal)
|
if (verbAtLeast opts Normal)
|
||||||
then putStrLnFlush $
|
then putStrLnFlush $
|
||||||
unwords $ "\nLanguages:" : map showCId (languages pgf1)
|
unwords $ "\nLanguages:" : map showCId (languages pgf1)
|
||||||
else done
|
else return ()
|
||||||
return pgf1
|
return pgf1
|
||||||
|
|
||||||
tryGetLine = do
|
tryGetLine = do
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import GF.Command.CommandInfo
|
|||||||
import GF.Command.Help(helpCommand)
|
import GF.Command.Help(helpCommand)
|
||||||
import GF.Command.Abstract
|
import GF.Command.Abstract
|
||||||
import GF.Command.Parse(readCommandLine,pCommand)
|
import GF.Command.Parse(readCommandLine,pCommand)
|
||||||
import GF.Data.Operations (Err(..),done)
|
import GF.Data.Operations (Err(..))
|
||||||
import GF.Data.Utilities(whenM,repeatM)
|
import GF.Data.Utilities(whenM,repeatM)
|
||||||
|
|
||||||
import GF.Infra.UseIO(ioErrorText,putStrLnE)
|
import GF.Infra.UseIO(ioErrorText,putStrLnE)
|
||||||
@@ -58,6 +58,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
|
||||||
|
|
||||||
{-
|
{-
|
||||||
@@ -164,7 +165,7 @@ execute1' s0 =
|
|||||||
continue
|
continue
|
||||||
where
|
where
|
||||||
execute :: [String] -> ShellM ()
|
execute :: [String] -> ShellM ()
|
||||||
execute [] = done
|
execute [] = return ()
|
||||||
execute (line:lines) = whenM (execute1' line) (execute lines)
|
execute (line:lines) = whenM (execute1' line) (execute lines)
|
||||||
|
|
||||||
execute_history _ =
|
execute_history _ =
|
||||||
@@ -279,14 +280,14 @@ importInEnv opts files =
|
|||||||
_ | flag optRetainResource opts ->
|
_ | flag optRetainResource opts ->
|
||||||
putStrLnE "Flag -retain is not supported in this shell"
|
putStrLnE "Flag -retain is not supported in this shell"
|
||||||
[file] | takeExtensions file == ".pgf" -> importPGF file
|
[file] | takeExtensions file == ".pgf" -> importPGF file
|
||||||
[] -> done
|
[] -> return ()
|
||||||
_ -> do putStrLnE "Can only import one .pgf file"
|
_ -> do putStrLnE "Can only import one .pgf file"
|
||||||
where
|
where
|
||||||
importPGF file =
|
importPGF file =
|
||||||
do gfenv <- get
|
do gfenv <- get
|
||||||
case multigrammar gfenv of
|
case multigrammar gfenv of
|
||||||
Just _ -> putStrLnE "Discarding previous grammar"
|
Just _ -> putStrLnE "Discarding previous grammar"
|
||||||
_ -> done
|
_ -> return ()
|
||||||
pgf1 <- lift $ readPGF2 file
|
pgf1 <- lift $ readPGF2 file
|
||||||
let gfenv' = gfenv { pgfenv = pgfEnv pgf1 }
|
let gfenv' = gfenv { pgfenv = pgfEnv pgf1 }
|
||||||
when (verbAtLeast opts Normal) $
|
when (verbAtLeast opts Normal) $
|
||||||
|
|||||||
@@ -16,18 +16,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
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import qualified Data.Map as M
|
|||||||
import Control.Applicative -- for GHC<7.10
|
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.Error(ErrorT(..),Error(..))
|
import Control.Monad.Except(ExceptT(..),runExceptT)
|
||||||
import System.Random(randomRIO)
|
import System.Random(randomRIO)
|
||||||
--import System.IO(stderr,hPutStrLn)
|
--import System.IO(stderr,hPutStrLn)
|
||||||
import GF.System.Catch(try)
|
import GF.System.Catch(try)
|
||||||
@@ -108,9 +108,9 @@ handle_fcgi execute1 state0 stateM cache =
|
|||||||
|
|
||||||
-- * Request handler
|
-- * Request handler
|
||||||
-- | Handler monad
|
-- | Handler monad
|
||||||
type HM s a = StateT (Q,s) (ErrorT Response IO) a
|
type HM s a = StateT (Q,s) (ExceptT Response IO) a
|
||||||
run :: HM s Response -> (Q,s) -> IO (s,Response)
|
run :: HM s Response -> (Q,s) -> IO (s,Response)
|
||||||
run m s = either bad ok =<< runErrorT (runStateT m s)
|
run m s = either bad ok =<< runExceptT (runStateT m s)
|
||||||
where
|
where
|
||||||
bad resp = return (snd s,resp)
|
bad resp = return (snd s,resp)
|
||||||
ok (resp,(qs,state)) = return (state,resp)
|
ok (resp,(qs,state)) = return (state,resp)
|
||||||
@@ -123,12 +123,12 @@ put_qs qs = do state <- get_state; put (qs,state)
|
|||||||
put_state state = do qs <- get_qs; put (qs,state)
|
put_state state = do qs <- get_qs; put (qs,state)
|
||||||
|
|
||||||
err :: Response -> HM s a
|
err :: Response -> HM s a
|
||||||
err e = StateT $ \ s -> ErrorT $ return $ Left e
|
err e = StateT $ \ s -> ExceptT $ return $ Left e
|
||||||
|
|
||||||
hmbracket_ :: IO () -> IO () -> HM s a -> HM s a
|
hmbracket_ :: IO () -> IO () -> HM s a -> HM s a
|
||||||
hmbracket_ pre post m =
|
hmbracket_ pre post m =
|
||||||
do s <- get
|
do s <- get
|
||||||
e <- liftIO $ bracket_ pre post $ runErrorT $ runStateT m s
|
e <- liftIO $ bracket_ pre post $ runExceptT $ runStateT m s
|
||||||
case e of
|
case e of
|
||||||
Left resp -> err resp
|
Left resp -> err resp
|
||||||
Right (a,s) -> do put s;return a
|
Right (a,s) -> do put s;return a
|
||||||
@@ -407,9 +407,6 @@ resp404 path = Response 404 [plain,xo] $ "Not found: "++path++"\n"
|
|||||||
resp500 msg = Response 500 [plain,xo] $ "Internal error: "++msg++"\n"
|
resp500 msg = Response 500 [plain,xo] $ "Internal error: "++msg++"\n"
|
||||||
resp501 msg = Response 501 [plain,xo] $ "Not implemented: "++msg++"\n"
|
resp501 msg = Response 501 [plain,xo] $ "Not implemented: "++msg++"\n"
|
||||||
|
|
||||||
instance Error Response where
|
|
||||||
noMsg = resp500 "no message"
|
|
||||||
strMsg = resp500
|
|
||||||
|
|
||||||
-- * Content types
|
-- * Content types
|
||||||
plain = ct "text/plain" ""
|
plain = ct "text/plain" ""
|
||||||
|
|||||||
@@ -110,4 +110,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
|
||||||
|
|
||||||
|
|||||||
@@ -125,4 +125,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
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
-- | Lexers and unlexers - they work on space-separated word strings
|
-- | Lexers and unlexers - they work on space-separated word strings
|
||||||
module GF.Text.Lexing (stringOp,opInEnv) where
|
module GF.Text.Lexing (stringOp,opInEnv,bindTok) where
|
||||||
|
|
||||||
import GF.Text.Transliterations
|
import GF.Text.Transliterations
|
||||||
|
|
||||||
|
|||||||
@@ -300,9 +300,7 @@ 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* 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* m. m- m' m( m) m m? m* "++
|
||||||
" s. s- s' s( s) s s? s* r. r- r' r( r) r r? r* "++
|
" s. s- s' s( s) s s? s* r. r- r' r( r) r r? r* "++
|
||||||
@@ -325,7 +323,7 @@ allTrans = words $
|
|||||||
" P. P- P' P( P) P P? P* S. S- S' S( S) S S? S* "++
|
" P. P- P' P( P) P P? P* S. S- S' S( S) S S? S* "++
|
||||||
" - - - - - - - - f. f- f' f( f) f f? f*"++
|
" - - - - - - - - f. f- f' f( f) f f? f*"++
|
||||||
" p. p- p' p( p) p p? p*"
|
" p. p- p' p( p) p p? p*"
|
||||||
allCodes = [0x1200..0x1357]
|
allCodes = [0x1200..0x1357]
|
||||||
|
|
||||||
-- by Prasad 31/5/2013
|
-- by Prasad 31/5/2013
|
||||||
transSanskrit :: Transliteration
|
transSanskrit :: Transliteration
|
||||||
|
|||||||
@@ -9,14 +9,24 @@ instance JSON Grammar where
|
|||||||
showJSON (Grammar name extends abstract concretes) =
|
showJSON (Grammar name extends abstract concretes) =
|
||||||
makeObj ["basename".=name, "extends".=extends,
|
makeObj ["basename".=name, "extends".=extends,
|
||||||
"abstract".=abstract, "concretes".=concretes]
|
"abstract".=abstract, "concretes".=concretes]
|
||||||
|
readJSON = error "Grammar.readJSON intentionally not defined"
|
||||||
|
|
||||||
instance JSON Abstract where
|
instance JSON Abstract where
|
||||||
showJSON (Abstract startcat cats funs) =
|
showJSON (Abstract startcat cats funs) =
|
||||||
makeObj ["startcat".=startcat, "cats".=cats, "funs".=funs]
|
makeObj ["startcat".=startcat, "cats".=cats, "funs".=funs]
|
||||||
|
readJSON = error "Abstract.readJSON intentionally not defined"
|
||||||
|
|
||||||
instance JSON Fun where showJSON (Fun name typ) = signature name typ
|
instance JSON Fun where
|
||||||
instance JSON Param where showJSON (Param name rhs) = definition name rhs
|
showJSON (Fun name typ) = signature name typ
|
||||||
instance JSON Oper where showJSON (Oper name rhs) = definition name rhs
|
readJSON = error "Fun.readJSON intentionally not defined"
|
||||||
|
|
||||||
|
instance JSON Param where
|
||||||
|
showJSON (Param name rhs) = definition name rhs
|
||||||
|
readJSON = error "Param.readJSON intentionally not defined"
|
||||||
|
|
||||||
|
instance JSON Oper where
|
||||||
|
showJSON (Oper name rhs) = definition name rhs
|
||||||
|
readJSON = error "Oper.readJSON intentionally not defined"
|
||||||
|
|
||||||
signature name typ = makeObj ["name".=name,"type".=typ]
|
signature name typ = makeObj ["name".=name,"type".=typ]
|
||||||
definition name rhs = makeObj ["name".=name,"rhs".=rhs]
|
definition name rhs = makeObj ["name".=name,"rhs".=rhs]
|
||||||
@@ -26,12 +36,15 @@ instance JSON Concrete where
|
|||||||
makeObj ["langcode".=langcode, "opens".=opens,
|
makeObj ["langcode".=langcode, "opens".=opens,
|
||||||
"params".=params, "opers".=opers,
|
"params".=params, "opers".=opers,
|
||||||
"lincats".=lincats, "lins".=lins]
|
"lincats".=lincats, "lins".=lins]
|
||||||
|
readJSON = error "Concrete.readJSON intentionally not defined"
|
||||||
|
|
||||||
instance JSON Lincat where
|
instance JSON Lincat where
|
||||||
showJSON (Lincat cat lintype) = makeObj ["cat".=cat, "type".=lintype]
|
showJSON (Lincat cat lintype) = makeObj ["cat".=cat, "type".=lintype]
|
||||||
|
readJSON = error "Lincat.readJSON intentionally not defined"
|
||||||
|
|
||||||
instance JSON Lin where
|
instance JSON Lin where
|
||||||
showJSON (Lin fun args lin) = makeObj ["fun".=fun, "args".=args, "lin".=lin]
|
showJSON (Lin fun args lin) = makeObj ["fun".=fun, "args".=args, "lin".=lin]
|
||||||
|
readJSON = error "Lin.readJSON intentionally not defined"
|
||||||
|
|
||||||
infix 1 .=
|
infix 1 .=
|
||||||
name .= v = (name,showJSON v)
|
name .= v = (name,showJSON v)
|
||||||
|
|||||||
@@ -14,6 +14,9 @@ For Linux users
|
|||||||
|
|
||||||
You will need the packages: autoconf, automake, libtool, make
|
You will need the packages: autoconf, automake, libtool, make
|
||||||
|
|
||||||
|
- On Ubuntu: $ apt-get install autotools-dev
|
||||||
|
- On Fedora: $ dnf install autoconf automake libtool
|
||||||
|
|
||||||
The compilation steps are:
|
The compilation steps are:
|
||||||
|
|
||||||
$ autoreconf -i
|
$ autoreconf -i
|
||||||
@@ -28,7 +31,7 @@ For Mac OSX users
|
|||||||
The following is what I did to make it work on MacOSX 10.8:
|
The following is what I did to make it work on MacOSX 10.8:
|
||||||
|
|
||||||
- Install XCode and XCode command line tools
|
- Install XCode and XCode command line tools
|
||||||
- Install Homebrew: http://mxcl.github.com/homebrew/
|
- Install Homebrew: https://brew.sh
|
||||||
|
|
||||||
$ brew install automake autoconf libtool
|
$ brew install automake autoconf libtool
|
||||||
$ glibtoolize
|
$ glibtoolize
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
lib_LTLIBRARIES = libgu.la libpgf.la libsg.la
|
lib_LTLIBRARIES = libgu.la libpgf.la
|
||||||
|
|
||||||
pkgconfigdir = $(libdir)/pkgconfig
|
pkgconfigdir = $(libdir)/pkgconfig
|
||||||
pkgconfig_DATA = libgu.pc libpgf.pc libsg.pc
|
pkgconfig_DATA = libgu.pc libpgf.pc
|
||||||
|
|
||||||
configincludedir = $(libdir)/libgu/include
|
configincludedir = $(libdir)/libgu/include
|
||||||
|
|
||||||
@@ -37,10 +37,6 @@ pgfinclude_HEADERS = \
|
|||||||
pgf/pgf.h \
|
pgf/pgf.h \
|
||||||
pgf/data.h
|
pgf/data.h
|
||||||
|
|
||||||
sgincludedir=$(includedir)/sg
|
|
||||||
sginclude_HEADERS = \
|
|
||||||
sg/sg.h
|
|
||||||
|
|
||||||
libgu_la_SOURCES = \
|
libgu_la_SOURCES = \
|
||||||
gu/assert.c \
|
gu/assert.c \
|
||||||
gu/bits.c \
|
gu/bits.c \
|
||||||
@@ -92,12 +88,6 @@ libpgf_la_SOURCES = \
|
|||||||
libpgf_la_LDFLAGS = -no-undefined
|
libpgf_la_LDFLAGS = -no-undefined
|
||||||
libpgf_la_LIBADD = libgu.la
|
libpgf_la_LIBADD = libgu.la
|
||||||
|
|
||||||
libsg_la_SOURCES = \
|
|
||||||
sg/sqlite3Btree.c \
|
|
||||||
sg/sg.c
|
|
||||||
libsg_la_LDFLAGS = -no-undefined
|
|
||||||
libsg_la_LIBADD = libgu.la libpgf.la
|
|
||||||
|
|
||||||
bin_PROGRAMS =
|
bin_PROGRAMS =
|
||||||
|
|
||||||
AUTOMAKE_OPTIONS = foreign subdir-objects dist-bzip2
|
AUTOMAKE_OPTIONS = foreign subdir-objects dist-bzip2
|
||||||
@@ -105,5 +95,4 @@ ACLOCAL_AMFLAGS = -I m4
|
|||||||
|
|
||||||
EXTRA_DIST = \
|
EXTRA_DIST = \
|
||||||
libgu.pc.in \
|
libgu.pc.in \
|
||||||
libpgf.pc.in \
|
libpgf.pc.in
|
||||||
libsg.pc.in
|
|
||||||
|
|||||||
@@ -58,7 +58,6 @@ AC_CONFIG_LINKS(pgf/lightning/asm.h:$cpu_dir/asm.h dnl
|
|||||||
AC_CONFIG_FILES([Makefile
|
AC_CONFIG_FILES([Makefile
|
||||||
libgu.pc
|
libgu.pc
|
||||||
libpgf.pc
|
libpgf.pc
|
||||||
libsg.pc
|
|
||||||
])
|
])
|
||||||
|
|
||||||
AC_OUTPUT
|
AC_OUTPUT
|
||||||
|
|||||||
@@ -322,7 +322,7 @@ gu_map_iter(GuMap* map, GuMapItor* itor, GuExn* err)
|
|||||||
}
|
}
|
||||||
|
|
||||||
GU_API bool
|
GU_API bool
|
||||||
gu_map_next(GuMap* map, size_t* pi, void** pkey, void* pvalue)
|
gu_map_next(GuMap* map, size_t* pi, void* pkey, void* pvalue)
|
||||||
{
|
{
|
||||||
while (*pi < map->data.n_entries) {
|
while (*pi < map->data.n_entries) {
|
||||||
if (gu_map_entry_is_free(map, &map->data, *pi)) {
|
if (gu_map_entry_is_free(map, &map->data, *pi)) {
|
||||||
@@ -330,11 +330,14 @@ gu_map_next(GuMap* map, size_t* pi, void** pkey, void* pvalue)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
*pkey = &map->data.keys[*pi * map->key_size];
|
|
||||||
if (map->hasher == gu_addr_hasher) {
|
if (map->hasher == gu_addr_hasher) {
|
||||||
*pkey = *(void**) *pkey;
|
*((void**) pkey) = *((void**) &map->data.keys[*pi * sizeof(void*)]);
|
||||||
|
} else if (map->hasher == gu_word_hasher) {
|
||||||
|
*((GuWord*) pkey) = *((GuWord*) &map->data.keys[*pi * sizeof(GuWord)]);
|
||||||
} else if (map->hasher == gu_string_hasher) {
|
} else if (map->hasher == gu_string_hasher) {
|
||||||
*pkey = *(void**) *pkey;
|
*((GuString*) pkey) = *((GuString*) &map->data.keys[*pi * sizeof(GuString)]);
|
||||||
|
} else {
|
||||||
|
memcpy(pkey, &map->data.keys[*pi * map->key_size], map->key_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(pvalue, &map->data.values[*pi * map->cell_size],
|
memcpy(pvalue, &map->data.values[*pi * map->cell_size],
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ GU_API_DECL void
|
|||||||
gu_map_iter(GuMap* ht, GuMapItor* itor, GuExn* err);
|
gu_map_iter(GuMap* ht, GuMapItor* itor, GuExn* err);
|
||||||
|
|
||||||
GU_API bool
|
GU_API bool
|
||||||
gu_map_next(GuMap* map, size_t* pi, void** pkey, void* pvalue);
|
gu_map_next(GuMap* map, size_t* pi, void* pkey, void* pvalue);
|
||||||
|
|
||||||
typedef GuMap GuIntMap;
|
typedef GuMap GuIntMap;
|
||||||
|
|
||||||
|
|||||||
3
src/runtime/c/install.sh
Executable file
3
src/runtime/c/install.sh
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
bash setup.sh configure
|
||||||
|
bash setup.sh build
|
||||||
|
bash setup.sh install
|
||||||
@@ -142,14 +142,14 @@ pgf_aligner_lzn_symbol_token(PgfLinFuncs** funcs, PgfToken tok)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
pgf_aligner_lzn_begin_phrase(PgfLinFuncs** funcs, PgfCId cat, int fid, size_t lindex, PgfCId fun)
|
pgf_aligner_lzn_begin_phrase(PgfLinFuncs** funcs, PgfCId cat, int fid, GuString ann, PgfCId fun)
|
||||||
{
|
{
|
||||||
PgfAlignerLin* alin = gu_container(funcs, PgfAlignerLin, funcs);
|
PgfAlignerLin* alin = gu_container(funcs, PgfAlignerLin, funcs);
|
||||||
gu_buf_push(alin->parent_stack, int, fid);
|
gu_buf_push(alin->parent_stack, int, fid);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
pgf_aligner_lzn_end_phrase(PgfLinFuncs** funcs, PgfCId cat, int fid, size_t lindex, PgfCId fun)
|
pgf_aligner_lzn_end_phrase(PgfLinFuncs** funcs, PgfCId cat, int fid, GuString ann, PgfCId fun)
|
||||||
{
|
{
|
||||||
PgfAlignerLin* alin = gu_container(funcs, PgfAlignerLin, funcs);
|
PgfAlignerLin* alin = gu_container(funcs, PgfAlignerLin, funcs);
|
||||||
gu_buf_pop(alin->parent_stack, int);
|
gu_buf_pop(alin->parent_stack, int);
|
||||||
|
|||||||
@@ -322,7 +322,8 @@ typedef struct PgfProductionCoerce
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
PgfExprProb *ep;
|
PgfExprProb *ep;
|
||||||
GuSeq* lins;
|
size_t n_lins;
|
||||||
|
PgfSymbols* lins[];
|
||||||
} PgfProductionExtern;
|
} PgfProductionExtern;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|||||||
@@ -918,94 +918,6 @@ pgf_read_expr(GuIn* in, GuPool* pool, GuPool* tmp_pool, GuExn* err)
|
|||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
PGF_API int
|
|
||||||
pgf_read_expr_tuple(GuIn* in,
|
|
||||||
size_t n_exprs, PgfExpr exprs[],
|
|
||||||
GuPool* pool, GuExn* err)
|
|
||||||
{
|
|
||||||
GuPool* tmp_pool = gu_new_pool();
|
|
||||||
PgfExprParser* parser =
|
|
||||||
pgf_new_parser(in, pgf_expr_parser_in_getc, pool, tmp_pool, err);
|
|
||||||
if (parser->token_tag != PGF_TOKEN_LTRIANGLE)
|
|
||||||
goto fail;
|
|
||||||
pgf_expr_parser_token(parser, false);
|
|
||||||
for (size_t i = 0; i < n_exprs; i++) {
|
|
||||||
if (i > 0) {
|
|
||||||
if (parser->token_tag != PGF_TOKEN_COMMA)
|
|
||||||
goto fail;
|
|
||||||
pgf_expr_parser_token(parser, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
exprs[i] = pgf_expr_parser_expr(parser, false);
|
|
||||||
if (gu_variant_is_null(exprs[i]))
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
if (parser->token_tag != PGF_TOKEN_RTRIANGLE)
|
|
||||||
goto fail;
|
|
||||||
pgf_expr_parser_token(parser, false);
|
|
||||||
if (parser->token_tag != PGF_TOKEN_EOF)
|
|
||||||
goto fail;
|
|
||||||
gu_pool_free(tmp_pool);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
fail:
|
|
||||||
gu_pool_free(tmp_pool);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
PGF_API GuSeq*
|
|
||||||
pgf_read_expr_matrix(GuIn* in,
|
|
||||||
size_t n_exprs,
|
|
||||||
GuPool* pool, GuExn* err)
|
|
||||||
{
|
|
||||||
GuPool* tmp_pool = gu_new_pool();
|
|
||||||
PgfExprParser* parser =
|
|
||||||
pgf_new_parser(in, pgf_expr_parser_in_getc, pool, tmp_pool, err);
|
|
||||||
if (parser->token_tag != PGF_TOKEN_LTRIANGLE)
|
|
||||||
goto fail;
|
|
||||||
pgf_expr_parser_token(parser, false);
|
|
||||||
|
|
||||||
GuBuf* buf = gu_new_buf(PgfExpr, pool);
|
|
||||||
|
|
||||||
if (parser->token_tag != PGF_TOKEN_RTRIANGLE) {
|
|
||||||
for (;;) {
|
|
||||||
PgfExpr* exprs = gu_buf_extend_n(buf, n_exprs);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < n_exprs; i++) {
|
|
||||||
if (i > 0) {
|
|
||||||
if (parser->token_tag != PGF_TOKEN_COMMA)
|
|
||||||
goto fail;
|
|
||||||
pgf_expr_parser_token(parser, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
exprs[i] = pgf_expr_parser_expr(parser, false);
|
|
||||||
if (gu_variant_is_null(exprs[i]))
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parser->token_tag != PGF_TOKEN_SEMI)
|
|
||||||
break;
|
|
||||||
|
|
||||||
pgf_expr_parser_token(parser, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parser->token_tag != PGF_TOKEN_RTRIANGLE)
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
pgf_expr_parser_token(parser, false);
|
|
||||||
if (parser->token_tag != PGF_TOKEN_EOF)
|
|
||||||
goto fail;
|
|
||||||
gu_pool_free(tmp_pool);
|
|
||||||
|
|
||||||
return gu_buf_data_seq(buf);
|
|
||||||
|
|
||||||
fail:
|
|
||||||
gu_pool_free(tmp_pool);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
PGF_API PgfType*
|
PGF_API PgfType*
|
||||||
pgf_read_type(GuIn* in, GuPool* pool, GuPool* tmp_pool, GuExn* err)
|
pgf_read_type(GuIn* in, GuPool* pool, GuPool* tmp_pool, GuExn* err)
|
||||||
{
|
{
|
||||||
@@ -1723,19 +1635,6 @@ pgf_print_context(PgfHypos *hypos, PgfPrintContext* ctxt,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PGF_API void
|
|
||||||
pgf_print_expr_tuple(size_t n_exprs, PgfExpr exprs[], PgfPrintContext* ctxt,
|
|
||||||
GuOut* out, GuExn* err)
|
|
||||||
{
|
|
||||||
gu_putc('<', out, err);
|
|
||||||
for (size_t i = 0; i < n_exprs; i++) {
|
|
||||||
if (i > 0)
|
|
||||||
gu_putc(',', out, err);
|
|
||||||
pgf_print_expr(exprs[i], ctxt, 0, out, err);
|
|
||||||
}
|
|
||||||
gu_putc('>', out, err);
|
|
||||||
}
|
|
||||||
|
|
||||||
PGF_API bool
|
PGF_API bool
|
||||||
pgf_type_eq(PgfType* t1, PgfType* t2)
|
pgf_type_eq(PgfType* t1, PgfType* t2)
|
||||||
{
|
{
|
||||||
@@ -1771,6 +1670,168 @@ pgf_type_eq(PgfType* t1, PgfType* t2)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PGF_API PgfLiteral
|
||||||
|
pgf_clone_literal(PgfLiteral lit, GuPool* pool)
|
||||||
|
{
|
||||||
|
PgfLiteral new_lit = gu_null_variant;
|
||||||
|
|
||||||
|
GuVariantInfo inf = gu_variant_open(lit);
|
||||||
|
switch (inf.tag) {
|
||||||
|
case PGF_LITERAL_STR: {
|
||||||
|
PgfLiteralStr* lit_str = inf.data;
|
||||||
|
PgfLiteralStr* new_lit_str =
|
||||||
|
gu_new_flex_variant(PGF_LITERAL_STR,
|
||||||
|
PgfLiteralStr,
|
||||||
|
val, strlen(lit_str->val)+1,
|
||||||
|
&new_lit, pool);
|
||||||
|
strcpy(new_lit_str->val, lit_str->val);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PGF_LITERAL_INT: {
|
||||||
|
PgfLiteralInt *lit_int = inf.data;
|
||||||
|
PgfLiteralInt *new_lit_int =
|
||||||
|
gu_new_variant(PGF_LITERAL_INT,
|
||||||
|
PgfLiteralInt,
|
||||||
|
&new_lit, pool);
|
||||||
|
new_lit_int->val = lit_int->val;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PGF_LITERAL_FLT: {
|
||||||
|
PgfLiteralFlt *lit_flt = inf.data;
|
||||||
|
PgfLiteralFlt *new_lit_flt =
|
||||||
|
gu_new_variant(PGF_LITERAL_FLT,
|
||||||
|
PgfLiteralFlt,
|
||||||
|
&new_lit, pool);
|
||||||
|
new_lit_flt->val = lit_flt->val;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
gu_impossible();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new_lit;
|
||||||
|
}
|
||||||
|
|
||||||
|
PGF_API PgfExpr
|
||||||
|
pgf_clone_expr(PgfExpr expr, GuPool* pool)
|
||||||
|
{
|
||||||
|
PgfExpr new_expr = gu_null_variant;
|
||||||
|
|
||||||
|
GuVariantInfo inf = gu_variant_open(expr);
|
||||||
|
switch (inf.tag) {
|
||||||
|
case PGF_EXPR_ABS: {
|
||||||
|
PgfExprAbs* abs = inf.data;
|
||||||
|
PgfExprAbs* new_abs =
|
||||||
|
gu_new_variant(PGF_EXPR_ABS,
|
||||||
|
PgfExprAbs,
|
||||||
|
&new_expr, pool);
|
||||||
|
|
||||||
|
new_abs->bind_type = abs->bind_type;
|
||||||
|
new_abs->id = gu_string_copy(abs->id, pool);
|
||||||
|
new_abs->body = pgf_clone_expr(abs->body,pool);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PGF_EXPR_APP: {
|
||||||
|
PgfExprApp* app = inf.data;
|
||||||
|
PgfExprApp* new_app =
|
||||||
|
gu_new_variant(PGF_EXPR_APP,
|
||||||
|
PgfExprApp,
|
||||||
|
&new_expr, pool);
|
||||||
|
new_app->fun = pgf_clone_expr(app->fun, pool);
|
||||||
|
new_app->arg = pgf_clone_expr(app->arg, pool);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PGF_EXPR_LIT: {
|
||||||
|
PgfExprLit* lit = inf.data;
|
||||||
|
PgfExprLit* new_lit =
|
||||||
|
gu_new_variant(PGF_EXPR_LIT,
|
||||||
|
PgfExprLit,
|
||||||
|
&new_expr, pool);
|
||||||
|
new_lit->lit = pgf_clone_literal(lit->lit, pool);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PGF_EXPR_META: {
|
||||||
|
PgfExprMeta* meta = inf.data;
|
||||||
|
PgfExprMeta* new_meta =
|
||||||
|
gu_new_variant(PGF_EXPR_META,
|
||||||
|
PgfExprMeta,
|
||||||
|
&new_expr, pool);
|
||||||
|
new_meta->id = meta->id;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PGF_EXPR_FUN: {
|
||||||
|
PgfExprFun* fun = inf.data;
|
||||||
|
PgfExprFun* new_fun =
|
||||||
|
gu_new_flex_variant(PGF_EXPR_FUN,
|
||||||
|
PgfExprFun,
|
||||||
|
fun, strlen(fun->fun)+1,
|
||||||
|
&new_expr, pool);
|
||||||
|
strcpy(new_fun->fun, fun->fun);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PGF_EXPR_VAR: {
|
||||||
|
PgfExprVar* var = inf.data;
|
||||||
|
PgfExprVar* new_var =
|
||||||
|
gu_new_variant(PGF_EXPR_VAR,
|
||||||
|
PgfExprVar,
|
||||||
|
&new_expr, pool);
|
||||||
|
new_var->var = var->var;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PGF_EXPR_TYPED: {
|
||||||
|
PgfExprTyped* typed = inf.data;
|
||||||
|
|
||||||
|
PgfExprTyped *new_typed =
|
||||||
|
gu_new_variant(PGF_EXPR_TYPED,
|
||||||
|
PgfExprTyped,
|
||||||
|
&new_expr, pool);
|
||||||
|
new_typed->expr = pgf_clone_expr(typed->expr, pool);
|
||||||
|
new_typed->type = pgf_clone_type(typed->type, pool);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PGF_EXPR_IMPL_ARG: {
|
||||||
|
PgfExprImplArg* impl = inf.data;
|
||||||
|
PgfExprImplArg *new_impl =
|
||||||
|
gu_new_variant(PGF_EXPR_IMPL_ARG,
|
||||||
|
PgfExprImplArg,
|
||||||
|
&new_expr, pool);
|
||||||
|
new_impl->expr = pgf_clone_expr(impl->expr, pool);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
gu_impossible();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new_expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
PGF_API PgfType*
|
||||||
|
pgf_clone_type(PgfType* type, GuPool* pool)
|
||||||
|
{
|
||||||
|
PgfType* new_type =
|
||||||
|
gu_new_flex(pool, PgfType, exprs, type->n_exprs);
|
||||||
|
|
||||||
|
size_t n_hypos = gu_seq_length(type->hypos);
|
||||||
|
new_type->hypos = gu_new_seq(PgfHypo, n_hypos, pool);
|
||||||
|
for (size_t i = 0; i < n_hypos; i++) {
|
||||||
|
PgfHypo* hypo = gu_seq_index(type->hypos, PgfHypo, i);
|
||||||
|
PgfHypo* new_hypo = gu_seq_index(new_type->hypos, PgfHypo, i);
|
||||||
|
|
||||||
|
new_hypo->bind_type = hypo->bind_type;
|
||||||
|
new_hypo->cid = gu_string_copy(hypo->cid, pool);
|
||||||
|
new_hypo->type = pgf_clone_type(hypo->type, pool);
|
||||||
|
}
|
||||||
|
|
||||||
|
new_type->cid = gu_string_copy(type->cid, pool);
|
||||||
|
|
||||||
|
new_type->n_exprs = type->n_exprs;
|
||||||
|
for (size_t i = 0; i < new_type->n_exprs; i++) {
|
||||||
|
new_type->exprs[i] = pgf_clone_expr(type->exprs[i], pool);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new_type;
|
||||||
|
}
|
||||||
|
|
||||||
PGF_API prob_t
|
PGF_API prob_t
|
||||||
pgf_compute_tree_probability(PgfPGF *gr, PgfExpr expr)
|
pgf_compute_tree_probability(PgfPGF *gr, PgfExpr expr)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -170,15 +170,6 @@ pgf_expr_unmeta(PgfExpr expr);
|
|||||||
PGF_API_DECL PgfExpr
|
PGF_API_DECL PgfExpr
|
||||||
pgf_read_expr(GuIn* in, GuPool* pool, GuPool* tmp_pool, GuExn* err);
|
pgf_read_expr(GuIn* in, GuPool* pool, GuPool* tmp_pool, GuExn* err);
|
||||||
|
|
||||||
PGF_API_DECL int
|
|
||||||
pgf_read_expr_tuple(GuIn* in,
|
|
||||||
size_t n_exprs, PgfExpr exprs[],
|
|
||||||
GuPool* pool, GuExn* err);
|
|
||||||
|
|
||||||
PGF_API_DECL GuSeq*
|
|
||||||
pgf_read_expr_matrix(GuIn* in, size_t n_exprs,
|
|
||||||
GuPool* pool, GuExn* err);
|
|
||||||
|
|
||||||
PGF_API_DECL PgfType*
|
PGF_API_DECL PgfType*
|
||||||
pgf_read_type(GuIn* in, GuPool* pool, GuPool* tmp_pool, GuExn* err);
|
pgf_read_type(GuIn* in, GuPool* pool, GuPool* tmp_pool, GuExn* err);
|
||||||
|
|
||||||
@@ -238,9 +229,14 @@ PGF_API_DECL void
|
|||||||
pgf_print_context(PgfHypos *hypos, PgfPrintContext* ctxt,
|
pgf_print_context(PgfHypos *hypos, PgfPrintContext* ctxt,
|
||||||
GuOut *out, GuExn *err);
|
GuOut *out, GuExn *err);
|
||||||
|
|
||||||
PGF_API_DECL void
|
PGF_API PgfLiteral
|
||||||
pgf_print_expr_tuple(size_t n_exprs, PgfExpr exprs[], PgfPrintContext* ctxt,
|
pgf_clone_literal(PgfLiteral lit, GuPool* pool);
|
||||||
GuOut* out, GuExn* err);
|
|
||||||
|
PGF_API PgfExpr
|
||||||
|
pgf_clone_expr(PgfExpr expr, GuPool* pool);
|
||||||
|
|
||||||
|
PGF_API PgfType*
|
||||||
|
pgf_clone_type(PgfType* type, GuPool* pool);
|
||||||
|
|
||||||
PGF_API_DECL prob_t
|
PGF_API_DECL prob_t
|
||||||
pgf_compute_tree_probability(PgfPGF *gr, PgfExpr expr);
|
pgf_compute_tree_probability(PgfPGF *gr, PgfExpr expr);
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ pgf_bracket_lzn_symbol_token(PgfLinFuncs** funcs, PgfToken tok)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
pgf_bracket_lzn_begin_phrase(PgfLinFuncs** funcs, PgfCId cat, int fid, size_t lindex, PgfCId fun)
|
pgf_bracket_lzn_begin_phrase(PgfLinFuncs** funcs, PgfCId cat, int fid, GuString ann, PgfCId fun)
|
||||||
{
|
{
|
||||||
PgfBracketLznState* state = gu_container(funcs, PgfBracketLznState, funcs);
|
PgfBracketLznState* state = gu_container(funcs, PgfBracketLznState, funcs);
|
||||||
|
|
||||||
@@ -192,7 +192,7 @@ pgf_bracket_lzn_begin_phrase(PgfLinFuncs** funcs, PgfCId cat, int fid, size_t li
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
pgf_bracket_lzn_end_phrase(PgfLinFuncs** funcs, PgfCId cat, int fid, size_t lindex, PgfCId fun)
|
pgf_bracket_lzn_end_phrase(PgfLinFuncs** funcs, PgfCId cat, int fid, GuString ann, PgfCId fun)
|
||||||
{
|
{
|
||||||
PgfBracketLznState* state = gu_container(funcs, PgfBracketLznState, funcs);
|
PgfBracketLznState* state = gu_container(funcs, PgfBracketLznState, funcs);
|
||||||
|
|
||||||
|
|||||||
@@ -606,7 +606,7 @@ typedef struct {
|
|||||||
PgfLzrCachedTag tag;
|
PgfLzrCachedTag tag;
|
||||||
PgfCId cat;
|
PgfCId cat;
|
||||||
int fid;
|
int fid;
|
||||||
int lin_idx;
|
GuString ann;
|
||||||
PgfCId fun;
|
PgfCId fun;
|
||||||
} PgfLzrCached;
|
} PgfLzrCached;
|
||||||
|
|
||||||
@@ -644,7 +644,7 @@ pgf_lzr_cache_flush(PgfLzrCache* cache, PgfSymbols* form)
|
|||||||
cache->lzr->funcs,
|
cache->lzr->funcs,
|
||||||
event->cat,
|
event->cat,
|
||||||
event->fid,
|
event->fid,
|
||||||
event->lin_idx,
|
event->ann,
|
||||||
event->fun);
|
event->fun);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -654,7 +654,7 @@ pgf_lzr_cache_flush(PgfLzrCache* cache, PgfSymbols* form)
|
|||||||
cache->lzr->funcs,
|
cache->lzr->funcs,
|
||||||
event->cat,
|
event->cat,
|
||||||
event->fid,
|
event->fid,
|
||||||
event->lin_idx,
|
event->ann,
|
||||||
event->fun);
|
event->fun);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -709,26 +709,26 @@ found:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
pgf_lzr_cache_begin_phrase(PgfLinFuncs** funcs, PgfCId cat, int fid, size_t lin_idx, PgfCId fun)
|
pgf_lzr_cache_begin_phrase(PgfLinFuncs** funcs, PgfCId cat, int fid, GuString ann, PgfCId fun)
|
||||||
{
|
{
|
||||||
PgfLzrCache* cache = gu_container(funcs, PgfLzrCache, funcs);
|
PgfLzrCache* cache = gu_container(funcs, PgfLzrCache, funcs);
|
||||||
PgfLzrCached* event = gu_buf_extend(cache->events);
|
PgfLzrCached* event = gu_buf_extend(cache->events);
|
||||||
event->tag = PGF_CACHED_BEGIN;
|
event->tag = PGF_CACHED_BEGIN;
|
||||||
event->cat = cat;
|
event->cat = cat;
|
||||||
event->fid = fid;
|
event->fid = fid;
|
||||||
event->lin_idx = lin_idx;
|
event->ann = ann;
|
||||||
event->fun = fun;
|
event->fun = fun;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
pgf_lzr_cache_end_phrase(PgfLinFuncs** funcs, PgfCId cat, int fid, size_t lin_idx, PgfCId fun)
|
pgf_lzr_cache_end_phrase(PgfLinFuncs** funcs, PgfCId cat, int fid, GuString ann, PgfCId fun)
|
||||||
{
|
{
|
||||||
PgfLzrCache* cache = gu_container(funcs, PgfLzrCache, funcs);
|
PgfLzrCache* cache = gu_container(funcs, PgfLzrCache, funcs);
|
||||||
PgfLzrCached* event = gu_buf_extend(cache->events);
|
PgfLzrCached* event = gu_buf_extend(cache->events);
|
||||||
event->tag = PGF_CACHED_END;
|
event->tag = PGF_CACHED_END;
|
||||||
event->cat = cat;
|
event->cat = cat;
|
||||||
event->fid = fid;
|
event->fid = fid;
|
||||||
event->lin_idx = lin_idx;
|
event->ann = ann;
|
||||||
event->fun = fun;
|
event->fun = fun;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -918,7 +918,7 @@ pgf_lzr_linearize_tree(PgfLzr* lzr, PgfCncTree ctree, size_t lin_idx)
|
|||||||
if ((*lzr->funcs)->begin_phrase && fapp->ccat != NULL) {
|
if ((*lzr->funcs)->begin_phrase && fapp->ccat != NULL) {
|
||||||
(*lzr->funcs)->begin_phrase(lzr->funcs,
|
(*lzr->funcs)->begin_phrase(lzr->funcs,
|
||||||
fapp->ccat->cnccat->abscat->name,
|
fapp->ccat->cnccat->abscat->name,
|
||||||
fapp->fid, lin_idx,
|
fapp->fid, fapp->ccat->cnccat->labels[lin_idx],
|
||||||
fapp->abs_id);
|
fapp->abs_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -928,7 +928,7 @@ pgf_lzr_linearize_tree(PgfLzr* lzr, PgfCncTree ctree, size_t lin_idx)
|
|||||||
if ((*lzr->funcs)->end_phrase && fapp->ccat != NULL) {
|
if ((*lzr->funcs)->end_phrase && fapp->ccat != NULL) {
|
||||||
(*lzr->funcs)->end_phrase(lzr->funcs,
|
(*lzr->funcs)->end_phrase(lzr->funcs,
|
||||||
fapp->ccat->cnccat->abscat->name,
|
fapp->ccat->cnccat->abscat->name,
|
||||||
fapp->fid, lin_idx,
|
fapp->fid, fapp->ccat->cnccat->labels[lin_idx],
|
||||||
fapp->abs_id);
|
fapp->abs_id);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -957,7 +957,7 @@ pgf_lzr_linearize_tree(PgfLzr* lzr, PgfCncTree ctree, size_t lin_idx)
|
|||||||
|
|
||||||
if ((*lzr->funcs)->begin_phrase && flit->fid >= 0) {
|
if ((*lzr->funcs)->begin_phrase && flit->fid >= 0) {
|
||||||
(*lzr->funcs)->begin_phrase(lzr->funcs,
|
(*lzr->funcs)->begin_phrase(lzr->funcs,
|
||||||
cat, flit->fid, 0,
|
cat, flit->fid, "s",
|
||||||
"");
|
"");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -989,7 +989,7 @@ pgf_lzr_linearize_tree(PgfLzr* lzr, PgfCncTree ctree, size_t lin_idx)
|
|||||||
|
|
||||||
if ((*lzr->funcs)->end_phrase && flit->fid >= 0) {
|
if ((*lzr->funcs)->end_phrase && flit->fid >= 0) {
|
||||||
(*lzr->funcs)->end_phrase(lzr->funcs,
|
(*lzr->funcs)->end_phrase(lzr->funcs,
|
||||||
cat, flit->fid, 0,
|
cat, flit->fid, "s",
|
||||||
"");
|
"");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -84,10 +84,10 @@ struct PgfLinFuncs
|
|||||||
void (*symbol_token)(PgfLinFuncs** self, PgfToken tok);
|
void (*symbol_token)(PgfLinFuncs** self, PgfToken tok);
|
||||||
|
|
||||||
/// Begin phrase
|
/// Begin phrase
|
||||||
void (*begin_phrase)(PgfLinFuncs** self, PgfCId cat, int fid, size_t lindex, PgfCId fun);
|
void (*begin_phrase)(PgfLinFuncs** self, PgfCId cat, int fid, GuString ann, PgfCId fun);
|
||||||
|
|
||||||
/// End phrase
|
/// End phrase
|
||||||
void (*end_phrase)(PgfLinFuncs** self, PgfCId cat, int fid, size_t lindex, PgfCId fun);
|
void (*end_phrase)(PgfLinFuncs** self, PgfCId cat, int fid, GuString ann, PgfCId fun);
|
||||||
|
|
||||||
/// handling nonExist
|
/// handling nonExist
|
||||||
void (*symbol_ne)(PgfLinFuncs** self);
|
void (*symbol_ne)(PgfLinFuncs** self);
|
||||||
|
|||||||
@@ -6,11 +6,12 @@
|
|||||||
|
|
||||||
static PgfExprProb*
|
static PgfExprProb*
|
||||||
pgf_match_string_lit(PgfLiteralCallback* self, PgfConcr* concr,
|
pgf_match_string_lit(PgfLiteralCallback* self, PgfConcr* concr,
|
||||||
size_t lin_idx,
|
GuString ann,
|
||||||
GuString sentence, size_t* poffset,
|
GuString sentence, size_t* poffset,
|
||||||
GuPool *out_pool)
|
GuPool *out_pool)
|
||||||
{
|
{
|
||||||
gu_assert(lin_idx == 0);
|
if (strcmp(ann,"s") != 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
const uint8_t* buf = (uint8_t*) (sentence + *poffset);
|
const uint8_t* buf = (uint8_t*) (sentence + *poffset);
|
||||||
const uint8_t* p = buf;
|
const uint8_t* p = buf;
|
||||||
@@ -51,7 +52,7 @@ pgf_predict_empty_next(GuEnum* self, void* to, GuPool* pool)
|
|||||||
|
|
||||||
static GuEnum*
|
static GuEnum*
|
||||||
pgf_predict_empty(PgfLiteralCallback* self, PgfConcr* concr,
|
pgf_predict_empty(PgfLiteralCallback* self, PgfConcr* concr,
|
||||||
size_t lin_idx,
|
GuString ann,
|
||||||
GuString prefix,
|
GuString prefix,
|
||||||
GuPool *out_pool)
|
GuPool *out_pool)
|
||||||
{
|
{
|
||||||
@@ -67,11 +68,12 @@ static PgfLiteralCallback pgf_string_literal_callback =
|
|||||||
|
|
||||||
static PgfExprProb*
|
static PgfExprProb*
|
||||||
pgf_match_int_lit(PgfLiteralCallback* self, PgfConcr* concr,
|
pgf_match_int_lit(PgfLiteralCallback* self, PgfConcr* concr,
|
||||||
size_t lin_idx,
|
GuString ann,
|
||||||
GuString sentence, size_t* poffset,
|
GuString sentence, size_t* poffset,
|
||||||
GuPool *out_pool)
|
GuPool *out_pool)
|
||||||
{
|
{
|
||||||
gu_assert(lin_idx == 0);
|
if (strcmp(ann,"s") != 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
const uint8_t* buf = (uint8_t*) (sentence + *poffset);
|
const uint8_t* buf = (uint8_t*) (sentence + *poffset);
|
||||||
const uint8_t* p = buf;
|
const uint8_t* p = buf;
|
||||||
@@ -121,11 +123,12 @@ static PgfLiteralCallback pgf_int_literal_callback =
|
|||||||
|
|
||||||
static PgfExprProb*
|
static PgfExprProb*
|
||||||
pgf_match_float_lit(PgfLiteralCallback* self, PgfConcr* concr,
|
pgf_match_float_lit(PgfLiteralCallback* self, PgfConcr* concr,
|
||||||
size_t lin_idx,
|
GuString ann,
|
||||||
GuString sentence, size_t* poffset,
|
GuString sentence, size_t* poffset,
|
||||||
GuPool *out_pool)
|
GuPool *out_pool)
|
||||||
{
|
{
|
||||||
gu_assert(lin_idx == 0);
|
if (strcmp(ann,"s") != 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
const uint8_t* buf = (uint8_t*) (sentence + *poffset);
|
const uint8_t* buf = (uint8_t*) (sentence + *poffset);
|
||||||
const uint8_t* p = buf;
|
const uint8_t* p = buf;
|
||||||
@@ -226,11 +229,11 @@ pgf_match_name_morpho_callback(PgfMorphoCallback* self_,
|
|||||||
|
|
||||||
static PgfExprProb*
|
static PgfExprProb*
|
||||||
pgf_match_name_lit(PgfLiteralCallback* self, PgfConcr* concr,
|
pgf_match_name_lit(PgfLiteralCallback* self, PgfConcr* concr,
|
||||||
size_t lin_idx,
|
GuString ann,
|
||||||
GuString sentence, size_t* poffset,
|
GuString sentence, size_t* poffset,
|
||||||
GuPool *out_pool)
|
GuPool *out_pool)
|
||||||
{
|
{
|
||||||
if (lin_idx != 0)
|
if (strcmp(ann,"s") != 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
GuPool* tmp_pool = gu_local_pool();
|
GuPool* tmp_pool = gu_local_pool();
|
||||||
@@ -349,7 +352,7 @@ pgf_match_unknown_morpho_callback(PgfMorphoCallback* self_,
|
|||||||
|
|
||||||
static PgfExprProb*
|
static PgfExprProb*
|
||||||
pgf_match_unknown_lit(PgfLiteralCallback* self, PgfConcr* concr,
|
pgf_match_unknown_lit(PgfLiteralCallback* self, PgfConcr* concr,
|
||||||
size_t lin_idx,
|
GuString ann,
|
||||||
GuString sentence, size_t* poffset,
|
GuString sentence, size_t* poffset,
|
||||||
GuPool *out_pool)
|
GuPool *out_pool)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -876,7 +876,7 @@ pgf_lookup_symbol_token(PgfLinFuncs** self, PgfToken token)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
pgf_lookup_begin_phrase(PgfLinFuncs** self, PgfCId cat, int fid, size_t lindex, PgfCId funname)
|
pgf_lookup_begin_phrase(PgfLinFuncs** self, PgfCId cat, int fid, GuString ann, PgfCId funname)
|
||||||
{
|
{
|
||||||
PgfLookupState* st = gu_container(self, PgfLookupState, funcs);
|
PgfLookupState* st = gu_container(self, PgfLookupState, funcs);
|
||||||
|
|
||||||
@@ -890,7 +890,7 @@ pgf_lookup_begin_phrase(PgfLinFuncs** self, PgfCId cat, int fid, size_t lindex,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
pgf_lookup_end_phrase(PgfLinFuncs** self, PgfCId cat, int fid, size_t lindex, PgfCId fun)
|
pgf_lookup_end_phrase(PgfLinFuncs** self, PgfCId cat, int fid, GuString ann, PgfCId fun)
|
||||||
{
|
{
|
||||||
PgfLookupState* st = gu_container(self, PgfLookupState, funcs);
|
PgfLookupState* st = gu_container(self, PgfLookupState, funcs);
|
||||||
st->curr_absfun = NULL;
|
st->curr_absfun = NULL;
|
||||||
|
|||||||
@@ -61,6 +61,14 @@ typedef struct {
|
|||||||
|
|
||||||
typedef enum { BIND_NONE, BIND_HARD, BIND_SOFT } BIND_TYPE;
|
typedef enum { BIND_NONE, BIND_HARD, BIND_SOFT } BIND_TYPE;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
PgfProductionIdx* idx;
|
||||||
|
size_t offset;
|
||||||
|
size_t sym_idx;
|
||||||
|
} PgfLexiconIdxEntry;
|
||||||
|
|
||||||
|
typedef GuBuf PgfLexiconIdx;
|
||||||
|
|
||||||
struct PgfParseState {
|
struct PgfParseState {
|
||||||
PgfParseState* next;
|
PgfParseState* next;
|
||||||
|
|
||||||
@@ -74,6 +82,8 @@ struct PgfParseState {
|
|||||||
size_t end_offset;
|
size_t end_offset;
|
||||||
|
|
||||||
prob_t viterbi_prob;
|
prob_t viterbi_prob;
|
||||||
|
|
||||||
|
PgfLexiconIdx* lexicon_idx;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct PgfAnswers {
|
typedef struct PgfAnswers {
|
||||||
@@ -113,43 +123,10 @@ struct PgfItem {
|
|||||||
prob_t inside_prob;
|
prob_t inside_prob;
|
||||||
};
|
};
|
||||||
|
|
||||||
static PgfSymbol
|
static PgfSymbols*
|
||||||
pgf_prev_extern_sym(PgfSymbol sym)
|
|
||||||
{
|
|
||||||
GuVariantInfo i = gu_variant_open(sym);
|
|
||||||
switch (i.tag) {
|
|
||||||
case PGF_SYMBOL_CAT:
|
|
||||||
return *((PgfSymbol*) (((PgfSymbolCat*) i.data)+1));
|
|
||||||
case PGF_SYMBOL_KP:
|
|
||||||
return *((PgfSymbol*) (((PgfSymbolKP*) i.data)+1));
|
|
||||||
case PGF_SYMBOL_KS: {
|
|
||||||
PgfSymbolKS* sks = (PgfSymbolKS*) i.data;
|
|
||||||
size_t tok_len = strlen(sks->token);
|
|
||||||
return *((PgfSymbol*) (((uint8_t*) sks)+sizeof(PgfSymbolKS)+tok_len+1));
|
|
||||||
}
|
|
||||||
case PGF_SYMBOL_LIT:
|
|
||||||
return *((PgfSymbol*) (((PgfSymbolLit*) i.data)+1));
|
|
||||||
case PGF_SYMBOL_VAR:
|
|
||||||
return *((PgfSymbol*) (((PgfSymbolVar*) i.data)+1));
|
|
||||||
case PGF_SYMBOL_BIND:
|
|
||||||
case PGF_SYMBOL_SOFT_BIND:
|
|
||||||
case PGF_SYMBOL_SOFT_SPACE:
|
|
||||||
return *((PgfSymbol*) (((PgfSymbolBIND*) i.data)+1));
|
|
||||||
case PGF_SYMBOL_CAPIT:
|
|
||||||
case PGF_SYMBOL_ALL_CAPIT:
|
|
||||||
return *((PgfSymbol*) (((PgfSymbolCAPIT*) i.data)+1));
|
|
||||||
case PGF_SYMBOL_NE:
|
|
||||||
return *((PgfSymbol*) (((PgfSymbolNE*) i.data)+1));
|
|
||||||
default:
|
|
||||||
gu_impossible();
|
|
||||||
return gu_null_variant;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static PgfSymbol
|
|
||||||
pgf_collect_extern_tok(PgfParsing* ps, size_t start_offset, size_t end_offset)
|
pgf_collect_extern_tok(PgfParsing* ps, size_t start_offset, size_t end_offset)
|
||||||
{
|
{
|
||||||
PgfSymbol sym = gu_null_variant;
|
GuBuf* syms = gu_new_buf(PgfSymbol, ps->pool);
|
||||||
|
|
||||||
const uint8_t* start = (uint8_t*) ps->sentence+start_offset;
|
const uint8_t* start = (uint8_t*) ps->sentence+start_offset;
|
||||||
const uint8_t* end = (uint8_t*) ps->sentence+end_offset;
|
const uint8_t* end = (uint8_t*) ps->sentence+end_offset;
|
||||||
@@ -163,16 +140,15 @@ pgf_collect_extern_tok(PgfParsing* ps, size_t start_offset, size_t end_offset)
|
|||||||
ucs = gu_utf8_decode(&p);
|
ucs = gu_utf8_decode(&p);
|
||||||
}
|
}
|
||||||
|
|
||||||
PgfSymbol new_sym;
|
PgfSymbol sym;
|
||||||
PgfSymbolKS* sks = (PgfSymbolKS*)
|
PgfSymbolKS* sks = (PgfSymbolKS*)
|
||||||
gu_alloc_variant(PGF_SYMBOL_KS,
|
gu_alloc_variant(PGF_SYMBOL_KS,
|
||||||
sizeof(PgfSymbol)+sizeof(PgfSymbolKS)+len+1,
|
sizeof(PgfSymbolKS)+len+1,
|
||||||
gu_alignof(PgfSymbolKS),
|
gu_alignof(PgfSymbolKS),
|
||||||
&new_sym, ps->pool);
|
&sym, ps->pool);
|
||||||
memcpy((char*) sks->token, start, len);
|
memcpy((char*) sks->token, start, len);
|
||||||
((char*) sks->token)[len] = 0;
|
((char*) sks->token)[len] = 0;
|
||||||
*((PgfSymbol*) (((uint8_t*) sks)+sizeof(PgfSymbolKS)+len+1)) = sym;
|
gu_buf_push(syms, PgfSymbol, sym);
|
||||||
sym = new_sym;
|
|
||||||
|
|
||||||
start = p;
|
start = p;
|
||||||
while (gu_ucs_is_space(ucs)) {
|
while (gu_ucs_is_space(ucs)) {
|
||||||
@@ -181,68 +157,16 @@ pgf_collect_extern_tok(PgfParsing* ps, size_t start_offset, size_t end_offset)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return sym;
|
return gu_buf_data_seq(syms);
|
||||||
}
|
|
||||||
|
|
||||||
static size_t
|
|
||||||
pgf_item_symbols_length(PgfItem* item)
|
|
||||||
{
|
|
||||||
GuVariantInfo i = gu_variant_open(item->prod);
|
|
||||||
switch (i.tag) {
|
|
||||||
case PGF_PRODUCTION_APPLY: {
|
|
||||||
PgfProductionApply* papp = i.data;
|
|
||||||
return gu_seq_length(papp->fun->lins[item->conts->lin_idx]->syms);
|
|
||||||
}
|
|
||||||
case PGF_PRODUCTION_COERCE: {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
case PGF_PRODUCTION_EXTERN: {
|
|
||||||
PgfProductionExtern* pext = i.data;
|
|
||||||
PgfSymbols* syms;
|
|
||||||
|
|
||||||
if (pext->lins != NULL &&
|
|
||||||
(syms = gu_seq_get(pext->lins,PgfSymbols*,item->conts->lin_idx)) != NULL) {
|
|
||||||
return gu_seq_length(syms);
|
|
||||||
} else {
|
|
||||||
int seq_len = 0;
|
|
||||||
PgfSymbol sym = item->curr_sym;
|
|
||||||
while (!gu_variant_is_null(sym)) {
|
|
||||||
seq_len++;
|
|
||||||
sym = pgf_prev_extern_sym(sym);
|
|
||||||
}
|
|
||||||
|
|
||||||
return seq_len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
gu_impossible();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static PgfSymbols*
|
|
||||||
pgf_extern_syms_get(PgfItem* item, GuPool* pool)
|
|
||||||
{
|
|
||||||
int syms_len = pgf_item_symbols_length(item);
|
|
||||||
|
|
||||||
PgfSymbols* syms =
|
|
||||||
gu_new_seq(PgfSymbol, syms_len, pool);
|
|
||||||
PgfSymbol sym = item->curr_sym;
|
|
||||||
while (!gu_variant_is_null(sym)) {
|
|
||||||
gu_seq_set(syms, PgfSymbol, --syms_len, sym);
|
|
||||||
sym = pgf_prev_extern_sym(sym);
|
|
||||||
}
|
|
||||||
|
|
||||||
return syms;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef PGF_PARSER_DEBUG
|
||||||
PGF_INTERNAL void
|
PGF_INTERNAL void
|
||||||
pgf_print_fid(int fid, GuOut* out, GuExn* err);
|
pgf_print_fid(int fid, GuOut* out, GuExn* err);
|
||||||
|
|
||||||
PGF_INTERNAL_DECL void
|
PGF_INTERNAL_DECL void
|
||||||
pgf_print_symbol(PgfSymbol sym, GuOut *out, GuExn *err);
|
pgf_print_symbol(PgfSymbol sym, GuOut *out, GuExn *err);
|
||||||
|
|
||||||
#ifdef PGF_PARSER_DEBUG
|
|
||||||
static void
|
static void
|
||||||
pgf_item_symbols(PgfItem* item,
|
pgf_item_symbols(PgfItem* item,
|
||||||
size_t* lin_idx, PgfSymbols** syms,
|
size_t* lin_idx, PgfSymbols** syms,
|
||||||
@@ -267,11 +191,7 @@ pgf_item_symbols(PgfItem* item,
|
|||||||
}
|
}
|
||||||
case PGF_PRODUCTION_EXTERN: {
|
case PGF_PRODUCTION_EXTERN: {
|
||||||
PgfProductionExtern* pext = i.data;
|
PgfProductionExtern* pext = i.data;
|
||||||
|
*syms = pext->lins[item->conts->lin_idx];
|
||||||
if (pext->lins == NULL ||
|
|
||||||
(*syms = gu_seq_get(pext->lins, PgfSymbols*, item->conts->lin_idx)) == NULL) {
|
|
||||||
*syms = pgf_extern_syms_get(item, pool);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -603,17 +523,12 @@ pgf_item_set_curr_symbol(PgfItem* item, GuPool* pool)
|
|||||||
case PGF_PRODUCTION_EXTERN: {
|
case PGF_PRODUCTION_EXTERN: {
|
||||||
PgfProductionExtern* pext = i.data;
|
PgfProductionExtern* pext = i.data;
|
||||||
|
|
||||||
PgfSymbols* syms;
|
PgfSymbols* syms = pext->lins[item->conts->lin_idx];
|
||||||
if (pext->lins != NULL &&
|
|
||||||
(syms = gu_seq_get(pext->lins,PgfSymbols*,item->conts->lin_idx)) != NULL) {
|
|
||||||
if (item->sym_idx == gu_seq_length(syms)) {
|
if (item->sym_idx == gu_seq_length(syms)) {
|
||||||
item->curr_sym = gu_null_variant;
|
item->curr_sym = gu_null_variant;
|
||||||
} else {
|
} else {
|
||||||
item->curr_sym = gu_seq_get(syms, PgfSymbol, item->sym_idx);
|
item->curr_sym = gu_seq_get(syms, PgfSymbol, item->sym_idx);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
item->curr_sym = gu_null_variant;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -781,16 +696,6 @@ pgf_result_production(PgfParsing* ps,
|
|||||||
static void
|
static void
|
||||||
pgf_parsing_complete(PgfParsing* ps, PgfItem* item, PgfExprProb *ep);
|
pgf_parsing_complete(PgfParsing* ps, PgfItem* item, PgfExprProb *ep);
|
||||||
|
|
||||||
static void
|
|
||||||
pgf_parsing_push_item(PgfParseState* state, PgfItem* item)
|
|
||||||
{
|
|
||||||
if (gu_buf_length(state->agenda) == 0) {
|
|
||||||
state->viterbi_prob =
|
|
||||||
item->inside_prob+item->conts->outside_prob;
|
|
||||||
}
|
|
||||||
gu_buf_heap_push(state->agenda, pgf_item_prob_order, &item);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
pgf_parsing_push_production(PgfParsing* ps, PgfParseState* state,
|
pgf_parsing_push_production(PgfParsing* ps, PgfParseState* state,
|
||||||
PgfItemConts* conts, PgfProduction prod)
|
PgfItemConts* conts, PgfProduction prod)
|
||||||
@@ -822,7 +727,7 @@ pgf_parsing_combine(PgfParsing* ps,
|
|||||||
}
|
}
|
||||||
|
|
||||||
pgf_item_advance(item, ps->pool);
|
pgf_item_advance(item, ps->pool);
|
||||||
pgf_parsing_push_item(before, item);
|
gu_buf_heap_push(before->agenda, pgf_item_prob_order, &item);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PgfProduction
|
static PgfProduction
|
||||||
@@ -851,36 +756,7 @@ pgf_parsing_new_production(PgfItem* item, PgfExprProb *ep, GuPool *pool)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PGF_PRODUCTION_EXTERN: {
|
case PGF_PRODUCTION_EXTERN: {
|
||||||
PgfProductionExtern* pext = i.data;
|
|
||||||
|
|
||||||
if (pext->lins == NULL ||
|
|
||||||
gu_seq_get(pext->lins,PgfSymbols*,item->conts->lin_idx) == NULL) {
|
|
||||||
PgfSymbols* syms =
|
|
||||||
pgf_extern_syms_get(item, pool);
|
|
||||||
|
|
||||||
size_t n_lins = item->conts->ccat->cnccat->n_lins;
|
|
||||||
|
|
||||||
PgfProductionExtern* new_pext = (PgfProductionExtern*)
|
|
||||||
gu_new_variant(PGF_PRODUCTION_EXTERN,
|
|
||||||
PgfProductionExtern,
|
|
||||||
&prod, pool);
|
|
||||||
new_pext->ep = ep;
|
|
||||||
new_pext->lins = gu_new_seq(PgfSymbols*, n_lins, pool);
|
|
||||||
|
|
||||||
if (pext->lins == NULL) {
|
|
||||||
for (size_t i = 0; i < n_lins; i++) {
|
|
||||||
gu_seq_set(new_pext->lins,PgfSymbols*,i,NULL);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (size_t i = 0; i < n_lins; i++) {
|
|
||||||
gu_seq_set(new_pext->lins,PgfSymbols*,i,
|
|
||||||
gu_seq_get(pext->lins,PgfSymbols*,i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
gu_seq_set(new_pext->lins,PgfSymbols*,item->conts->lin_idx,syms);
|
|
||||||
} else {
|
|
||||||
prod = item->prod;
|
prod = item->prod;
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -1022,9 +898,65 @@ pgf_parsing_complete(PgfParsing* ps, PgfItem* item, PgfExprProb *ep)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PGF_INTERNAL_DECL int
|
||||||
|
pgf_symbols_cmp(PgfCohortSpot* spot,
|
||||||
|
PgfSymbols* syms, size_t* sym_idx,
|
||||||
|
bool case_sensitive);
|
||||||
|
|
||||||
|
static void
|
||||||
|
pgf_parsing_lookahead(PgfParsing *ps, PgfParseState* state,
|
||||||
|
int i, int j, ptrdiff_t min, ptrdiff_t max)
|
||||||
|
{
|
||||||
|
// This is a variation of a binary search algorithm which
|
||||||
|
// can retrieve all prefixes of a string with minimal
|
||||||
|
// comparisons, i.e. there is no need to lookup every
|
||||||
|
// prefix separately.
|
||||||
|
|
||||||
|
while (i <= j) {
|
||||||
|
int k = (i+j) / 2;
|
||||||
|
PgfSequence* seq = gu_seq_index(ps->concr->sequences, PgfSequence, k);
|
||||||
|
|
||||||
|
PgfCohortSpot start = {0, ps->sentence + state->end_offset};
|
||||||
|
PgfCohortSpot current = start;
|
||||||
|
size_t sym_idx = 0;
|
||||||
|
int cmp = pgf_symbols_cmp(¤t, seq->syms, &sym_idx, ps->case_sensitive);
|
||||||
|
if (cmp < 0) {
|
||||||
|
j = k-1;
|
||||||
|
} else if (cmp > 0) {
|
||||||
|
ptrdiff_t len = current.ptr - start.ptr;
|
||||||
|
|
||||||
|
if (min <= len)
|
||||||
|
pgf_parsing_lookahead(ps, state, i, k-1, min, len);
|
||||||
|
|
||||||
|
if (len+1 <= max)
|
||||||
|
pgf_parsing_lookahead(ps, state, k+1, j, len+1, max);
|
||||||
|
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
ptrdiff_t len = current.ptr - start.ptr;
|
||||||
|
|
||||||
|
if (min <= len-1)
|
||||||
|
pgf_parsing_lookahead(ps, state, i, k-1, min, len-1);
|
||||||
|
|
||||||
|
if (seq->idx != NULL) {
|
||||||
|
PgfLexiconIdxEntry* entry = gu_buf_extend(state->lexicon_idx);
|
||||||
|
entry->idx = seq->idx;
|
||||||
|
entry->offset = (size_t) (current.ptr - ps->sentence);
|
||||||
|
entry->sym_idx = sym_idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len+1 <= max)
|
||||||
|
pgf_parsing_lookahead(ps, state, k+1, j, len+1, max);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static PgfParseState*
|
static PgfParseState*
|
||||||
pgf_new_parse_state(PgfParsing* ps, size_t start_offset,
|
pgf_new_parse_state(PgfParsing* ps, size_t start_offset,
|
||||||
BIND_TYPE bind_type)
|
BIND_TYPE bind_type,
|
||||||
|
prob_t viterbi_prob)
|
||||||
{
|
{
|
||||||
PgfParseState** pstate;
|
PgfParseState** pstate;
|
||||||
if (ps->before == NULL && start_offset == 0)
|
if (ps->before == NULL && start_offset == 0)
|
||||||
@@ -1077,172 +1009,36 @@ pgf_new_parse_state(PgfParsing* ps, size_t start_offset,
|
|||||||
(start_offset == end_offset);
|
(start_offset == end_offset);
|
||||||
state->start_offset = start_offset;
|
state->start_offset = start_offset;
|
||||||
state->end_offset = end_offset;
|
state->end_offset = end_offset;
|
||||||
state->viterbi_prob = 0;
|
state->viterbi_prob = viterbi_prob;
|
||||||
|
state->lexicon_idx =
|
||||||
|
gu_new_buf(PgfLexiconIdxEntry, ps->pool);
|
||||||
|
|
||||||
if (ps->before == NULL && start_offset == 0)
|
if (ps->before == NULL && start_offset == 0)
|
||||||
state->needs_bind = false;
|
state->needs_bind = false;
|
||||||
|
|
||||||
|
if (gu_seq_length(ps->concr->sequences) > 0) {
|
||||||
|
// Add epsilon lexical rules to the bottom up index
|
||||||
|
PgfSequence* seq = gu_seq_index(ps->concr->sequences, PgfSequence, 0);
|
||||||
|
if (gu_seq_length(seq->syms) == 0 && seq->idx != NULL) {
|
||||||
|
PgfLexiconIdxEntry* entry = gu_buf_extend(state->lexicon_idx);
|
||||||
|
entry->idx = seq->idx;
|
||||||
|
entry->offset = state->start_offset;
|
||||||
|
entry->sym_idx= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add non-epsilon lexical rules to the bottom up index
|
||||||
|
if (!state->needs_bind) {
|
||||||
|
pgf_parsing_lookahead(ps, state,
|
||||||
|
0, gu_seq_length(ps->concr->sequences)-1,
|
||||||
|
1, strlen(ps->sentence)-state->end_offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
*pstate = state;
|
*pstate = state;
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
PGF_INTERNAL_DECL int
|
|
||||||
pgf_symbols_cmp(PgfCohortSpot* spot,
|
|
||||||
PgfSymbols* syms, size_t* sym_idx,
|
|
||||||
bool case_sensitive);
|
|
||||||
|
|
||||||
static bool
|
|
||||||
pgf_parsing_scan_helper(PgfParsing *ps, PgfParseState* state,
|
|
||||||
int i, int j, ptrdiff_t min, ptrdiff_t max)
|
|
||||||
{
|
|
||||||
// This is a variation of a binary search algorithm which
|
|
||||||
// can retrieve all prefixes of a string with minimal
|
|
||||||
// comparisons, i.e. there is no need to lookup every
|
|
||||||
// prefix separately.
|
|
||||||
|
|
||||||
bool found = false;
|
|
||||||
while (i <= j) {
|
|
||||||
int k = (i+j) / 2;
|
|
||||||
PgfSequence* seq = gu_seq_index(ps->concr->sequences, PgfSequence, k);
|
|
||||||
|
|
||||||
PgfCohortSpot start = {0, ps->sentence+state->end_offset};
|
|
||||||
PgfCohortSpot current = start;
|
|
||||||
|
|
||||||
size_t sym_idx = 0;
|
|
||||||
int cmp = pgf_symbols_cmp(¤t, seq->syms, &sym_idx, ps->case_sensitive);
|
|
||||||
if (cmp < 0) {
|
|
||||||
j = k-1;
|
|
||||||
} else if (cmp > 0) {
|
|
||||||
ptrdiff_t len = current.ptr - start.ptr;
|
|
||||||
|
|
||||||
if (min <= len)
|
|
||||||
if (pgf_parsing_scan_helper(ps, state, i, k-1, min, len))
|
|
||||||
found = true;
|
|
||||||
|
|
||||||
if (len+1 <= max)
|
|
||||||
if (pgf_parsing_scan_helper(ps, state, k+1, j, len+1, max))
|
|
||||||
found = true;
|
|
||||||
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
ptrdiff_t len = current.ptr - start.ptr;
|
|
||||||
|
|
||||||
if (min <= len)
|
|
||||||
if (pgf_parsing_scan_helper(ps, state, i, k-1, min, len))
|
|
||||||
found = true;
|
|
||||||
|
|
||||||
// Here we do bottom-up prediction for all lexical categories.
|
|
||||||
// The epsilon productions will be predicted in top-down
|
|
||||||
// fashion while parsing.
|
|
||||||
if (seq->idx != NULL && len > 0) {
|
|
||||||
found = true;
|
|
||||||
|
|
||||||
// A new state will mark the end of the current match
|
|
||||||
PgfParseState* new_state =
|
|
||||||
pgf_new_parse_state(ps, (size_t) (current.ptr - ps->sentence), BIND_NONE);
|
|
||||||
|
|
||||||
// Bottom-up prediction for lexical rules
|
|
||||||
size_t n_entries = gu_buf_length(seq->idx);
|
|
||||||
for (size_t i = 0; i < n_entries; i++) {
|
|
||||||
PgfProductionIdxEntry* entry =
|
|
||||||
gu_buf_index(seq->idx, PgfProductionIdxEntry, i);
|
|
||||||
|
|
||||||
PgfItemConts* conts =
|
|
||||||
pgf_parsing_get_conts(state,
|
|
||||||
entry->ccat, entry->lin_idx,
|
|
||||||
ps->pool);
|
|
||||||
|
|
||||||
// Create the new category if it doesn't exist yet
|
|
||||||
PgfCCat* tmp_ccat = pgf_parsing_get_completed(new_state, conts);
|
|
||||||
PgfCCat* ccat = tmp_ccat;
|
|
||||||
if (ccat == NULL) {
|
|
||||||
ccat = pgf_parsing_create_completed(ps, new_state, conts, INFINITY);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the production
|
|
||||||
if (ccat->prods == NULL || ccat->n_synprods >= gu_seq_length(ccat->prods)) {
|
|
||||||
ccat->prods = gu_realloc_seq(ccat->prods, PgfProduction, ccat->n_synprods+1);
|
|
||||||
}
|
|
||||||
GuVariantInfo i;
|
|
||||||
i.tag = PGF_PRODUCTION_APPLY;
|
|
||||||
i.data = entry->papp;
|
|
||||||
PgfProduction prod = gu_variant_close(i);
|
|
||||||
gu_seq_set(ccat->prods, PgfProduction, ccat->n_synprods++, prod);
|
|
||||||
|
|
||||||
// Update the category's probability to be minimum
|
|
||||||
if (ccat->viterbi_prob > entry->papp->fun->ep->prob)
|
|
||||||
ccat->viterbi_prob = entry->papp->fun->ep->prob;
|
|
||||||
|
|
||||||
#ifdef PGF_PARSER_DEBUG
|
|
||||||
GuPool* tmp_pool = gu_new_pool();
|
|
||||||
GuOut* out = gu_file_out(stderr, tmp_pool);
|
|
||||||
GuExn* err = gu_exn(tmp_pool);
|
|
||||||
if (tmp_ccat == NULL) {
|
|
||||||
gu_printf(out, err, "[");
|
|
||||||
pgf_print_range(state, new_state, out, err);
|
|
||||||
gu_puts("; ", out, err);
|
|
||||||
pgf_print_fid(conts->ccat->fid, out, err);
|
|
||||||
gu_printf(out, err, "; %d; ",
|
|
||||||
conts->lin_idx);
|
|
||||||
pgf_print_fid(ccat->fid, out, err);
|
|
||||||
gu_puts("] ", out, err);
|
|
||||||
pgf_print_fid(ccat->fid, out, err);
|
|
||||||
gu_printf(out, err, ".chunk_count=%d\n", ccat->chunk_count);
|
|
||||||
}
|
|
||||||
pgf_print_production(ccat->fid, prod, out, err);
|
|
||||||
gu_pool_free(tmp_pool);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len <= max)
|
|
||||||
if (pgf_parsing_scan_helper(ps, state, k+1, j, len, max))
|
|
||||||
found = true;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
pgf_parsing_scan(PgfParsing *ps)
|
|
||||||
{
|
|
||||||
size_t len = strlen(ps->sentence);
|
|
||||||
|
|
||||||
PgfParseState* state =
|
|
||||||
pgf_new_parse_state(ps, 0, BIND_SOFT);
|
|
||||||
|
|
||||||
while (state != NULL && state->end_offset < len) {
|
|
||||||
if (state->needs_bind) {
|
|
||||||
// We have encountered two tokens without space in between.
|
|
||||||
// Those can be accepted only if there is a BIND token
|
|
||||||
// in between. We encode this by having one more state
|
|
||||||
// at the same offset. A transition between these two
|
|
||||||
// states is possible only with the BIND token.
|
|
||||||
state =
|
|
||||||
pgf_new_parse_state(ps, state->end_offset, BIND_HARD);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!pgf_parsing_scan_helper
|
|
||||||
(ps, state,
|
|
||||||
0, gu_seq_length(ps->concr->sequences)-1,
|
|
||||||
1, len-state->end_offset)) {
|
|
||||||
// skip one character and try again
|
|
||||||
GuString s = ps->sentence+state->end_offset;
|
|
||||||
gu_utf8_decode((const uint8_t**) &s);
|
|
||||||
pgf_new_parse_state(ps, s-ps->sentence, BIND_NONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state == ps->before)
|
|
||||||
state = ps->after;
|
|
||||||
else
|
|
||||||
state = state->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
pgf_parsing_add_transition(PgfParsing* ps, PgfToken tok, PgfItem* item)
|
pgf_parsing_add_transition(PgfParsing* ps, PgfToken tok, PgfItem* item)
|
||||||
{
|
{
|
||||||
@@ -1262,14 +1058,36 @@ pgf_parsing_add_transition(PgfParsing* ps, PgfToken tok, PgfItem* item)
|
|||||||
if (!ps->before->needs_bind && cmp_string(¤t, tok, ps->case_sensitive) == 0) {
|
if (!ps->before->needs_bind && cmp_string(¤t, tok, ps->case_sensitive) == 0) {
|
||||||
PgfParseState* state =
|
PgfParseState* state =
|
||||||
pgf_new_parse_state(ps, (current.ptr - ps->sentence),
|
pgf_new_parse_state(ps, (current.ptr - ps->sentence),
|
||||||
BIND_NONE);
|
BIND_NONE,
|
||||||
pgf_parsing_push_item(state, item);
|
item->inside_prob+item->conts->outside_prob);
|
||||||
|
gu_buf_heap_push(state->agenda, pgf_item_prob_order, &item);
|
||||||
} else {
|
} else {
|
||||||
pgf_item_free(ps, item);
|
pgf_item_free(ps, item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
pgf_parsing_predict_lexeme(PgfParsing* ps, PgfItemConts* conts,
|
||||||
|
PgfProductionIdxEntry* entry,
|
||||||
|
size_t offset, size_t sym_idx)
|
||||||
|
{
|
||||||
|
GuVariantInfo i = { PGF_PRODUCTION_APPLY, entry->papp };
|
||||||
|
PgfProduction prod = gu_variant_close(i);
|
||||||
|
PgfItem* item =
|
||||||
|
pgf_new_item(ps, conts, prod);
|
||||||
|
PgfSymbols* syms = entry->papp->fun->lins[conts->lin_idx]->syms;
|
||||||
|
item->sym_idx = sym_idx;
|
||||||
|
pgf_item_set_curr_symbol(item, ps->pool);
|
||||||
|
prob_t prob = item->inside_prob+item->conts->outside_prob;
|
||||||
|
PgfParseState* state =
|
||||||
|
pgf_new_parse_state(ps, offset, BIND_NONE, prob);
|
||||||
|
if (state->viterbi_prob > prob) {
|
||||||
|
state->viterbi_prob = prob;
|
||||||
|
}
|
||||||
|
gu_buf_heap_push(state->agenda, pgf_item_prob_order, &item);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
pgf_parsing_td_predict(PgfParsing* ps,
|
pgf_parsing_td_predict(PgfParsing* ps,
|
||||||
PgfItem* item, PgfCCat* ccat, size_t lin_idx)
|
PgfItem* item, PgfCCat* ccat, size_t lin_idx)
|
||||||
@@ -1317,36 +1135,34 @@ pgf_parsing_td_predict(PgfParsing* ps,
|
|||||||
pgf_parsing_push_production(ps, ps->before, conts, prod);
|
pgf_parsing_push_production(ps, ps->before, conts, prod);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Top-down prediction for epsilon lexical rules if any
|
// Bottom-up prediction for lexical and epsilon rules
|
||||||
PgfSequence* seq = gu_seq_index(ps->concr->sequences, PgfSequence, 0);
|
size_t n_idcs = gu_buf_length(ps->before->lexicon_idx);
|
||||||
if (gu_seq_length(seq->syms) == 0 && seq->idx != NULL) {
|
for (size_t i = 0; i < n_idcs; i++) {
|
||||||
|
PgfLexiconIdxEntry* lentry =
|
||||||
|
gu_buf_index(ps->before->lexicon_idx, PgfLexiconIdxEntry, i);
|
||||||
|
|
||||||
PgfProductionIdxEntry key;
|
PgfProductionIdxEntry key;
|
||||||
key.ccat = ccat;
|
key.ccat = ccat;
|
||||||
key.lin_idx = lin_idx;
|
key.lin_idx = lin_idx;
|
||||||
key.papp = NULL;
|
key.papp = NULL;
|
||||||
PgfProductionIdxEntry* value =
|
PgfProductionIdxEntry* value =
|
||||||
gu_seq_binsearch(gu_buf_data_seq(seq->idx),
|
gu_seq_binsearch(gu_buf_data_seq(lentry->idx),
|
||||||
pgf_production_idx_entry_order,
|
pgf_production_idx_entry_order,
|
||||||
PgfProductionIdxEntry, &key);
|
PgfProductionIdxEntry, &key);
|
||||||
|
|
||||||
if (value != NULL) {
|
if (value != NULL) {
|
||||||
GuVariantInfo i = { PGF_PRODUCTION_APPLY, value->papp };
|
pgf_parsing_predict_lexeme(ps, conts, value, lentry->offset, lentry->sym_idx);
|
||||||
PgfProduction prod = gu_variant_close(i);
|
|
||||||
pgf_parsing_push_production(ps, ps->before, conts, prod);
|
|
||||||
|
|
||||||
PgfProductionIdxEntry* start =
|
PgfProductionIdxEntry* start =
|
||||||
gu_buf_data(seq->idx);
|
gu_buf_data(lentry->idx);
|
||||||
PgfProductionIdxEntry* end =
|
PgfProductionIdxEntry* end =
|
||||||
start + gu_buf_length(seq->idx)-1;
|
start + gu_buf_length(lentry->idx)-1;
|
||||||
|
|
||||||
PgfProductionIdxEntry* left = value-1;
|
PgfProductionIdxEntry* left = value-1;
|
||||||
while (left >= start &&
|
while (left >= start &&
|
||||||
value->ccat->fid == left->ccat->fid &&
|
value->ccat->fid == left->ccat->fid &&
|
||||||
value->lin_idx == left->lin_idx) {
|
value->lin_idx == left->lin_idx) {
|
||||||
GuVariantInfo i = { PGF_PRODUCTION_APPLY, left->papp };
|
pgf_parsing_predict_lexeme(ps, conts, left, lentry->offset, lentry->sym_idx);
|
||||||
PgfProduction prod = gu_variant_close(i);
|
|
||||||
pgf_parsing_push_production(ps, ps->before, conts, prod);
|
|
||||||
left--;
|
left--;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1354,9 +1170,7 @@ pgf_parsing_td_predict(PgfParsing* ps,
|
|||||||
while (right <= end &&
|
while (right <= end &&
|
||||||
value->ccat->fid == right->ccat->fid &&
|
value->ccat->fid == right->ccat->fid &&
|
||||||
value->lin_idx == right->lin_idx) {
|
value->lin_idx == right->lin_idx) {
|
||||||
GuVariantInfo i = { PGF_PRODUCTION_APPLY, right->papp };
|
pgf_parsing_predict_lexeme(ps, conts, right, lentry->offset, lentry->sym_idx);
|
||||||
PgfProduction prod = gu_variant_close(i);
|
|
||||||
pgf_parsing_push_production(ps, ps->before, conts, prod);
|
|
||||||
right++;
|
right++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1395,7 +1209,7 @@ pgf_parsing_pre(PgfParsing* ps, PgfItem* item, PgfSymbols* syms)
|
|||||||
} else {
|
} else {
|
||||||
item->alt = 0;
|
item->alt = 0;
|
||||||
pgf_item_advance(item, ps->pool);
|
pgf_item_advance(item, ps->pool);
|
||||||
pgf_parsing_push_item(ps->before, item);
|
gu_buf_heap_push(ps->before->agenda, pgf_item_prob_order, &item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1494,28 +1308,40 @@ pgf_parsing_symbol(PgfParsing* ps, PgfItem* item, PgfSymbol sym)
|
|||||||
|
|
||||||
if (callback != NULL) {
|
if (callback != NULL) {
|
||||||
ep = callback->match(callback, ps->concr,
|
ep = callback->match(callback, ps->concr,
|
||||||
slit->r,
|
parg->ccat->cnccat->labels[slit->r],
|
||||||
ps->sentence, &offset,
|
ps->sentence, &offset,
|
||||||
ps->out_pool);
|
ps->out_pool);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ep != NULL) {
|
if (ep != NULL) {
|
||||||
|
PgfSymbols* syms =
|
||||||
|
pgf_collect_extern_tok(ps, start, offset);
|
||||||
|
|
||||||
|
size_t n_lins = conts->ccat->cnccat->n_lins;
|
||||||
|
|
||||||
PgfProduction prod;
|
PgfProduction prod;
|
||||||
PgfProductionExtern* pext =
|
PgfProductionExtern* pext =
|
||||||
gu_new_variant(PGF_PRODUCTION_EXTERN,
|
gu_new_flex_variant(PGF_PRODUCTION_EXTERN,
|
||||||
PgfProductionExtern,
|
PgfProductionExtern,
|
||||||
|
lins, n_lins,
|
||||||
&prod, ps->pool);
|
&prod, ps->pool);
|
||||||
pext->ep = ep;
|
pext->ep = ep;
|
||||||
pext->lins = NULL;
|
pext->n_lins = n_lins;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < n_lins; i++) {
|
||||||
|
pext->lins[i] = NULL;
|
||||||
|
}
|
||||||
|
pext->lins[conts->lin_idx] = syms;
|
||||||
|
|
||||||
PgfItem* item =
|
PgfItem* item =
|
||||||
pgf_new_item(ps, conts, prod);
|
pgf_new_item(ps, conts, prod);
|
||||||
item->curr_sym = pgf_collect_extern_tok(ps,start,offset);
|
item->curr_sym = gu_null_variant;
|
||||||
item->sym_idx = pgf_item_symbols_length(item);
|
item->sym_idx = gu_seq_length(syms);
|
||||||
PgfParseState* state =
|
PgfParseState* state =
|
||||||
pgf_new_parse_state(ps, offset, BIND_NONE);
|
pgf_new_parse_state(ps, offset, BIND_NONE,
|
||||||
pgf_parsing_push_item(state, item);
|
item->inside_prob+item->conts->outside_prob);
|
||||||
|
gu_buf_heap_push(state->agenda, pgf_item_prob_order, &item);
|
||||||
match = true;
|
match = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1558,10 +1384,11 @@ pgf_parsing_symbol(PgfParsing* ps, PgfItem* item, PgfSymbol sym)
|
|||||||
if (ps->before->start_offset == ps->before->end_offset &&
|
if (ps->before->start_offset == ps->before->end_offset &&
|
||||||
ps->before->needs_bind) {
|
ps->before->needs_bind) {
|
||||||
PgfParseState* state =
|
PgfParseState* state =
|
||||||
pgf_new_parse_state(ps, ps->before->end_offset, BIND_HARD);
|
pgf_new_parse_state(ps, ps->before->end_offset, BIND_HARD,
|
||||||
|
item->inside_prob+item->conts->outside_prob);
|
||||||
if (state != NULL) {
|
if (state != NULL) {
|
||||||
pgf_item_advance(item, ps->pool);
|
pgf_item_advance(item, ps->pool);
|
||||||
pgf_parsing_push_item(state, item);
|
gu_buf_heap_push(state->agenda, pgf_item_prob_order, &item);
|
||||||
} else {
|
} else {
|
||||||
pgf_item_free(ps, item);
|
pgf_item_free(ps, item);
|
||||||
}
|
}
|
||||||
@@ -1575,10 +1402,11 @@ pgf_parsing_symbol(PgfParsing* ps, PgfItem* item, PgfSymbol sym)
|
|||||||
if (ps->before->start_offset == ps->before->end_offset) {
|
if (ps->before->start_offset == ps->before->end_offset) {
|
||||||
if (ps->before->needs_bind) {
|
if (ps->before->needs_bind) {
|
||||||
PgfParseState* state =
|
PgfParseState* state =
|
||||||
pgf_new_parse_state(ps, ps->before->end_offset, BIND_HARD);
|
pgf_new_parse_state(ps, ps->before->end_offset, BIND_HARD,
|
||||||
|
item->inside_prob+item->conts->outside_prob);
|
||||||
if (state != NULL) {
|
if (state != NULL) {
|
||||||
pgf_item_advance(item, ps->pool);
|
pgf_item_advance(item, ps->pool);
|
||||||
pgf_parsing_push_item(state, item);
|
gu_buf_heap_push(state->agenda, pgf_item_prob_order, &item);
|
||||||
} else {
|
} else {
|
||||||
pgf_item_free(ps, item);
|
pgf_item_free(ps, item);
|
||||||
}
|
}
|
||||||
@@ -1587,12 +1415,13 @@ pgf_parsing_symbol(PgfParsing* ps, PgfItem* item, PgfSymbol sym)
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
pgf_item_advance(item, ps->pool);
|
pgf_item_advance(item, ps->pool);
|
||||||
pgf_parsing_push_item(ps->before, item);
|
gu_buf_heap_push(ps->before->agenda, pgf_item_prob_order, &item);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PGF_SYMBOL_CAPIT:
|
case PGF_SYMBOL_CAPIT:
|
||||||
case PGF_SYMBOL_ALL_CAPIT: {
|
case PGF_SYMBOL_ALL_CAPIT: {
|
||||||
|
printf("PGF_SYMBOL_CAPIT\n");
|
||||||
pgf_item_advance(item, ps->pool);
|
pgf_item_advance(item, ps->pool);
|
||||||
pgf_parsing_symbol(ps, item, item->curr_sym);
|
pgf_parsing_symbol(ps, item, item->curr_sym);
|
||||||
break;
|
break;
|
||||||
@@ -1837,7 +1666,8 @@ pgf_parsing_init(PgfConcr* concr, PgfCId cat,
|
|||||||
ps->heuristic_factor = heuristic_factor;
|
ps->heuristic_factor = heuristic_factor;
|
||||||
}
|
}
|
||||||
|
|
||||||
pgf_parsing_scan(ps);
|
PgfParseState* state =
|
||||||
|
pgf_new_parse_state(ps, 0, BIND_SOFT, 0);
|
||||||
|
|
||||||
int fidString = -1;
|
int fidString = -1;
|
||||||
PgfCCat* start_ccat = gu_new(PgfCCat, ps->pool);
|
PgfCCat* start_ccat = gu_new(PgfCCat, ps->pool);
|
||||||
@@ -1857,7 +1687,7 @@ pgf_parsing_init(PgfConcr* concr, PgfCId cat,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
PgfItemConts* conts =
|
PgfItemConts* conts =
|
||||||
pgf_parsing_get_conts(ps->before, start_ccat, 0, ps->pool);
|
pgf_parsing_get_conts(state, start_ccat, 0, ps->pool);
|
||||||
gu_buf_push(conts->items, PgfItem*, NULL);
|
gu_buf_push(conts->items, PgfItem*, NULL);
|
||||||
|
|
||||||
size_t n_ccats = gu_seq_length(cnccat->cats);
|
size_t n_ccats = gu_seq_length(cnccat->cats);
|
||||||
@@ -2196,6 +2026,8 @@ pgf_process_generated_cat(PgfParsing* ps,
|
|||||||
children[i] = pcoerce->coerce;
|
children[i] = pcoerce->coerce;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case PGF_PRODUCTION_EXTERN:
|
||||||
|
just_coercions = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2341,6 +2173,104 @@ pgf_parse_with_heuristics(PgfConcr* concr, PgfType* typ, GuString sentence,
|
|||||||
return &ps->en;
|
return &ps->en;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PGF_API PgfParsing*
|
||||||
|
pgf_parse_to_chart(PgfConcr* concr, PgfType* typ, GuString sentence,
|
||||||
|
double heuristics,
|
||||||
|
PgfCallbacksMap* callbacks,
|
||||||
|
size_t n_roots,
|
||||||
|
GuExn* err,
|
||||||
|
GuPool* pool, GuPool* out_pool)
|
||||||
|
{
|
||||||
|
if (concr->sequences == NULL ||
|
||||||
|
concr->cnccats == NULL) {
|
||||||
|
GuExnData* err_data = gu_raise(err, PgfExn);
|
||||||
|
if (err_data) {
|
||||||
|
err_data->data = "The concrete syntax is not loaded";
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Begin parsing a sentence with the specified category
|
||||||
|
PgfParsing* ps =
|
||||||
|
pgf_parsing_init(concr, typ->cid, sentence, heuristics, callbacks, NULL, err, pool, out_pool);
|
||||||
|
if (ps == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef PGF_COUNTS_DEBUG
|
||||||
|
pgf_parsing_print_counts(ps);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
while (gu_buf_length(ps->expr_queue) < n_roots) {
|
||||||
|
if (!pgf_parsing_proceed(ps)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef PGF_COUNTS_DEBUG
|
||||||
|
pgf_parsing_print_counts(ps);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return ps;
|
||||||
|
}
|
||||||
|
|
||||||
|
PGF_API PgfCCats*
|
||||||
|
pgf_get_parse_roots(PgfParsing* ps, GuPool* pool)
|
||||||
|
{
|
||||||
|
size_t n_cats = 0;
|
||||||
|
size_t n_states = gu_buf_length(ps->expr_queue);
|
||||||
|
GuSeq* roots = gu_new_seq(PgfCCat*, n_states, pool);
|
||||||
|
for (size_t i = 0; i < n_states; i++) {
|
||||||
|
PgfCCat* ccat = gu_buf_get(ps->expr_queue, PgfExprState*, i)->answers->ccat;
|
||||||
|
|
||||||
|
bool found = false;
|
||||||
|
for (size_t j = 0; j < n_cats; j++) {
|
||||||
|
if (gu_seq_get(roots, PgfCCat*, j) == ccat) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
gu_seq_set(roots, PgfCCat*, n_cats, ccat);
|
||||||
|
n_cats++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
roots->len = n_cats;
|
||||||
|
return roots;
|
||||||
|
}
|
||||||
|
|
||||||
|
PGF_API GuSeq*
|
||||||
|
pgf_ccat_to_range(PgfParsing* ps, PgfCCat* ccat, GuPool* pool)
|
||||||
|
{
|
||||||
|
PgfParseState* state = ps->before;
|
||||||
|
GuBuf* buf = gu_new_buf(PgfParseRange, pool);
|
||||||
|
|
||||||
|
while (ccat->conts != NULL) {
|
||||||
|
size_t start = ccat->conts->state->end_offset;
|
||||||
|
size_t end = start;
|
||||||
|
while (state != NULL) {
|
||||||
|
if (pgf_parsing_get_completed(state, ccat->conts) == ccat) {
|
||||||
|
if (state->start_offset >= start)
|
||||||
|
end = state->start_offset;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
state = state->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (start != end) {
|
||||||
|
PgfParseRange* range = gu_buf_extend(buf);
|
||||||
|
range->start = start;
|
||||||
|
range->end = end;
|
||||||
|
range->field = ccat->cnccat->labels[ccat->conts->lin_idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
ccat = ccat->conts->ccat;
|
||||||
|
}
|
||||||
|
|
||||||
|
return gu_buf_data_seq(buf);
|
||||||
|
}
|
||||||
|
|
||||||
PGF_API PgfExprEnum*
|
PGF_API PgfExprEnum*
|
||||||
pgf_parse_with_oracle(PgfConcr* concr, PgfType* typ,
|
pgf_parse_with_oracle(PgfConcr* concr, PgfType* typ,
|
||||||
GuString sentence,
|
GuString sentence,
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
int start, end;
|
int start, end;
|
||||||
PgfCId cat;
|
PgfCId cat;
|
||||||
size_t lin_idx;
|
GuString ann;
|
||||||
} PgfPhrase;
|
} PgfPhrase;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -46,14 +46,14 @@ pgf_metrics_lzn_symbol_token(PgfLinFuncs** funcs, PgfToken tok)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
pgf_metrics_lzn_begin_phrase(PgfLinFuncs** funcs, PgfCId cat, int fid, size_t lin_index, PgfCId fun)
|
pgf_metrics_lzn_begin_phrase(PgfLinFuncs** funcs, PgfCId cat, int fid, GuString ann, PgfCId fun)
|
||||||
{
|
{
|
||||||
PgfMetricsLznState* state = gu_container(funcs, PgfMetricsLznState, funcs);
|
PgfMetricsLznState* state = gu_container(funcs, PgfMetricsLznState, funcs);
|
||||||
gu_buf_push(state->marks, int, state->pos);
|
gu_buf_push(state->marks, int, state->pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
pgf_metrics_lzn_end_phrase1(PgfLinFuncs** funcs, PgfCId cat, int fid, size_t lin_idx, PgfCId fun)
|
pgf_metrics_lzn_end_phrase1(PgfLinFuncs** funcs, PgfCId cat, int fid, GuString ann, PgfCId fun)
|
||||||
{
|
{
|
||||||
PgfMetricsLznState* state = gu_container(funcs, PgfMetricsLznState, funcs);
|
PgfMetricsLznState* state = gu_container(funcs, PgfMetricsLznState, funcs);
|
||||||
|
|
||||||
@@ -65,7 +65,7 @@ pgf_metrics_lzn_end_phrase1(PgfLinFuncs** funcs, PgfCId cat, int fid, size_t lin
|
|||||||
phrase->start = start;
|
phrase->start = start;
|
||||||
phrase->end = end;
|
phrase->end = end;
|
||||||
phrase->cat = cat;
|
phrase->cat = cat;
|
||||||
phrase->lin_idx = lin_idx;
|
phrase->ann = ann;
|
||||||
gu_buf_push(state->phrases, PgfPhrase*, phrase);
|
gu_buf_push(state->phrases, PgfPhrase*, phrase);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -85,7 +85,7 @@ pgf_metrics_symbol_bind(PgfLinFuncs** funcs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
pgf_metrics_lzn_end_phrase2(PgfLinFuncs** funcs, PgfCId cat, int fid, size_t lin_idx, PgfCId fun)
|
pgf_metrics_lzn_end_phrase2(PgfLinFuncs** funcs, PgfCId cat, int fid, GuString ann, PgfCId fun)
|
||||||
{
|
{
|
||||||
PgfMetricsLznState* state = gu_container(funcs, PgfMetricsLznState, funcs);
|
PgfMetricsLznState* state = gu_container(funcs, PgfMetricsLznState, funcs);
|
||||||
|
|
||||||
@@ -100,7 +100,7 @@ pgf_metrics_lzn_end_phrase2(PgfLinFuncs** funcs, PgfCId cat, int fid, size_t lin
|
|||||||
if (phrase->start == start &&
|
if (phrase->start == start &&
|
||||||
phrase->end == end &&
|
phrase->end == end &&
|
||||||
strcmp(phrase->cat, cat) == 0 &&
|
strcmp(phrase->cat, cat) == 0 &&
|
||||||
phrase->lin_idx == lin_idx) {
|
strcmp(phrase->ann, ann) == 0) {
|
||||||
state->matches++;
|
state->matches++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -163,6 +163,20 @@ pgf_category_prob(PgfPGF* pgf, PgfCId catname)
|
|||||||
return abscat->prob;
|
return abscat->prob;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PGF_API GuString*
|
||||||
|
pgf_category_fields(PgfConcr* concr, PgfCId catname, size_t *n_lins)
|
||||||
|
{
|
||||||
|
PgfCncCat* cnccat =
|
||||||
|
gu_map_get(concr->cnccats, catname, PgfCncCat*);
|
||||||
|
if (!cnccat) {
|
||||||
|
*n_lins = 0;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
*n_lins = cnccat->n_lins;
|
||||||
|
return &cnccat->labels;
|
||||||
|
}
|
||||||
|
|
||||||
PGF_API GuString
|
PGF_API GuString
|
||||||
pgf_language_code(PgfConcr* concr)
|
pgf_language_code(PgfConcr* concr)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -95,6 +95,9 @@ pgf_category_context(PgfPGF *gr, PgfCId catname);
|
|||||||
PGF_API_DECL prob_t
|
PGF_API_DECL prob_t
|
||||||
pgf_category_prob(PgfPGF* pgf, PgfCId catname);
|
pgf_category_prob(PgfPGF* pgf, PgfCId catname);
|
||||||
|
|
||||||
|
PGF_API GuString*
|
||||||
|
pgf_category_fields(PgfConcr* concr, PgfCId catname, size_t *n_lins);
|
||||||
|
|
||||||
PGF_API_DECL void
|
PGF_API_DECL void
|
||||||
pgf_iter_functions(PgfPGF* pgf, GuMapItor* itor, GuExn* err);
|
pgf_iter_functions(PgfPGF* pgf, GuMapItor* itor, GuExn* err);
|
||||||
|
|
||||||
@@ -168,8 +171,8 @@ pgf_lookup_morpho(PgfConcr *concr, GuString sentence,
|
|||||||
PgfMorphoCallback* callback, GuExn* err);
|
PgfMorphoCallback* callback, GuExn* err);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
size_t pos;
|
size_t pos; // position in Unicode characters
|
||||||
GuString ptr;
|
GuString ptr; // pointer into the string
|
||||||
} PgfCohortSpot;
|
} PgfCohortSpot;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -208,6 +211,12 @@ pgf_parse_with_heuristics(PgfConcr* concr, PgfType* typ,
|
|||||||
GuExn* err,
|
GuExn* err,
|
||||||
GuPool* pool, GuPool* out_pool);
|
GuPool* pool, GuPool* out_pool);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
size_t start;
|
||||||
|
size_t end;
|
||||||
|
GuString field;
|
||||||
|
} PgfParseRange;
|
||||||
|
|
||||||
typedef struct PgfOracleCallback PgfOracleCallback;
|
typedef struct PgfOracleCallback PgfOracleCallback;
|
||||||
|
|
||||||
struct PgfOracleCallback {
|
struct PgfOracleCallback {
|
||||||
@@ -248,11 +257,11 @@ typedef struct PgfLiteralCallback PgfLiteralCallback;
|
|||||||
|
|
||||||
struct PgfLiteralCallback {
|
struct PgfLiteralCallback {
|
||||||
PgfExprProb* (*match)(PgfLiteralCallback* self, PgfConcr* concr,
|
PgfExprProb* (*match)(PgfLiteralCallback* self, PgfConcr* concr,
|
||||||
size_t lin_idx,
|
GuString ann,
|
||||||
GuString sentence, size_t* poffset,
|
GuString sentence, size_t* poffset,
|
||||||
GuPool *out_pool);
|
GuPool *out_pool);
|
||||||
GuEnum* (*predict)(PgfLiteralCallback* self, PgfConcr* concr,
|
GuEnum* (*predict)(PgfLiteralCallback* self, PgfConcr* concr,
|
||||||
size_t lin_idx,
|
GuString ann,
|
||||||
GuString prefix,
|
GuString prefix,
|
||||||
GuPool *out_pool);
|
GuPool *out_pool);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -234,12 +234,13 @@ typedef struct {
|
|||||||
GuEnum en;
|
GuEnum en;
|
||||||
PgfConcr* concr;
|
PgfConcr* concr;
|
||||||
GuString sentence;
|
GuString sentence;
|
||||||
GuString current;
|
|
||||||
size_t len;
|
size_t len;
|
||||||
PgfMorphoCallback* callback;
|
PgfMorphoCallback* callback;
|
||||||
GuExn* err;
|
GuExn* err;
|
||||||
bool case_sensitive;
|
bool case_sensitive;
|
||||||
GuBuf* spots;
|
GuBuf* spots;
|
||||||
|
GuBuf* skip_spots;
|
||||||
|
GuBuf* empty_buf;
|
||||||
GuBuf* found;
|
GuBuf* found;
|
||||||
} PgfCohortsState;
|
} PgfCohortsState;
|
||||||
|
|
||||||
@@ -255,6 +256,23 @@ cmp_cohort_spot(GuOrder* self, const void* a, const void* b)
|
|||||||
static GuOrder
|
static GuOrder
|
||||||
pgf_cohort_spot_order[1] = {{ cmp_cohort_spot }};
|
pgf_cohort_spot_order[1] = {{ cmp_cohort_spot }};
|
||||||
|
|
||||||
|
static void
|
||||||
|
pgf_lookup_cohorts_report_skip(PgfCohortsState *state,
|
||||||
|
PgfCohortSpot* spot)
|
||||||
|
{
|
||||||
|
size_t n_spots = gu_buf_length(state->skip_spots);
|
||||||
|
for (size_t i = 0; i < n_spots; i++) {
|
||||||
|
PgfCohortSpot* skip_spot =
|
||||||
|
gu_buf_index(state->skip_spots, PgfCohortSpot, i);
|
||||||
|
|
||||||
|
PgfCohortRange* range = gu_buf_insert(state->found, 0);
|
||||||
|
range->start = *skip_spot;
|
||||||
|
range->end = *spot;
|
||||||
|
range->buf = state->empty_buf;
|
||||||
|
}
|
||||||
|
gu_buf_flush(state->skip_spots);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
pgf_lookup_cohorts_helper(PgfCohortsState *state, PgfCohortSpot* spot,
|
pgf_lookup_cohorts_helper(PgfCohortsState *state, PgfCohortSpot* spot,
|
||||||
int i, int j, ptrdiff_t min, ptrdiff_t max)
|
int i, int j, ptrdiff_t min, ptrdiff_t max)
|
||||||
@@ -291,18 +309,23 @@ pgf_lookup_cohorts_helper(PgfCohortsState *state, PgfCohortSpot* spot,
|
|||||||
pgf_lookup_cohorts_helper(state, spot, i, k-1, min, len);
|
pgf_lookup_cohorts_helper(state, spot, i, k-1, min, len);
|
||||||
|
|
||||||
if (seq->idx != NULL && gu_buf_length(seq->idx) > 0) {
|
if (seq->idx != NULL && gu_buf_length(seq->idx) > 0) {
|
||||||
|
// Report unknown words
|
||||||
|
pgf_lookup_cohorts_report_skip(state, spot);
|
||||||
|
|
||||||
|
// Report the actual hit
|
||||||
PgfCohortRange* range = gu_buf_insert(state->found, 0);
|
PgfCohortRange* range = gu_buf_insert(state->found, 0);
|
||||||
range->start = *spot;
|
range->start = *spot;
|
||||||
range->end = current;
|
range->end = current;
|
||||||
range->buf = seq->idx;
|
range->buf = seq->idx;
|
||||||
}
|
|
||||||
|
|
||||||
|
// Schedule the next search spot
|
||||||
while (*current.ptr != 0) {
|
while (*current.ptr != 0) {
|
||||||
if (!skip_space(¤t.ptr, ¤t.pos))
|
if (!skip_space(¤t.ptr, ¤t.pos))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
gu_buf_heap_push(state->spots, pgf_cohort_spot_order, ¤t);
|
gu_buf_heap_push(state->spots, pgf_cohort_spot_order, ¤t);
|
||||||
|
}
|
||||||
|
|
||||||
if (len <= max)
|
if (len <= max)
|
||||||
pgf_lookup_cohorts_helper(state, spot, k+1, j, len, max);
|
pgf_lookup_cohorts_helper(state, spot, k+1, j, len, max);
|
||||||
@@ -322,24 +345,62 @@ pgf_lookup_cohorts_enum_next(GuEnum* self, void* to, GuPool* pool)
|
|||||||
PgfCohortSpot spot;
|
PgfCohortSpot spot;
|
||||||
gu_buf_heap_pop(state->spots, pgf_cohort_spot_order, &spot);
|
gu_buf_heap_pop(state->spots, pgf_cohort_spot_order, &spot);
|
||||||
|
|
||||||
if (spot.ptr == state->current)
|
GuString next_ptr = state->sentence+state->len;
|
||||||
continue;
|
while (gu_buf_length(state->spots) > 0) {
|
||||||
|
GuString ptr =
|
||||||
if (*spot.ptr == 0)
|
gu_buf_index(state->spots, PgfCohortSpot, 0)->ptr;
|
||||||
|
if (ptr > spot.ptr) {
|
||||||
|
next_ptr = ptr;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
gu_buf_heap_pop(state->spots, pgf_cohort_spot_order, &spot);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool needs_report = true;
|
||||||
|
while (next_ptr > spot.ptr) {
|
||||||
pgf_lookup_cohorts_helper
|
pgf_lookup_cohorts_helper
|
||||||
(state, &spot,
|
(state, &spot,
|
||||||
0, gu_seq_length(state->concr->sequences)-1,
|
0, gu_seq_length(state->concr->sequences)-1,
|
||||||
1, (state->sentence+state->len)-spot.ptr);
|
1, (state->sentence+state->len)-spot.ptr);
|
||||||
|
|
||||||
if (gu_buf_length(state->found) == 0) {
|
// got a hit -> exit
|
||||||
// skip one character and try again
|
if (gu_buf_length(state->found) > 0)
|
||||||
gu_utf8_decode((const uint8_t**) &spot.ptr);
|
break;
|
||||||
|
|
||||||
|
if (needs_report) {
|
||||||
|
// no hit, but the word must be reported as unknown.
|
||||||
|
gu_buf_push(state->skip_spots, PgfCohortSpot, spot);
|
||||||
|
needs_report = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip one character
|
||||||
|
const uint8_t* ptr = (const uint8_t*) spot.ptr;
|
||||||
|
GuUCS c = gu_utf8_decode(&ptr);
|
||||||
|
if (gu_ucs_is_space(c)) {
|
||||||
|
// We have encounter a space and we must report
|
||||||
|
// a new unknown word.
|
||||||
|
pgf_lookup_cohorts_report_skip(state, &spot);
|
||||||
|
|
||||||
|
spot.ptr = (GuString) ptr;
|
||||||
spot.pos++;
|
spot.pos++;
|
||||||
|
|
||||||
|
// Schedule the next search spot
|
||||||
|
while (*spot.ptr != 0) {
|
||||||
|
if (!skip_space(&spot.ptr, &spot.pos))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
gu_buf_heap_push(state->spots, pgf_cohort_spot_order, &spot);
|
gu_buf_heap_push(state->spots, pgf_cohort_spot_order, &spot);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
spot.ptr = (GuString) ptr;
|
||||||
|
spot.pos++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PgfCohortSpot end_spot = {state->len, state->sentence+state->len};
|
||||||
|
pgf_lookup_cohorts_report_skip(state, &end_spot);
|
||||||
|
|
||||||
PgfCohortRange* pRes = (PgfCohortRange*)to;
|
PgfCohortRange* pRes = (PgfCohortRange*)to;
|
||||||
|
|
||||||
@@ -349,15 +410,19 @@ pgf_lookup_cohorts_enum_next(GuEnum* self, void* to, GuPool* pool)
|
|||||||
pRes->end.pos = 0;
|
pRes->end.pos = 0;
|
||||||
pRes->end.ptr = NULL;
|
pRes->end.ptr = NULL;
|
||||||
pRes->buf = NULL;
|
pRes->buf = NULL;
|
||||||
state->current = NULL;
|
} else for (;;) {
|
||||||
return;
|
|
||||||
} else do {
|
|
||||||
*pRes = gu_buf_pop(state->found, PgfCohortRange);
|
*pRes = gu_buf_pop(state->found, PgfCohortRange);
|
||||||
state->current = pRes->start.ptr;
|
|
||||||
pgf_morpho_iter(pRes->buf, state->callback, state->err);
|
pgf_morpho_iter(pRes->buf, state->callback, state->err);
|
||||||
} while (gu_buf_length(state->found) > 0 &&
|
|
||||||
gu_buf_index_last(state->found, PgfCohortRange)->end.ptr == pRes->end.ptr);
|
|
||||||
|
|
||||||
|
if (gu_buf_length(state->found) <= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
PgfCohortRange* last =
|
||||||
|
gu_buf_index_last(state->found, PgfCohortRange);
|
||||||
|
if (last->start.ptr != pRes->start.ptr ||
|
||||||
|
last->end.ptr != pRes->end.ptr)
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PGF_API GuEnum*
|
PGF_API GuEnum*
|
||||||
@@ -376,12 +441,14 @@ pgf_lookup_cohorts(PgfConcr *concr, GuString sentence,
|
|||||||
PgfCohortsState* state = gu_new(PgfCohortsState, pool);
|
PgfCohortsState* state = gu_new(PgfCohortsState, pool);
|
||||||
state->en.next = pgf_lookup_cohorts_enum_next;
|
state->en.next = pgf_lookup_cohorts_enum_next;
|
||||||
state->concr = concr;
|
state->concr = concr;
|
||||||
state->sentence= sentence;
|
state->sentence = sentence;
|
||||||
state->len = strlen(sentence);
|
state->len = strlen(sentence);
|
||||||
state->callback= callback;
|
state->callback = callback;
|
||||||
state->err = err;
|
state->err = err;
|
||||||
state->case_sensitive = pgf_is_case_sensitive(concr);
|
state->case_sensitive= pgf_is_case_sensitive(concr);
|
||||||
state->spots = gu_new_buf(PgfCohortSpot, pool);
|
state->spots = gu_new_buf(PgfCohortSpot, pool);
|
||||||
|
state->skip_spots = gu_new_buf(PgfCohortSpot, pool);
|
||||||
|
state->empty_buf = gu_new_buf(PgfProductionIdxEntry, pool);
|
||||||
state->found = gu_new_buf(PgfCohortRange, pool);
|
state->found = gu_new_buf(PgfCohortRange, pool);
|
||||||
|
|
||||||
PgfCohortSpot spot = {0,sentence};
|
PgfCohortSpot spot = {0,sentence};
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user