1
0
forked from GitHub/gf-core

Compare commits

..

352 Commits

Author SHA1 Message Date
John J. Camilleri
c058457337 Change Data.Text to String as a test, seemingly makes no difference. 2021-03-10 16:50:26 +01:00
John J. Camilleri
8f5033e4ce Add notes on profiling 2021-03-09 08:36:35 +01:00
John J. Camilleri
126b61ea03 Merge branch 'master' into lpgf 2021-03-08 13:52:34 +01:00
John J. Camilleri
9b4f2dd18b Remove notice about RGL not being included anymore from build scripts 2021-03-08 13:48:30 +01:00
John J. Camilleri
99abb9b2a5 Add Phrasebook benchmark snippet to LPGF README 2021-03-08 13:37:02 +01:00
John J. Camilleri
3e9d12854a Switch to 10000-tree Phrasebook treebank. All errors to do with missing functions, plus variants in German. 2021-03-08 11:19:06 +01:00
John J. Camilleri
fd07946a50 Remove commented line 2021-03-08 10:42:16 +01:00
John J. Camilleri
c76efcf916 Use C runtime in mkTreebank script 2021-03-08 10:17:03 +01:00
John J. Camilleri
785d6069e2 Fix lin2string and pass all unittests and Phrasebook 2021-03-08 09:53:10 +01:00
John J. Camilleri
0f4b349b0b Remove old commented code 2021-03-05 16:51:59 +01:00
John J. Camilleri
dbf369aae5 Make removal of record fields recursive. Latest results with Phrasebook:
Bul ✓
Cat ✗
Chi ✓
Dan ✓
Dut ✓
Eng ✓
Est ✓
Fin ✓
Fre ✗
Ger ✓
Hin ✓
Ita ✗
Jpn ✓
Lav ✓
Nor ✓
Pol ✓
Ron ✓
Snd ✗
Spa ✓
Swe ✓
Tha ✓
Urd ✓

Passed 18 | Failed 4 | Total 22
2021-03-05 16:48:05 +01:00
John J. Camilleri
0d4659fe8c Add workaround for missing param defs. Add links to gf-core issues in workaround comments. 2021-03-05 13:23:00 +01:00
John J. Camilleri
575a746a3e Add LPGF function for catching errors. Manual fixes to Phrasebook treebank. 2021-03-05 12:05:25 +01:00
John J. Camilleri
70581c2d8c Improve base case in table handling, cleanup. Add run-phrasebook script, current output:
Bul ✗
Cat ✗
Chi ✓
Dan ✓
Dut ✓
Eng ✓
Est ✓
Fin ✗
Fre ✗
Ger ✓
Hin ✓
Ita ✗
Jpn ✓
Lav ✓
Nor ✓
Pol ✓
Ron ✓
Snd ✗
Spa ✗
Swe ✓
Tha ✓
Urd ✓

Passed 15 | Failed 7 | Total 22
2021-03-04 17:09:35 +01:00
John J. Camilleri
bca1e2286d New handling of tables, works for all tests but Phrasebook still fails 2021-03-04 16:42:56 +01:00
John J. Camilleri
94f76b9e36 Add more tests to Params5 which cause it to fail again
Originally found in PhrasebookFre
2021-03-04 13:38:55 +01:00
John J. Camilleri
f5886bf447 Add more complex param/table unit tests and pass them. Still fails on Phrasebook though. 2021-03-04 12:37:12 +01:00
John J. Camilleri
0ba0438dc7 Add a little colour to benchmark output 2021-03-04 10:20:57 +01:00
John J. Camilleri
30b016032d Also store Pre prefixes in token map. Introduce IntMapBuilder data structure.
Storing of prefixes uses show/read, which isn't a great solution but avoids having yet another token map.
2021-03-04 09:58:17 +01:00
John J. Camilleri
4082c006c3 Extract token strings and put them in map which linfuns refer to by index, to reduce LPGF sizes. 2021-03-04 00:16:12 +01:00
John J. Camilleri
adc162b374 Pass all unit tests and Foods again, with new strategy. Cleanup. 2021-03-03 15:21:32 +01:00
John J. Camilleri
3beed2c49e Replace list comprehension lookups with maps. Halfway through transitioning to new strategy for tables/params, see testsuite/lpgf/README.md. 2021-03-03 13:26:03 +01:00
John J. Camilleri
a8e3dc8855 Improve mkTreebank script. Add 100-tree Phrasebook treebank. Improve output in testsuite. 2021-03-03 11:01:31 +01:00
John J. Camilleri
997d7c1694 Use ErrorMonad instead of IOE
It probably ends up being the same thing, but the code is a little cleaner for it.
2021-03-03 09:36:48 +01:00
John J. Camilleri
4c09e4a340 Remove LF prefix from constructors. Pass all unit tests and Foods again, but improvements/cleanup still necessary. 2021-03-03 09:19:52 +01:00
Inari Listenmaa
9dda5dfa8a (Homepage) Link to summer school 2021 2021-03-01 04:23:39 +01:00
Inari Listenmaa
2fd94f5f57 Merge pull request #99 from inariksit/refman-updates
(refman) Add section about lists + links to my blog
2021-03-01 04:16:47 +01:00
John J. Camilleri
33e0e98aec Add 1-tree treebank for Phrasebook in a few languages 2021-02-28 00:34:46 +01:00
John J. Camilleri
83bc3c9c6e More work on params: pass all tests except params1 (!) 2021-02-27 23:13:02 +01:00
John J. Camilleri
f42b5ec9ef More work on params, but Foods fails now 2021-02-26 20:25:05 +01:00
John J. Camilleri
4771d9c356 WIP params 2021-02-26 17:18:21 +01:00
krangelov
ba3e09cc38 Merge branch 'master' of https://github.com/GrammaticalFramework/gf-core 2021-02-26 14:59:18 +01:00
krangelov
8fbfc0b4a9 bracketedLinearize now reports the binding spots just like the Haskell binding 2021-02-26 14:58:31 +01:00
John J. Camilleri
9785f8351d Reduce Params2 further 2021-02-26 11:52:12 +01:00
John J. Camilleri
6a5d735904 Reduce Params2 unittest (still fails) 2021-02-26 10:26:11 +01:00
John J. Camilleri
8324ad8801 Add pretty-printing of LPGF grammars, to help debugging 2021-02-26 10:13:33 +01:00
Inari Listenmaa
f9b8653ab2 (refman) Add section about lists + links to my blog 2021-02-22 23:18:42 +08:00
John J. Camilleri
20290be616 Add Params2 unit test, from problem uncovered in PhrasebookGer 2021-02-22 10:52:37 +01:00
John J. Camilleri
b4a393ac09 Pass missing unit test 2021-02-21 14:22:46 +01:00
John J. Camilleri
9942908df9 Add unit test for missing lins 2021-02-21 14:05:31 +01:00
John J. Camilleri
dca2ebaf72 Add Phrasebook to testsuite. Move grammars into subfolders. Add run-bench script. 2021-02-20 13:22:29 +01:00
John J. Camilleri
5ad5789b31 Filter out record fields which don't exist in lintype
This is to work around an inconsistency in the canonical representation
2021-02-19 15:19:40 +01:00
John J. Camilleri
9f3f4139b1 Grammar and languages to run in testsuite can be specified by command line options, see README 2021-02-19 11:14:55 +01:00
John J. Camilleri
505c12c528 Rename run.hs to test.hs 2021-02-19 09:33:35 +01:00
John J. Camilleri
023b50557e Write LPGF dump to file when DEBUG is set, rather than console 2021-02-19 09:31:26 +01:00
John J. Camilleri
2b0493eece Tweak memory reporting and strictness in benchmark 2021-02-19 09:18:01 +01:00
John J. Camilleri
51e543878b Add support for wildcards when specifying modules names in benchmark compilation 2021-02-18 21:34:23 +01:00
John J. Camilleri
625386a14f Force evaluation in benchmark linearisation
BangPatterns only does WHNF which is not sufficient, previous benchmark results are thus wrong
2021-02-18 21:01:30 +01:00
John J. Camilleri
5240749fad Make grammar and trees files command line arguments into benchmark script 2021-02-18 15:27:25 +01:00
John J. Camilleri
e6079523f1 Remove ParamAliasDefs by inlining their definitions 2021-02-18 14:45:10 +01:00
John J. Camilleri
866a2101e1 When projecting a non-existent field, return Prelude.False
This seems to be GF's own behaviour, as exhibited by the canonical version of PhrasebookTha:

    NNumeral Numeral_0 = {s = Numeral_0.s; hasC = <>.hasC};
2021-02-18 14:42:39 +01:00
John J. Camilleri
d8557e8433 Enable debug output to files with envvar DEBUG=1 2021-02-18 14:40:03 +01:00
John J. Camilleri
7a5bc2dab3 Separate compile/run in benchmark 2021-02-17 16:57:06 +01:00
John J. Camilleri
9a263450f5 Add PFG2 linearisation to benchmark 2021-02-17 15:30:11 +01:00
John J. Camilleri
8e1fa4981f Add memory stats to benchmark 2021-02-17 15:02:39 +01:00
John J. Camilleri
b4fce5db59 Use envvars in benchmark for controlling PGF/LPGF. Add readme. 2021-02-17 11:44:00 +01:00
John J. Camilleri
6a7ead0f84 Add benchmark for comparing PGF and LPGF 2021-02-17 10:04:36 +01:00
John J. Camilleri
d3988f93d5 writePGF et al. functions return path[s] of written files 2021-02-17 10:03:52 +01:00
John J. Camilleri
236dbdbba3 Minor tidying 2021-02-17 00:15:44 +01:00
John J. Camilleri
768c3d9b2d Include return types for params, records, pre 2021-02-17 00:04:37 +01:00
John J. Camilleri
29114ce606 Improve binary format, reducing Foods.lpgf from 300 to 73KB (4x smaller!) 2021-02-16 23:30:21 +01:00
John J. Camilleri
5be21dba1c Add and pass FoodsJpn 2021-02-16 22:49:37 +01:00
John J. Camilleri
d5cf00f711 Add and pass all Foods languages, except Jpn 2021-02-16 22:41:28 +01:00
John J. Camilleri
312cfeb69d Add Afr, Amh, Cat, Cze, Dut, Ger foods grammars to testsuite 2021-02-16 22:33:26 +01:00
John J. Camilleri
2d03b9ee0c Finish type passing in val2lin, generalise projection case and pass FoodsFre testsuite. 2021-02-16 21:07:24 +01:00
John J. Camilleri
4c06c3f825 Add case for when pre is not followed by anything 2021-02-16 21:01:01 +01:00
John J. Camilleri
7227ede24b WIP return type from val2lin for use in projection case 2021-02-16 17:18:01 +01:00
John J. Camilleri
398b294734 Use Data.Text instead of String. Rename Abstr to Abstract, Concr to Concrete. 2021-02-16 16:04:40 +01:00
John J. Camilleri
d394cacddf Add support for CAPIT and ALL_CAPIT 2021-02-16 15:17:54 +01:00
John J. Camilleri
21f14c2aa1 Add support for SOFT_SPACE 2021-02-16 14:57:33 +01:00
John J. Camilleri
23e49cddb7 Add support for SOFT_BIND (which PGF runtime doesn't support) 2021-02-16 14:51:29 +01:00
John J. Camilleri
4d1217b06d Add support for pre 2021-02-15 21:57:05 +01:00
John J. Camilleri
4f0abe5540 Add FoodsFre, fails because pre is not implemented
Also an unhandled Projection case
2021-02-15 01:14:34 +01:00
John J. Camilleri
109822675b Pass test with FoodsFin, by forcibly resorting record fields to make s first 2021-02-15 00:43:53 +01:00
John J. Camilleri
d563abb928 Minors 2021-02-13 00:59:15 +01:00
John J. Camilleri
a58a6c8a59 Add FoodsFin to testsuite (fails) 2021-02-13 00:16:03 +01:00
John J. Camilleri
98f6136ebd Add support for BIND 2021-02-13 00:14:35 +01:00
John J. Camilleri
8cfaa69b6e Handle record tables, pass FoodSwe in testsuite 2021-02-12 23:51:16 +01:00
John J. Camilleri
a12f58e7b0 Add test case for selection using records (fails) 2021-02-10 13:55:38 +01:00
John J. Camilleri
d5f68970b9 Add FoodsSwe (fails) 2021-02-09 10:54:51 +01:00
John J. Camilleri
9c2d8eb0b2 Add FoodsChi, FoodsHeb to LPGF testsuite 2021-02-09 10:14:40 +01:00
Inari Listenmaa
173fca7f12 Merge pull request #93 from inariksit/notYet-errormsg
Fix #92 (inappropriate error message)
2021-02-06 14:04:45 +01:00
John J. Camilleri
34f0fc0ba7 Fix bug in dynamic parameter handling, compile FoodsBul successfully 2021-02-03 15:41:27 +01:00
John J. Camilleri
42b9e7036e Support dynamic param values 2021-02-03 13:16:10 +01:00
John J. Camilleri
132f693713 Minor cleanup 2021-02-03 09:44:15 +01:00
John J. Camilleri
153bffdad7 Support nested parameters, but fails with non-static values (see FoodsBull, ASg kind.g). 2021-02-03 00:11:22 +01:00
John J. Camilleri
d09838e97e Separate .trees and .treebank, and add a script for making the latter from the former 2021-02-02 21:46:38 +01:00
John J. Camilleri
c94bffe435 Generalise testsuite script to use treebank files, add FoodEng 2021-02-02 21:22:36 +01:00
John J. Camilleri
2a5850023b Correctly handle projection, but only in limited cases 2021-02-01 13:08:39 +01:00
John J. Camilleri
fe15aa0c00 Use canonical GF in LPGF compiler
Still contains some hardcoded values, missing cases.

I notice now that LPGF and Canonical GF are almost identical, so maybe we don't need a new LPGF format,
just a linearization-only runtime which works on canonical grammars.
The argument for keeping LGPF is that it would be optimized for size and speed.
2021-02-01 12:28:06 +01:00
John J. Camilleri
cead0cc4c1 Add selection and projection cases but not working 2021-01-26 09:55:07 +01:00
John J. Camilleri
6f622b496b Rename Zero grammar to Walking 2021-01-26 09:35:21 +01:00
John J. Camilleri
270e7f021f Add binary instances 2021-01-25 14:42:00 +01:00
John J. Camilleri
32b0860925 Make LPGF testsuite work (but still fails)
stack test :lpgf
2021-01-25 13:41:33 +01:00
John J. Camilleri
f24c50339b Strip down format. More early work on compiler. Add testsuite (doesn't work yet). 2021-01-25 12:10:30 +01:00
Inari Listenmaa
c6ff3e0c5e Update also the stack setup 2021-01-25 18:48:46 +08:00
Inari Listenmaa
8a85dbc66f Update Github actions to latest haskell-setup 2021-01-25 18:43:25 +08:00
John J. Camilleri
cd5881d83a Early work on LPGF compiler 2021-01-22 15:17:36 +01:00
John J. Camilleri
93b81b9f13 Add first version of LPGF datatype, with linearization function and some hardcoded examples 2021-01-22 14:07:41 +01:00
krangelov
655173932e fix type signature 2021-01-20 20:38:19 +01:00
krangelov
04f6f113f0 Merge branch 'master' of https://github.com/GrammaticalFramework/gf-core 2021-01-20 20:16:26 +01:00
krangelov
bac619f025 fix gu_map_next 2021-01-20 20:15:40 +01:00
Inari Listenmaa
1a466c14c8 Don't print out the error msg for pattern matching unnecessarily 2021-01-20 01:15:28 +08:00
John J. Camilleri
8ad9cf1e09 Add flag and stubs for compiling to LPGF format 2021-01-19 17:21:13 +01:00
Inari Listenmaa
d77921005a Specify that the Windows guide is for Windows 10 2020-12-16 17:38:13 +01:00
John J. Camilleri
2b6b315bd7 Add note to changelog that #87 is still pending 2020-12-07 10:35:11 +01:00
John J. Camilleri
7f6bfa730b Update changelog for 3.11 by going through all commit messages since GF-3.10 2020-12-07 10:31:19 +01:00
John J. Camilleri
d6be4ec3b0 Add note about why we're not using Setup Haskell action for Ubuntu build. 2020-11-30 23:05:43 +01:00
John J. Camilleri
68ec61f44d Remove build status badge from README
The GitHub interface now provides much richer information about build status.
2020-11-30 22:03:23 +01:00
John J. Camilleri
491084e38e Merge pull request #88 from GrammaticalFramework/build-binary-packages
Build binary packages
2020-11-30 22:00:00 +01:00
John J. Camilleri
a7a6eb5581 Update release instructions 2020-11-30 21:34:50 +01:00
John J. Camilleri
4223935b12 Combine binary workflows into one with multiple jobs 2020-11-30 20:57:20 +01:00
John J. Camilleri
8dc1ed83b6 Update RELEASE.md 2020-11-30 13:01:51 +01:00
John J. Camilleri
8f3a7a3b6a Copy things into subfolders 2020-11-27 00:51:38 +01:00
John J. Camilleri
921a8981fb Install python-devel in msys2 2020-11-27 00:11:54 +01:00
John J. Camilleri
169f2c786d Install pip in msys2 2020-11-27 00:00:44 +01:00
John J. Camilleri
629a574dfa Considerable updates to 3.11 download page 2020-11-26 23:57:09 +01:00
John J. Camilleri
6b7e9c8c7a Inherit path with Python compilation too 2020-11-26 23:40:08 +01:00
John J. Camilleri
78f42774da Inherit path when running pip 2020-11-26 23:30:47 +01:00
John J. Camilleri
54c0949354 Change echo path command in powershell 2020-11-26 23:16:15 +01:00
John J. Camilleri
0632824b99 Need to add pip to msys2 path 2020-11-26 23:02:16 +01:00
John J. Camilleri
24bbeb31df Change extra lib/include directories 2020-11-26 22:38:23 +01:00
John J. Camilleri
70811d83be Merge remote-tracking branch 'origin/master' into build-binary-packages 2020-11-25 20:57:01 +01:00
John J. Camilleri
0ed6b726a2 Add lib/include envvars for Python build 2020-11-25 20:47:47 +01:00
John J. Camilleri
88252cb107 Try build Python bindings not using msys2 2020-11-24 23:21:05 +01:00
John J. Camilleri
cf6468a452 Install Python dev tools 2020-11-24 23:03:46 +01:00
John J. Camilleri
3e1c69da21 First attempt at building Python bindings for Windows 2020-11-24 22:46:28 +01:00
John J. Camilleri
4bcde7d6a2 Copy compiled Java files from local 2020-11-24 22:09:37 +01:00
John J. Camilleri
78c1c099df Find jpgf.jar 2020-11-24 21:08:56 +01:00
John J. Camilleri
7501a7916e Copy jpgf.jar to dist 2020-11-24 20:47:09 +01:00
John J. Camilleri
32f451f1d7 Add jdk/bin to path 2020-11-24 20:29:04 +01:00
John J. Camilleri
aad2ba61d4 Move flag 2020-11-24 15:59:01 +01:00
John J. Camilleri
9932b10bf1 Add -D__int64=int64_t flag to Java Windows build 2020-11-24 15:48:22 +01:00
John J. Camilleri
f8da24c5ec Change include path when building Java bindings in Windows build 2020-11-24 15:36:13 +01:00
John J. Camilleri
951e439703 First attempt at building Java bindings 2020-11-24 13:06:13 +01:00
John J. Camilleri
08e6aca83d Windows testing... 2020-11-24 13:00:05 +01:00
John J. Camilleri
301f23ac55 Windows testing... 2020-11-24 12:58:21 +01:00
John J. Camilleri
e36b7cb044 Windows testing... 2020-11-24 12:57:24 +01:00
John J. Camilleri
9131581f03 Add windows-testing workflow 2020-11-24 12:52:21 +01:00
John J. Camilleri
d79fa6d22b Move DLLs into another folder first 2020-11-24 12:48:46 +01:00
John J. Camilleri
c8623e2be7 Try to find Java stuff 2020-11-24 12:40:42 +01:00
John J. Camilleri
59dda75f16 Find Java stuff 2020-11-24 12:30:53 +01:00
John J. Camilleri
cac65418ff Try yet another path 2020-11-24 12:28:32 +01:00
John J. Camilleri
e47ce2a28b Try another upload path 2020-11-24 12:19:25 +01:00
John J. Camilleri
9a697fbde4 Try different upload path 2020-11-24 12:10:43 +01:00
John J. Camilleri
43b06d5f53 Use windows path with upload-artifact 2020-11-24 10:41:26 +01:00
John J. Camilleri
ee6082d100 Typo 2020-11-24 10:25:04 +01:00
John J. Camilleri
4d2218a0d1 See what's in /mingw64/bin 2020-11-24 10:10:04 +01:00
John J. Camilleri
af9c8ee553 Add compiled C runtime to artifact in Windows build 2020-11-19 14:56:51 +01:00
John J. Camilleri
3e20e735a3 Install gcc in MSYS 2020-11-19 01:22:26 +01:00
John J. Camilleri
0a0060373b Flip slashes 2020-11-19 01:09:07 +01:00
John J. Camilleri
12ece26409 sudo mkdir 2020-11-19 00:58:37 +01:00
John J. Camilleri
424e6887b5 Attempt to build C runtime in Windows build using MSYS 2020-11-19 00:58:07 +01:00
John J. Camilleri
4987b70df7 Make directory first 2020-11-19 00:49:31 +01:00
John J. Camilleri
a072b4688b Create symlink to JNI headers in a place where the Java runtime makefile looks 2020-11-19 00:40:51 +01:00
John J. Camilleri
0b3ae5aaa2 Rename artifacts 2020-11-19 00:26:53 +01:00
John J. Camilleri
a48bbb3b13 Enable server, upload artifact (only exe) to Windows build 2020-11-19 00:08:07 +01:00
John J. Camilleri
131d196fad Add 'export CPPFLAGS' line to macOS build 2020-11-19 00:02:50 +01:00
John J. Camilleri
b0341ec42d Add more test commands for JNI in macOS; re-enable mac & Windows builds on push for testing 2020-11-18 23:48:20 +01:00
John J. Camilleri
293d05fde1 Install alex, happy in Windows build 2020-11-18 23:26:31 +01:00
John J. Camilleri
d39e4a22a8 Don't build binaries on push 2020-11-18 23:24:38 +01:00
John J. Camilleri
8e9212d059 First install dependencies in Windows build 2020-11-18 23:19:24 +01:00
John J. Camilleri
012541ff55 Remove locate command, which fails because of missing DB 2020-11-18 23:17:42 +01:00
John J. Camilleri
0d12c7101c Add debugging output to macOS build for locating JNI headers 2020-11-18 23:15:15 +01:00
John J. Camilleri
6ee7c88f34 Add first attempt at Windows build 2020-11-18 23:10:54 +01:00
John J. Camilleri
08af135653 Install openjdk in macOS build 2020-11-18 23:08:49 +01:00
krangelov
37c63a0c22 Merge branch 'master' of https://github.com/GrammaticalFramework/gf-core 2020-11-17 10:27:07 +01:00
krangelov
d4ccd2848c Take a step back and do bottom up prediction only when needed. This solves the problem that some sentences were impossible to parse. 2020-11-17 10:26:00 +01:00
John J. Camilleri
6862098d8b Add preliminary RELEASE.md 2020-11-17 01:07:05 +01:00
John J. Camilleri
40e5f90d56 Add stubs in download/ for 3.11. Make dowload/index.html redirect to current version. 2020-11-17 01:05:32 +01:00
John J. Camilleri
3df552eb5d Remove 'download/gfc' 2020-11-17 00:48:31 +01:00
John J. Camilleri
dbb0bcc5dd Minors in comments 2020-11-17 00:44:05 +01:00
John J. Camilleri
38facbc064 Copy package from parent dir first because upload-artifact doesn't allow .. 2020-11-17 00:16:01 +01:00
John J. Camilleri
8cc901f334 Remove txt2tags and pandoc from Debian requirements 2020-11-17 00:04:57 +01:00
John J. Camilleri
8550f8deaf Remove RGL and HTML from Debian build 2020-11-17 00:01:05 +01:00
John J. Camilleri
5a6acf1d47 Replace _ with - 2020-11-16 23:50:02 +01:00
John J. Camilleri
a7ff2d0611 Upload artifact directly without copying elsewhere in between 2020-11-16 23:41:01 +01:00
John J. Camilleri
30bcafb76f Re-enable hack for finding C runtime on macOS 2020-11-16 23:18:40 +01:00
John J. Camilleri
ce9caa2726 Install alex and happy 2020-11-16 22:54:19 +01:00
John J. Camilleri
b4ccca8c18 Build on push too 2020-11-16 22:46:04 +01:00
John J. Camilleri
2dc11524fc Remove RGL from build, use 'cabal v1-' commands 2020-11-16 22:42:13 +01:00
John J. Camilleri
feed61dd30 Change setup-haskell version to just v1 2020-11-09 22:43:06 +01:00
John J. Camilleri
1c7c52da68 Use GHC 8.4.4 2020-11-09 22:11:29 +01:00
John J. Camilleri
71b10672e8 Fix macOS version at 10.13 2020-11-09 22:09:57 +01:00
John J. Camilleri
687f56178e Use newer version of setup-haskell 2020-11-09 22:05:50 +01:00
John J. Camilleri
359f1509fa Blurt out cabal version in both action and build script 2020-11-09 21:59:05 +01:00
John J. Camilleri
b1b3bc3360 Install C runtime in two places. Use cabal v1-copy. 2020-11-09 21:40:55 +01:00
John J. Camilleri
9018eabb10 Add libtool finish command from warning 2020-11-09 21:35:17 +01:00
John J. Camilleri
ed97a42fde Try it another way round 2020-11-09 21:23:52 +01:00
John J. Camilleri
f6eb94c33b Try removing something that looks like a typo 2020-11-09 21:12:23 +01:00
John J. Camilleri
6e2f34f4d0 Try to set PREFIX env var 2020-11-09 17:52:41 +01:00
John J. Camilleri
13ec9ca888 Explicitly specify env vars when building GF (test) 2020-11-09 17:43:15 +01:00
John J. Camilleri
24619bc3ee Change cabal version to 2.4, to match GHC 8.6.5 2020-11-09 17:15:13 +01:00
John J. Camilleri
399974ebfb Fix whitespace in binary build script 2020-11-09 13:55:53 +01:00
John J. Camilleri
6836360e0c Comment cabal freeze and caching in case it was causing build error below
https://github.com/GrammaticalFramework/gf-core/runs/1374091798?check_suite_focus=true
2020-11-09 13:55:26 +01:00
John J. Camilleri
3844277a66 Install Haskell via setup-haskell action, install build tools for C runtime 2020-11-09 13:35:03 +01:00
John J. Camilleri
86729b3efc Try to install GHC/Cabal via Homebrew 2020-11-09 13:18:57 +01:00
John J. Camilleri
beb7599d33 Add first attempt at GitHub action file for building .pkg 2020-11-09 13:15:35 +01:00
Inari Listenmaa
7dc6717b5e Merge pull request #79 from anka-213/fix-infinite-loop
Fix infinite recursion on error
2020-10-27 11:23:49 +01:00
Andreas Källberg
1ff66006b8 Fix infinite recursion on error
The implementation was meant to lift from SIO to IO,
but instead it was just the identity function,
which means that `fail = id . fail` and we have an infinite loop.
2020-10-26 17:21:22 +01:00
John J. Camilleri
db5ee0b66a Merge pull request #78 from anka-213/solve-syntax-error-bug
Fix syntax error problem for older versions of GHC
2020-10-09 11:56:21 +02:00
Andreas Källberg
7b4eeb368c Make CI green
See https://github.com/joerick/cibuildwheel/issues/446
2020-10-08 21:50:12 +02:00
Andreas Källberg
f2e4b89a22 Fix syntax error problem for older versions of GHC 2020-10-08 17:41:44 +02:00
Inari Listenmaa
670a58e7e7 Merge pull request #77 from inariksit/tutorial-fixes
Minor tweaks and updates to the tutorial
2020-10-02 20:32:21 +02:00
krangelov
f3a8658cc1 Merge branch 'master' of https://github.com/GrammaticalFramework/gf-core 2020-10-02 19:55:24 +02:00
krangelov
bfb94d1e48 fix parsing with HOAS 2020-10-02 19:34:52 +02:00
Inari Listenmaa
df77205c43 (Tutorial) Rename TV (transitive verb) to V2, the name used in RGL 2020-10-02 17:58:57 +02:00
Inari Listenmaa
e41436eb14 (Tutorial) Remove reference to morpho_list + overly verbose path 2020-10-02 17:57:35 +02:00
Inari Listenmaa
2826061251 (Tutorial) Update the pre syntax 2020-10-02 17:56:24 +02:00
Inari Listenmaa
f56fbcf86e (Tutorial) Remove mentions to pt -typecheck
The GF shell no longer has `put_tree -typecheck` option, and typechecking is done automatically when parsing.

The metavariable thing is a bit unclear: you don't get it when parsing "dim the light", or "switch on the fan, but you do get it when you `gt` after adding `switchOn` and `switchOff`.

```
> p "switch on the fan"
CAction fan (switchOff fan) (DKindOne fan)
> gt
CAction light dim (DKindOne light)
CAction ?3 (switchOff ?3) (DKindOne ?3)
CAction ?3 (switchOn ?3) (DKindOne ?3)
```

My hypothesis is that you don't get metavariable when parsing e.g. "dim the light", because even though `light` is suppressed in `CAction`, it still appears in `DKindOne`, so it gets to contribute to the whole tree with its string.
2020-09-29 09:23:36 +02:00
aarneranta
2c2bd158a6 link to CoLi paper, mention of iOS 2020-09-29 09:05:15 +02:00
John J. Camilleri
d95b3efd6b Add instructions for uploading PGF2 to Hackage 2020-09-18 10:49:21 +02:00
John J. Camilleri
db8b111e72 Bump PGF2 to 1.2.1 2020-09-18 10:34:45 +02:00
John J. Camilleri
ab52572f44 Fix bug where shell commands were ignored, introduced by #71 2020-09-18 09:25:08 +02:00
John J. Camilleri
6c54e5b63c Merge pull request #71 from anka-213/fix-newer-cabal
Fix support for newer stackage snapshots
2020-09-14 22:42:37 +02:00
Andreas Källberg
8bcdeedba0 Bump default stack.yaml to ghc8.6.5 2020-09-14 17:44:23 +02:00
Andreas Källberg
7d6a115cc1 Bump stackage snapshots to latest versions 2020-09-14 15:15:23 +02:00
Andreas Källberg
127a1b2842 Remove MonadFail requirements for aeson code 2020-09-12 11:04:32 +02:00
Andreas Källberg
2fd1040724 Fix incorrect type and update dependencies 2020-09-12 11:04:32 +02:00
Andreas Källberg
340f8d9b93 First attempt at github actions for stack 2020-09-12 10:55:18 +02:00
Andreas Källberg
9d8cd55cd5 Import orphan instances of MonadFail for ghc<8
Also upgrade alex/happy so automatic install works
2020-09-09 11:05:41 +02:00
Andreas Källberg
150b592aa9 Add stack file for ghc8.8.4 2020-09-08 15:10:29 +02:00
Andreas Källberg
56f94da772 Merge remote-tracking branch 'origin/master' into fix-newer-cabal 2020-09-05 21:11:12 +02:00
Andreas Källberg
57ce76dbc1 Add two more missing MonadFail imports 2020-09-05 20:57:30 +02:00
Andreas Källberg
2b23e0f27e Fix wrong indent 2020-09-05 20:45:08 +02:00
Andreas Källberg
57c1014e9f Update package database on ubuntu build
Fixes 404 error:
https://github.com/GrammaticalFramework/gf-core/runs/1076062405
2020-09-05 20:36:04 +02:00
Andreas Källberg
7268253f5a MonadFail: Make backwards-compatible 2020-09-05 20:23:07 +02:00
Andreas Källberg
1234c715fc Fix MonadFail for c-runtime as well 2020-09-05 18:57:40 +02:00
Inari Listenmaa
bca0691cb0 (Tutorial) Minor typofixes + current error message 2020-08-31 15:54:33 +02:00
Inari Listenmaa
3de9c664fd Merge pull request #73 from inariksit/video-tutorial-page
(Homepage) Change link of video tutorials to a page + small fixes
2020-08-31 15:31:31 +02:00
Inari Listenmaa
f6560d309e (Homepage) Change link of video tutorials to a page + small fixes
Also added video tutorial link to the footer.
2020-08-30 20:53:59 +02:00
Inari Listenmaa
254f03ecfe Fix wording + formatting slightly 2020-08-30 20:38:49 +02:00
Inari Listenmaa
0bb02eeb51 Add a page for all GF video tutorials 2020-08-30 20:08:17 +02:00
Inari Listenmaa
bf21b4768c (Tutorial) Fix to make calculator example compile
In abstract: startcat needs to be defined to run the commands that are shown later in the doc.
In concrete: ss and SS are defined in Prelude.
2020-08-21 13:25:16 +02:00
Andreas Källberg
47dbf9ac27 Add stack file for a more recent ghc 2020-08-19 14:13:17 +02:00
krangelov
90fc1d750e remove the deprecated pgf_print_expr_tuple 2020-08-14 21:03:48 +02:00
krangelov
24beed9a95 Merge branch 'master' of https://github.com/GrammaticalFramework/gf-core 2020-08-14 20:56:20 +02:00
krangelov
23edeec5a9 added an API for cloning expressions/types/literals 2020-08-14 20:54:15 +02:00
Inari Listenmaa
542a41fb32 Merge pull request #70 from inariksit/haskell
New features in PGF to Haskell translation
2020-08-11 14:20:28 +02:00
Andreas Källberg
85ab6daaaa Add cabal dist-newtyle to gitignore 2020-08-05 19:09:25 +02:00
Andreas Källberg
e351e7b79a Remove NoMonadFailDesugaring flag
I've fixed so everything has the fail it needs now
2020-08-05 18:48:24 +02:00
Andreas Källberg
05903b271c Fix testsuite compatability with newer Cabal 2020-08-05 18:48:24 +02:00
Andreas Källberg
3bd1f01959 Fix a few warnings 2020-08-05 18:48:24 +02:00
Andreas Källberg
0581d6827e Fix most build errors 2020-08-05 18:48:24 +02:00
Andreas Källberg
b8812b54b2 fix newer ghc: Don't try to be backwards compatible 2020-08-05 18:48:24 +02:00
Andreas Källberg
251845f83e First attempt at fixing incompabilities with newer cabal 2020-08-05 18:48:24 +02:00
Inari Listenmaa
7c478016d0 Replace deprecated pragma with up-to-date one. (#17) 2020-08-03 19:45:20 +02:00
John J. Camilleri
deddde953f Add script for uploading PGF2 documentation to Hackage
Hackage's attempt to build the package will fail because of missing C libraries
2020-08-03 14:22:32 +02:00
John J. Camilleri
e10bb790cb Merge pull request #69 from GrammaticalFramework/pgf2-hackage
Update pgf2 metadata for uploading to Hackage

Even though this isn't able to package the C runtime itself into the Haskell package, I think these changes are still worth merging into master.
2020-08-03 10:53:51 +02:00
Inari Listenmaa
868566a319 Remove accidentally added space character in deriving clause. 2020-07-31 15:16:45 +02:00
Inari Listenmaa
aeabc955c8 Remove characters that aren't allowed in Haskell data types.
GF allows more characters in its types, as long as they are inside
single quotes. E.g. 'VP/Object' is a valid name for a GF category,
but not for a Haskell data type.
2020-07-31 15:05:46 +02:00
Inari Listenmaa
030c3bfee9 Add option "data" to Haskell options.
Imports Data.Data, all GF types derive Data, and uses DeriveDataTypeable.
2020-07-31 12:46:19 +02:00
John J. Camilleri
c53353f087 Updates to PGF2 readme 2020-07-28 22:54:34 +02:00
John J. Camilleri
f00f0cb0ef Bump pgf2 to 1.2.0 2020-07-28 22:36:49 +02:00
John J. Camilleri
22d5f31d74 Merge remote-tracking branch 'origin/master' into pgf2-hackage 2020-07-28 22:19:15 +02:00
krangelov
830dbe760d expose parseToChart via the Web API 2020-07-26 15:56:54 +02:00
krangelov
d7965d81b4 parseToChart also returns the category 2020-07-26 15:56:21 +02:00
krangelov
a2d7f1369c filter out empty brackets 2020-07-26 15:55:18 +02:00
krangelov
0cee82f715 the if is actually unnecessary 2020-07-22 16:55:21 +02:00
krangelov
7229033e42 bugfix in bracketedLinearize 2020-07-22 16:26:05 +02:00
krangelov
8bc4cc7187 added function for posting query strings. scales better than get. 2020-07-21 22:29:00 +02:00
krangelov
2b09e70b4a allow specifying content-type in ajax_http 2020-07-21 13:19:19 +02:00
John J. Camilleri
38f468eed3 (pgf2) Readme, license, changelog 2020-07-11 21:06:08 +02:00
John J. Camilleri
88a73c1d9e Bump pgf2 to 1.1.0, update README 2020-07-11 20:00:25 +02:00
krangelov
77a2630ed9 revert to using unconditional probabilities in the different lookup functions 2020-07-11 09:52:43 +02:00
John J. Camilleri
f54e54123c Merge remote-tracking branch 'origin/master' into pgf2-hackage
# Conflicts:
#	src/runtime/haskell-bind/pgf2.cabal
2020-07-08 22:07:08 +02:00
John J. Camilleri
2ac796dbbc Remove PGF from PGF2, clean up PGF2 cabal file. 2020-07-08 21:55:42 +02:00
krangelov
33818076ff drop the SG library completely. 2020-07-08 21:12:01 +02:00
John J. Camilleri
47d1da0845 Merge pull request #65 from GrammaticalFramework/build-debian-package
Build Debian package via GitHub action
2020-07-07 12:02:35 +02:00
aarneranta
8a052edca2 an attempt to solve record extension overloading bug, commented out for the moment 2020-07-06 18:01:59 +02:00
aarneranta
1360723137 fixed issue #67 on order of record fields in overloading 2020-07-06 14:27:49 +02:00
John J. Camilleri
4594c36cfb Copy packages so that upload-artifact can find them 2020-06-30 11:41:12 +02:00
John J. Camilleri
d8e88fd42a Try alternate way for uploading artifact 2020-06-30 11:25:24 +02:00
John J. Camilleri
daa2145378 Try alternate way of cloning RGL one level up 2020-06-30 11:12:10 +02:00
John J. Camilleri
398c64734c Add txt2tags and pandoc to build env 2020-06-30 10:17:34 +02:00
John J. Camilleri
eb185e5358 Add sudo to apt command
https://help.github.com/en/actions/reference/virtual-environments-for-github-hosted-runners#administrative-privileges-of-github-hosted-runners
2020-06-30 10:14:35 +02:00
John J. Camilleri
bb4ad9ec7f First attempt at GitHub action for building Debian package 2020-06-30 10:10:36 +02:00
John J. Camilleri
5777b85701 Merge pull request #62 from GrammaticalFramework/python-bindings-description
Update descriptions in Python bindings setup.py
2020-06-23 10:42:00 +02:00
John J. Camilleri
ab3c6ec4eb Update descriptions in Python bindings setup.py 2020-06-17 11:36:31 +02:00
John J. Camilleri
63a3a57620 Remove duplicate --gfo flag
Fixes #51
2020-06-16 14:59:14 +02:00
Inari Listenmaa
aa9b4d06ba Merge pull request #55 from inariksit/error-messages
Improvements in common  error messages
2020-06-16 09:50:05 +02:00
John J. Camilleri
fff19f31af Add friendly name to upload job 2020-06-15 12:53:19 +02:00
John J. Camilleri
c47f2232c5 Merge pull request #61 from miracle2k/wheels2
Fix twine upload.
2020-06-15 12:38:56 +02:00
Michael Elsdörfer
c802ec6022 Only upload to PyPI on pushes to master. 2020-06-15 11:21:35 +01:00
Michael Elsdörfer
b2e6d52509 Fix twine upload. 2020-06-15 10:57:36 +01:00
John J. Camilleri
383ff5e227 Merge pull request #60 from miracle2k/wheels
WIP: Add Github action workflow to build Python wheels.
2020-06-15 08:59:40 +02:00
Michael Elsdörfer
71a98cdf00 Merge branch 'master' into wheels 2020-06-14 17:47:39 +01:00
Michael Elsdörfer
74f3f7a384 Update documentation. 2020-06-14 17:46:06 +01:00
Inari Listenmaa
3fe8c3109f (Homepage) Add new languages in list of RGL langs 2020-06-14 17:38:50 +01:00
bc²
7abad1f4bf in Fedora install instructions, use dnf
dnf is the new yum, see https://fedoramagazine.org/5tftw-2014-06-10/
2020-06-14 17:38:50 +01:00
Michael Elsdörfer
8d4eb9288a Remove references to live PyPI. 2020-06-14 17:38:01 +01:00
Michael Elsdörfer
866e91c917 Make sure sdist is included. 2020-06-14 17:38:01 +01:00
Michael Elsdörfer
6f5e25d01d Bring back fail-fast. 2020-06-14 17:38:00 +01:00
Michael Elsdörfer
9ad7d25fb4 Add upload to PyPI step. 2020-06-14 17:38:00 +01:00
Michael Elsdörfer
958da5e5e9 Add Github action workflow to build Python wheels. 2020-06-14 17:38:00 +01:00
Inari Listenmaa
f31bccca1c (Homepage) Add new languages in list of RGL langs 2020-06-06 18:15:50 +02:00
Inari Listenmaa
de8cc02ba5 Condense the unsupported token gluing as per John's suggestion 2020-06-05 19:39:31 +02:00
Inari Listenmaa
dbc7297d80 Don't output "\n **" if helpfulMsg is empty. 2020-06-04 20:19:06 +02:00
Inari Listenmaa
414c2a1a5f Add clarification to Internal error in GeneratePMCFG 2020-06-04 19:57:55 +02:00
Inari Listenmaa
dca1fcd7fe Add clarification to Unsupported token gluing (both good and bad case) 2020-06-04 19:57:38 +02:00
Inari Listenmaa
c0714b7d33 Add clarification to "expected foo, inferred bar" type of error msgs 2020-06-04 19:57:10 +02:00
Inari Listenmaa
a4e3bce6bb Add clarification to "Pattern is not linear" error msg. 2020-06-04 19:56:31 +02:00
Inari Listenmaa
9a903c166f Add suggestions to error messages that are caused by too few/many args 2020-06-04 17:56:13 +02:00
Inari Listenmaa
4414c3a9c8 Merge pull request #54 from odanoburu/patch-1
in Fedora install instructions, use dnf
2020-06-03 07:00:26 +02:00
bc²
11201d8645 in Fedora install instructions, use dnf
dnf is the new yum, see https://fedoramagazine.org/5tftw-2014-06-10/
2020-06-02 20:54:15 -03:00
John J. Camilleri
5846622c4d Homepage: fix some spacing, add RGL browser, add news about GFSS 2020 2020-06-01 11:18:06 +02:00
John J. Camilleri
d8e543a4e6 Add link to Inari's video tutorial from homepage 2020-06-01 09:44:38 +02:00
krangelov
0a915199e8 allow literals in the C shell 2020-05-20 20:18:47 +02:00
krangelov
165c5a6d9d bugfix in parsing literals 2020-05-20 19:57:33 +02:00
krangelov
0ad1c352fe expose lookupCohorts in Python 2020-05-20 16:12:50 +02:00
krangelov
48d3973daa fix the uggly typo that broke the literals. 2020-05-20 10:15:53 +02:00
krangelov
9a1f982b14 split unknown words by spaces 2020-05-16 08:32:00 +02:00
krangelov
e8653135d4 Merge branch 'master' of https://github.com/GrammaticalFramework/gf-core 2020-05-14 15:05:13 +02:00
krangelov
62bc78380e lookupCohorts now detects and reports unknown words. Also:
- added added two filtering functions: filterLongest and filterBest
 - updated the PGF service to work with the new API
2020-05-14 15:03:30 +02:00
Inari Listenmaa
dda348776e Add Lauri Alanko to the list of contributors 2020-05-11 13:32:26 +02:00
aarneranta
65c810f085 accepting gf-ud style abslabels in gf-core ; cnclabels TODO 2020-05-05 15:46:48 +02:00
Krasimir Angelov
b962bcd178 Merge pull request #50 from jdahlin/patch-1
Expose PGF/Concr/Iter/Bracket
2020-04-02 09:14:53 +02:00
Johan Dahlin
589c358389 Expose PGF/Concr/Iter/Bracket
Expose the remaining types in the module.

These are helpful for example in type annotations.
2020-04-01 21:37:13 -03:00
krangelov
57a1ea5b56 forgot the conversion of the annotation string to jstring 2020-04-01 16:26:03 +02:00
krangelov
762d83c1f0 switch off the debugger 2020-03-25 20:03:06 +01:00
krangelov
733fdac755 restore the sequence ordering after -optimize-pgf 2020-03-15 19:57:47 +01:00
krangelov
00e25d0ccb an API to access the names of all fields withing a category 2020-03-06 12:29:08 +01:00
krangelov
9806232532 fix the build after the change in the morphological API 2020-03-05 12:24:01 +01:00
krangelov
88f76ef671 lookup_morpho, lookup_cohorts and fullform_lexicon now report the usual conditional probability. This turns out to be more useful for part of speech tagging 2020-03-05 12:04:42 +01:00
krangelov
f22bd70585 The APIs for callbacks and the bracketed strings now use a string for the analysis intead of an integer. This is now consistent with lookupMorpho and friends 2020-03-05 11:58:21 +01:00
krangelov
3133900125 another bug related to mattern matching on multiword expression 2020-02-18 15:07:47 +01:00
krangelov
e15392e579 fix: pattern matching on strings should reconstruct the tokens after matching 2020-02-17 19:29:36 +01:00
krangelov
9604a6309c fix the compilation of case insensitive grammars 2020-02-17 12:40:14 +01:00
krangelov
98a18843da support command c-lookupCohorts 2020-02-13 14:51:03 +01:00
krangelov
61641e7a59 support post requests to the server 2020-02-13 14:50:23 +01:00
krangelov
c50df37144 rename the WordNet module when creating a new language 2020-01-28 21:12:28 +01:00
krangelov
34fd18ea96 added link to WordNet 2020-01-28 15:33:23 +01:00
krangelov
65024a0a55 added plugin for search in WordNet 2020-01-24 18:22:00 +01:00
krangelov
4b67949d36 Merge branch 'master' of https://github.com/GrammaticalFramework/gf-core 2020-01-17 12:42:40 +01:00
krangelov
2ab9fee8e4 Python 3 literal callbacks will receive offsets in number of characters instead of bytes 2020-01-17 12:41:54 +01:00
Inari Listenmaa
f4d9b534dc Remove outdated advice on producing Haskell file 2019-12-12 16:13:47 +01:00
krangelov
14f394c9e9 a version of the parser which returns a chart rather than a list of expressions 2019-12-07 22:00:39 +01:00
krangelov
dbb09cc689 remove bogus comment 2019-12-07 21:59:41 +01:00
krangelov
bb298fadbe silence warnings in the Python bindings 2019-12-07 10:27:06 +01:00
Thomas Hallgren
f1f47f7281 GF cloud: GFMorpho: responsive layout improvement for small screens 2019-12-03 17:07:20 +01:00
Thomas Hallgren
fb1199c49c GF Cloud: add Word inflection with smart paradigms
This is a reimplemention of Aarne's GFMorpho service from 2012, using
the GF shell web API. Not all features are implemented (yet).
2019-12-03 16:40:21 +01:00
Thomas Hallgren
12e55c93c0 Fix another build problem in bin/build-binary-dist.sh
Make sure the dynamic C runtime libraries are found when running GF to
compile the RGL
2019-11-27 14:31:45 +01:00
Thomas Hallgren
33aeb53f7a PGFService: userLanguage now defaults to English, if present in the grammar
The userLangauge is the name of the concrete syntax that has a languageCode
that matches the user's preferred language, as reported by the web browser.
If no matching language code is found, the PGF service now sets userLanguage
to the concrete syntax for English (e.g. FoodsEng) if present, and defaults
to the first concrete syntax (e.g. FoodsAfr) only if English is not present
in the grammar.
2019-11-26 15:27:02 +01:00
Thomas Hallgren
e6b33ac8b8 Minibar: make it possible to configure a list of preferred grammars
A preferred grammar is selected when a user visits the Minibar for the
first time. (Like before, Minibar remembers the selected grammar for future
visits.)

A preferred list of grammars can be specified in config.js in the .../minibar
directory on the server, e.g. like this:

  preferred_grammars=["/grammars/Foods.pgf","/grammars/ResourceDemo.pgf"]

The first available grammar from the list is used.
2019-11-21 14:25:07 +01:00
Thomas Hallgren
14e5528544 Fix build problems, bump versiom to gf-3.10.4-git
debian/rules and bin/build-binary-dist.sh needed to be adepted to changes
in how INSTALLPATH is used in src/runtime/java/Makefile.
2019-11-18 15:54:44 +01:00
Thomas Hallgren
28f53e801a PGFService: revert unlexing change in PGFService to restore &+ behaviour 2019-11-18 13:20:41 +01:00
aarneranta
6f2b1a83b7 fixed a vd bug that sometimes erased the root label 2019-11-13 11:40:37 +01:00
aarneranta
d3b501d35f fixed the problem with generating several roots in ud2gf. Now only the leftmost word becomes ROOT, the others become dep - which can be eliminated by cnclabels. This works fine for e.g. English prepositional and particle verbs. But it does not work if the 'main' word is not the leftmost one 2019-11-12 17:46:55 +01:00
krangelov
95b3fb306f forgot that debugging is on 2019-10-09 14:34:04 +02:00
krangelov
5b790b82c5 fix chunk extraction when there are literals 2019-10-09 14:32:20 +02:00
krangelov
26361b3692 fix the parsing for literals after the latest changes in the parser 2019-10-09 14:18:05 +02:00
krangelov
30eef61f0a more dead code 2019-09-20 16:15:28 +02:00
429 changed files with 324945 additions and 57009 deletions

View File

@@ -0,0 +1,95 @@
# 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: ["3.2"]
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: actions/setup-haskell@v1.1.4
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: ["2.3.3"]
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: actions/setup-haskell@v1.1.4
name: Setup Haskell Stack
with:
# ghc-version: ${{ matrix.ghc }}
stack-version: ${{ matrix.stack }}
- 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

View File

@@ -0,0 +1,185 @@
name: Build Binary Packages
on:
workflow_dispatch:
release:
jobs:
# ---
ubuntu:
name: Build Ubuntu package
runs-on: ubuntu-18.04
# strategy:
# matrix:
# ghc: ["8.6.5"]
# cabal: ["2.4"]
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 }}-ubuntu
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
- name: Build Java bindings
shell: msys2 {0}
run: |
export PATH="${PATH}:/c/Program Files/Java/jdk8u275-b01/bin"
cd src/runtime/java
make \
JNI_INCLUDES="-I \"/c/Program Files/Java/jdk8u275-b01/include\" -I \"/c/Program Files/Java/jdk8u275-b01/include/win32\" -I \"/mingw64/include\" -D__int64=int64_t" \
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.8/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

View 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@master
- 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/*

8
.gitignore vendored
View File

@@ -5,7 +5,15 @@
*.jar *.jar
*.gfo *.gfo
*.pgf *.pgf
*.lpgf
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

View File

@@ -2,8 +2,6 @@
# Grammatical Framework (GF) # Grammatical Framework (GF)
[![Build Status](https://travis-ci.org/GrammaticalFramework/gf-core.svg?branch=master)](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:

64
RELEASE.md Normal file
View File

@@ -0,0 +1,64 @@
# 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
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.

View File

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

View File

@@ -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,11 +42,11 @@ 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"
ln "$destdir$prefix/lib/python$pyver/site-packages"/pgf* "$pydest" ln "$destdir$prefix/lib/python$pyver/site-packages"/pgf* "$pydest"
fi fi
popd popd
else else
@@ -53,52 +57,42 @@ 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
pkgbuild --identifier org.grammaticalframework.gf.pkg --version "$ver" --root "$destdir" --install-location / dist/$pkg pkgbuild --identifier org.grammaticalframework.gf.pkg --version "$ver" --root "$destdir" --install-location / dist/$pkg
echo "Created $pkg" echo "Created $pkg"
esac esac
## Cleanup
rm -r "$destdir" rm -r "$destdir"

View File

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

View File

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

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

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

12
debian/rules vendored
View File

@@ -24,19 +24,15 @@ 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 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 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
View 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

View File

@@ -391,6 +391,8 @@ bindings are found in the ``src/runtime/python`` and ``src/runtime/java``
directories, respecively. Compile them by following the instructions in directories, respecively. Compile them by following the instructions in
the ``INSTALL`` files in those directories. the ``INSTALL`` files in those directories.
The Python library can also be installed from PyPI using `pip install pgf`.
== Compilation of RGL == == Compilation of RGL ==
As of 2018-07-26, the RGL is distributed separately from the GF compiler and runtimes. As of 2018-07-26, the RGL is distributed separately from the GF compiler and runtimes.

View File

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

View File

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

View File

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

View File

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

View File

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

182
download/index-3.11.md Normal file
View File

@@ -0,0 +1,182 @@
---
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 release from source
[GF is on Hackage](http://hackage.haskell.org/package/gf), so under
normal circumstances the procedure is fairly simple:
1. Install a recent version of the [Haskell Platform](http://hackage.haskell.org/platform) (see note below)
2. `cabal update`
3. On Linux: install some C libraries from your Linux distribution (see note below)
4. `cabal install gf`
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
```
**Build tools**
In order to compile GF you need the build tools **Alex** and **Happy**.
These can be installed via Cabal, e.g.:
```
cabal install alex happy
```
or obtained by other means, depending on your OS.
**Haskeline**
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
View 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>

40
download/release-3.11.md Normal file
View File

@@ -0,0 +1,40 @@
---
title: GF 3.11 Release Notes
date: ... December 2020
...
## 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 400 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.
- Updates to build scripts and CI.
- Bug fixes.
## GF compiler and run-time library
- Huge improvements in time & space requirements for grammar compilation (pending [#87](https://github.com/GrammaticalFramework/gf-core/pull/87)).
- Add CoNLL output to `visualize_tree` shell command.
- Add 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 to Haskell export.
- 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.

555
gf.cabal
View File

@@ -1,5 +1,5 @@
name: gf name: gf
version: 3.10.3-git version: 3.10.4-git
cabal-version: >= 1.22 cabal-version: >= 1.22
build-type: Custom build-type: Custom
@@ -47,10 +47,6 @@ custom-setup
filepath, filepath,
process >=1.0.1.1 process >=1.0.1.1
--source-repository head
-- type: darcs
-- location: http://www.grammaticalframework.org/
source-repository head source-repository head
type: git type: git
location: https://github.com/GrammaticalFramework/gf-core.git location: https://github.com/GrammaticalFramework/gf-core.git
@@ -67,12 +63,17 @@ flag network-uri
description: Get Network.URI from the network-uri package description: Get Network.URI from the network-uri package
default: True default: True
executable gf --flag new-comp
hs-source-dirs: src/programs -- Description: Make -new-comp the default
main-is: gf-main.hs -- Default: True
flag c-runtime
Description: Include functionality from the C run-time library (which must be installed already)
Default: False
Library
default-language: Haskell2010 default-language: Haskell2010
build-depends: pgf2, build-depends: base >= 4.6 && <5,
base >= 4.6 && <5,
array, array,
containers, containers,
bytestring, bytestring,
@@ -81,27 +82,85 @@ executable gf
pretty, pretty,
mtl, mtl,
exceptions, exceptions,
fail,
-- For compatability with ghc < 8
-- We need transformers-compat >= 0.6.3, but that is only in newer snapshots where it is redundant.
transformers-compat,
ghc-prim, ghc-prim,
filepath, directory>=1.2, time, text,
process, haskeline, parallel>=3, json hashable,
ghc-options: -threaded unordered-containers
hs-source-dirs: src/runtime/haskell
if impl(ghc>=7.0)
ghc-options: -rtsopts -with-rtsopts=-I5
if impl(ghc<7.8)
ghc-options: -with-rtsopts=-K64M
ghc-prof-options: -auto-all
hs-source-dirs: src/compiler
other-modules: other-modules:
-- not really part of GF but I have changed the original binary library
-- and we have to keep the copy for now.
Data.Binary
Data.Binary.Put
Data.Binary.Get
Data.Binary.Builder
Data.Binary.IEEE754
--ghc-options: -fwarn-unused-imports
--if impl(ghc>=7.8)
-- ghc-options: +RTS -A20M -RTS
ghc-prof-options: -fprof-auto
exposed-modules:
PGF
PGF.Internal
PGF.Haskell
LPGF
other-modules:
PGF.Data
PGF.Macros
PGF.Binary
PGF.Optimize
PGF.Printer
PGF.CId
PGF.Expr
PGF.Generate
PGF.Linearize
PGF.Morphology
PGF.Paraphrase
PGF.Parse
PGF.Probabilistic
PGF.SortTop
PGF.Tree
PGF.Type
PGF.TypeCheck
PGF.Forest
PGF.TrieMap
PGF.VisualizeTree
PGF.ByteCode
PGF.OldBinary
PGF.Utilities
if flag(c-runtime)
exposed-modules: PGF2
other-modules: PGF2.FFI PGF2.Expr PGF2.Type
GF.Interactive2 GF.Command.Commands2
hs-source-dirs: src/runtime/haskell-bind
build-tools: hsc2hs
extra-libraries: pgf gu
c-sources: src/runtime/haskell-bind/utils.c
cc-options: -std=c99
---- GF compiler as a library:
build-depends: filepath, directory>=1.2, time,
process, haskeline, parallel>=3, json
hs-source-dirs: src/compiler
exposed-modules:
GF GF
GF.Support GF.Support
GF.Text.Pretty GF.Text.Pretty
GF.Text.Lexing GF.Text.Lexing
GF.Grammar.Canonical GF.Grammar.Canonical
other-modules:
GF.Main GF.Compiler GF.Interactive GF.Main GF.Compiler GF.Interactive
GF.Compile GF.CompileInParallel GF.CompileOne GF.Compile.GetGrammar GF.Compile GF.CompileInParallel GF.CompileOne GF.Compile.GetGrammar
@@ -122,7 +181,6 @@ executable gf
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.ConcreteNew GF.Compile.Compute.ConcreteNew
GF.Compile.Compute.Predef GF.Compile.Compute.Predef
GF.Compile.Compute.Value GF.Compile.Compute.Value
@@ -130,17 +188,20 @@ executable gf
GF.Compile.Export GF.Compile.Export
GF.Compile.GenerateBC GF.Compile.GenerateBC
GF.Compile.GeneratePMCFG GF.Compile.GeneratePMCFG
GF.Compile.GrammarToLPGF
GF.Compile.GrammarToPGF GF.Compile.GrammarToPGF
GF.Compile.Multi GF.Compile.Multi
GF.Compile.Optimize GF.Compile.Optimize
GF.Compile.OptimizePGF
GF.Compile.PGFtoHaskell GF.Compile.PGFtoHaskell
GF.Compile.PGFtoJava GF.Compile.PGFtoJava
GF.Haskell GF.Haskell
GF.Compile.ConcreteToHaskell GF.Compile.ConcreteToHaskell
GF.Compile.GrammarToCanonical GF.Compile.GrammarToCanonical
GF.Grammar.CanonicalJSON GF.Grammar.CanonicalJSON
GF.Compile.PGFtoJS
GF.Compile.PGFtoJSON GF.Compile.PGFtoJSON
GF.Compile.PGFtoProlog
GF.Compile.PGFtoPython
GF.Compile.ReadFiles GF.Compile.ReadFiles
GF.Compile.Rename GF.Compile.Rename
GF.Compile.SubExOpt GF.Compile.SubExOpt
@@ -157,6 +218,7 @@ executable gf
GF.Data.ErrM GF.Data.ErrM
GF.Data.Graph GF.Data.Graph
GF.Data.Graphviz GF.Data.Graphviz
GF.Data.IntMapBuilder
GF.Data.Relation GF.Data.Relation
GF.Data.Str GF.Data.Str
GF.Data.Utilities GF.Data.Utilities
@@ -210,17 +272,11 @@ executable gf
GF.System.Signal GF.System.Signal
GF.Text.Clitics GF.Text.Clitics
GF.Text.Coding GF.Text.Coding
GF.Text.Lexing
GF.Text.Transliterations GF.Text.Transliterations
Paths_gf Paths_gf
-- not really part of GF but I have changed the original binary library if flag(c-runtime)
-- and we have to keep the copy for now. cpp-options: -DC_RUNTIME
Data.Binary
Data.Binary.Put
Data.Binary.Get
Data.Binary.Builder
Data.Binary.IEEE754
if flag(server) if flag(server)
build-depends: httpd-shed>=0.4.0.3, network>=2.3 && <2.7, build-depends: httpd-shed>=0.4.0.3, network>=2.3 && <2.7,
@@ -243,6 +299,8 @@ executable gf
CGIUtils CGIUtils
Cache Cache
Fold Fold
ExampleDemo
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)
@@ -253,6 +311,7 @@ executable gf
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
else else
build-tools: happy, alex>=3 build-tools: happy, alex>=3
@@ -263,13 +322,36 @@ executable gf
else else
build-depends: unix, terminfo>=0.4 build-depends: unix, terminfo>=0.4
if impl(ghc>=8.2)
ghc-options: -fhide-source-paths
test-suite rgl-tests Executable gf
type: exitcode-stdio-1.0 hs-source-dirs: src/programs
main-is: run.hs main-is: gf-main.hs
hs-source-dirs: lib/tests/
build-depends: base, HTF, process, HUnit, filepath, directory
default-language: Haskell2010 default-language: Haskell2010
build-depends: gf, base
ghc-options: -threaded
--ghc-options: -fwarn-unused-imports
if impl(ghc>=7.0)
ghc-options: -rtsopts -with-rtsopts=-I5
if impl(ghc<7.8)
ghc-options: -with-rtsopts=-K64M
ghc-prof-options: -auto-all
if impl(ghc>=8.2)
ghc-options: -fhide-source-paths
executable pgf-shell
--if !flag(c-runtime)
buildable: False
main-is: pgf-shell.hs
hs-source-dirs: src/runtime/haskell-bind/examples
build-depends: gf, base, containers, mtl, lifted-base
default-language: Haskell2010
if impl(ghc>=7.0)
ghc-options: -rtsopts
test-suite gf-tests test-suite gf-tests
type: exitcode-stdio-1.0 type: exitcode-stdio-1.0
@@ -277,3 +359,402 @@ test-suite gf-tests
hs-source-dirs: testsuite hs-source-dirs: testsuite
build-depends: base>=4.3 && <5, Cabal>=1.8, directory, filepath, process build-depends: base>=4.3 && <5, Cabal>=1.8, directory, filepath, process
default-language: Haskell2010 default-language: Haskell2010
test-suite lpgf
type: exitcode-stdio-1.0
main-is: test.hs
hs-source-dirs:
src/compiler
src/runtime/haskell
testsuite/lpgf
other-modules:
Data.Binary
Data.Binary.Builder
Data.Binary.Get
Data.Binary.IEEE754
Data.Binary.Put
GF
GF.Command.Abstract
GF.Command.CommandInfo
GF.Command.Commands
GF.Command.CommonCommands
GF.Command.Help
GF.Command.Importing
GF.Command.Interpreter
GF.Command.Messages
GF.Command.Parse
GF.Command.SourceCommands
GF.Command.TreeOperations
GF.Compile
GF.Compile.CFGtoPGF
GF.Compile.CheckGrammar
GF.Compile.Compute.ConcreteNew
GF.Compile.Compute.Predef
GF.Compile.Compute.Value
GF.Compile.ConcreteToHaskell
GF.Compile.ExampleBased
GF.Compile.Export
GF.Compile.GenerateBC
GF.Compile.GeneratePMCFG
GF.Compile.GetGrammar
GF.Compile.GrammarToCanonical
GF.Compile.GrammarToLPGF
GF.Compile.GrammarToPGF
GF.Compile.Multi
GF.Compile.Optimize
GF.Compile.PGFtoHaskell
GF.Compile.PGFtoJava
GF.Compile.PGFtoJS
GF.Compile.PGFtoJSON
GF.Compile.PGFtoProlog
GF.Compile.PGFtoPython
GF.Compile.ReadFiles
GF.Compile.Rename
GF.Compile.SubExOpt
GF.Compile.Tags
GF.Compile.ToAPI
GF.Compile.TypeCheck.Abstract
GF.Compile.TypeCheck.ConcreteNew
GF.Compile.TypeCheck.Primitives
GF.Compile.TypeCheck.RConcrete
GF.Compile.TypeCheck.TC
GF.Compile.Update
GF.CompileInParallel
GF.CompileOne
GF.Compiler
GF.Data.BacktrackM
GF.Data.ErrM
GF.Data.Graph
GF.Data.Graphviz
GF.Data.IntMapBuilder
GF.Data.Operations
GF.Data.Relation
GF.Data.Str
GF.Data.Utilities
GF.Data.XML
GF.Grammar
GF.Grammar.Analyse
GF.Grammar.Binary
GF.Grammar.BNFC
GF.Grammar.Canonical
GF.Grammar.CanonicalJSON
GF.Grammar.CFG
GF.Grammar.EBNF
GF.Grammar.Grammar
GF.Grammar.Lexer
GF.Grammar.Lockfield
GF.Grammar.Lookup
GF.Grammar.Macros
GF.Grammar.Parser
GF.Grammar.PatternMatch
GF.Grammar.Predef
GF.Grammar.Printer
GF.Grammar.ShowTerm
GF.Grammar.Unify
GF.Grammar.Values
GF.Haskell
GF.Infra.BuildInfo
GF.Infra.CheckM
GF.Infra.Concurrency
GF.Infra.Dependencies
GF.Infra.GetOpt
GF.Infra.Ident
GF.Infra.Location
GF.Infra.Option
GF.Infra.SIO
GF.Infra.UseIO
GF.Interactive
GF.JavaScript.AbsJS
GF.JavaScript.PrintJS
GF.Main
GF.Quiz
GF.Speech.CFGToFA
GF.Speech.FiniteState
GF.Speech.GSL
GF.Speech.JSGF
GF.Speech.PGFToCFG
GF.Speech.PrRegExp
GF.Speech.RegExp
GF.Speech.SISR
GF.Speech.SLF
GF.Speech.SRG
GF.Speech.SRGS_ABNF
GF.Speech.SRGS_XML
GF.Speech.VoiceXML
GF.Support
GF.System.Catch
GF.System.Concurrency
GF.System.Console
GF.System.Directory
GF.System.Process
GF.System.Signal
GF.Text.Clitics
GF.Text.Coding
GF.Text.Lexing
GF.Text.Pretty
GF.Text.Transliterations
LPGF
PGF
PGF.Binary
PGF.ByteCode
PGF.CId
PGF.Data
PGF.Expr
PGF.Forest
PGF.Generate
PGF.Internal
PGF.Linearize
PGF.Macros
PGF.Morphology
PGF.OldBinary
PGF.Optimize
PGF.Paraphrase
PGF.Parse
PGF.Printer
PGF.Probabilistic
PGF.Tree
PGF.TrieMap
PGF.Type
PGF.TypeCheck
PGF.Utilities
PGF.VisualizeTree
Paths_gf
if flag(interrupt)
cpp-options: -DUSE_INTERRUPT
other-modules: GF.System.UseSignal
else
other-modules: GF.System.NoSignal
build-depends:
ansi-terminal,
array,
base>=4.6 && <5,
bytestring,
containers,
directory,
filepath,
ghc-prim,
hashable,
haskeline,
json,
mtl,
parallel>=3,
pretty,
process,
random,
terminfo,
text,
time,
transformers-compat,
unix,
unordered-containers,
utf8-string
default-language: Haskell2010
benchmark lpgf-bench
type: exitcode-stdio-1.0
main-is: bench.hs
hs-source-dirs:
src/compiler
src/runtime/haskell
testsuite/lpgf
other-modules:
Data.Binary
Data.Binary.Builder
Data.Binary.Get
Data.Binary.IEEE754
Data.Binary.Put
GF
GF.Command.Abstract
GF.Command.CommandInfo
GF.Command.Commands
GF.Command.CommonCommands
GF.Command.Help
GF.Command.Importing
GF.Command.Interpreter
GF.Command.Messages
GF.Command.Parse
GF.Command.SourceCommands
GF.Command.TreeOperations
GF.Compile
GF.Compile.CFGtoPGF
GF.Compile.CheckGrammar
GF.Compile.Compute.ConcreteNew
GF.Compile.Compute.Predef
GF.Compile.Compute.Value
GF.Compile.ConcreteToHaskell
GF.Compile.ExampleBased
GF.Compile.Export
GF.Compile.GenerateBC
GF.Compile.GeneratePMCFG
GF.Compile.GetGrammar
GF.Compile.GrammarToCanonical
GF.Compile.GrammarToLPGF
GF.Compile.GrammarToPGF
GF.Compile.Multi
GF.Compile.Optimize
GF.Compile.PGFtoHaskell
GF.Compile.PGFtoJS
GF.Compile.PGFtoJSON
GF.Compile.PGFtoJava
GF.Compile.PGFtoProlog
GF.Compile.PGFtoPython
GF.Compile.ReadFiles
GF.Compile.Rename
GF.Compile.SubExOpt
GF.Compile.Tags
GF.Compile.ToAPI
GF.Compile.TypeCheck.Abstract
GF.Compile.TypeCheck.ConcreteNew
GF.Compile.TypeCheck.Primitives
GF.Compile.TypeCheck.RConcrete
GF.Compile.TypeCheck.TC
GF.Compile.Update
GF.CompileInParallel
GF.CompileOne
GF.Compiler
GF.Data.BacktrackM
GF.Data.ErrM
GF.Data.Graph
GF.Data.Graphviz
GF.Data.IntMapBuilder
GF.Data.Operations
GF.Data.Relation
GF.Data.Str
GF.Data.Utilities
GF.Data.XML
GF.Grammar
GF.Grammar.Analyse
GF.Grammar.BNFC
GF.Grammar.Binary
GF.Grammar.CFG
GF.Grammar.Canonical
GF.Grammar.CanonicalJSON
GF.Grammar.EBNF
GF.Grammar.Grammar
GF.Grammar.Lexer
GF.Grammar.Lockfield
GF.Grammar.Lookup
GF.Grammar.Macros
GF.Grammar.Parser
GF.Grammar.PatternMatch
GF.Grammar.Predef
GF.Grammar.Printer
GF.Grammar.ShowTerm
GF.Grammar.Unify
GF.Grammar.Values
GF.Haskell
GF.Infra.BuildInfo
GF.Infra.CheckM
GF.Infra.Concurrency
GF.Infra.Dependencies
GF.Infra.GetOpt
GF.Infra.Ident
GF.Infra.Location
GF.Infra.Option
GF.Infra.SIO
GF.Infra.UseIO
GF.Interactive
GF.JavaScript.AbsJS
GF.JavaScript.PrintJS
GF.Main
GF.Quiz
GF.Speech.CFGToFA
GF.Speech.FiniteState
GF.Speech.GSL
GF.Speech.JSGF
GF.Speech.PGFToCFG
GF.Speech.PrRegExp
GF.Speech.RegExp
GF.Speech.SISR
GF.Speech.SLF
GF.Speech.SRG
GF.Speech.SRGS_ABNF
GF.Speech.SRGS_XML
GF.Speech.VoiceXML
GF.Support
GF.System.Catch
GF.System.Concurrency
GF.System.Console
GF.System.Directory
GF.System.Process
GF.System.Signal
GF.Text.Clitics
GF.Text.Coding
GF.Text.Lexing
GF.Text.Pretty
GF.Text.Transliterations
LPGF
PGF
PGF.Binary
PGF.ByteCode
PGF.CId
PGF.Data
PGF.Expr
PGF.Expr
PGF.Forest
PGF.Generate
PGF.Internal
PGF.Linearize
PGF.Macros
PGF.Morphology
PGF.OldBinary
PGF.Optimize
PGF.Paraphrase
PGF.Parse
PGF.Printer
PGF.Probabilistic
PGF.Tree
PGF.TrieMap
PGF.Type
PGF.TypeCheck
PGF.Utilities
PGF.VisualizeTree
PGF2
PGF2.Expr
PGF2.Type
PGF2.FFI
Paths_gf
if flag(interrupt)
cpp-options: -DUSE_INTERRUPT
other-modules: GF.System.UseSignal
else
other-modules: GF.System.NoSignal
hs-source-dirs:
src/runtime/haskell-bind
other-modules:
PGF2
PGF2.FFI
PGF2.Expr
PGF2.Type
build-tools: hsc2hs
extra-libraries: pgf gu
c-sources: src/runtime/haskell-bind/utils.c
cc-options: -std=c99
build-depends:
ansi-terminal,
array,
base>=4.6 && <5,
bytestring,
containers,
deepseq,
directory,
filepath,
ghc-prim,
hashable,
haskeline,
json,
mtl,
parallel>=3,
pretty,
process,
random,
terminfo,
text,
time,
transformers-compat,
unix,
unordered-containers,
utf8-string
default-language: Haskell2010

View File

@@ -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&nbsp;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>
@@ -222,6 +228,14 @@ 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-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 &ndash; 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), 314 December 2018 <a href="//school.grammaticalframework.org/2018/">Sixth GF Summer School</a> in Stellenbosch (South Africa), 314 December 2018
@@ -324,9 +338,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 +354,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 +372,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,

View File

@@ -1,6 +1,6 @@
module GF.Command.Abstract(module GF.Command.Abstract,Expr,showExpr,Term) where module GF.Command.Abstract(module GF.Command.Abstract,Expr,showExpr,Term) where
import PGF2(Expr,showExpr) import PGF(CId,mkCId,Expr,showExpr)
import GF.Grammar.Grammar(Term) import GF.Grammar.Grammar(Term)
type Ident = String type Ident = String
@@ -11,7 +11,7 @@ type Pipe = [Command]
data Command data Command
= Command Ident [Option] Argument = Command Ident [Option] Argument
deriving Show deriving (Eq,Ord,Show)
data Option data Option
= OOpt Ident = OOpt Ident
@@ -29,7 +29,13 @@ data Argument
| ATerm Term | ATerm Term
| ANoArg | ANoArg
| AMacro Ident | AMacro Ident
deriving Show deriving (Eq,Ord,Show)
valCIdOpts :: String -> CId -> [Option] -> CId
valCIdOpts flag def opts =
case [v | OFlag f (VId v) <- opts, f == flag] of
(v:_) -> mkCId v
_ -> def
valIntOpts :: String -> Int -> [Option] -> Int valIntOpts :: String -> Int -> [Option] -> Int
valIntOpts flag def opts = valIntOpts flag def opts =
@@ -43,18 +49,6 @@ valStrOpts flag def opts =
v:_ -> valueString v v:_ -> valueString v
_ -> def _ -> def
maybeIntOpts :: String -> a -> (Int -> a) -> [Option] -> a
maybeIntOpts flag def fn opts =
case [v | OFlag f (VInt v) <- opts, f == flag] of
(v:_) -> fn v
_ -> def
maybeStrOpts :: String -> a -> (String -> a) -> [Option] -> a
maybeStrOpts flag def fn opts =
case listFlags flag opts of
v:_ -> fn (valueString v)
_ -> def
listFlags flag opts = [v | OFlag f v <- opts, f == flag] listFlags flag opts = [v | OFlag f v <- opts, f == flag]
valueString v = valueString v =

View File

@@ -3,7 +3,8 @@ import GF.Command.Abstract(Option,Expr,Term)
import GF.Text.Pretty(render) import GF.Text.Pretty(render)
import GF.Grammar.Printer() -- instance Pretty Term import GF.Grammar.Printer() -- instance Pretty Term
import GF.Grammar.Macros(string2term) import GF.Grammar.Macros(string2term)
import PGF2(mkStr,unStr,showExpr) import qualified PGF as H(showExpr)
import qualified PGF.Internal as H(Literal(LStr),Expr(ELit)) ----
data CommandInfo m = CommandInfo { data CommandInfo m = CommandInfo {
exec :: [Option] -> CommandArguments -> m CommandOutput, exec :: [Option] -> CommandArguments -> m CommandOutput,
@@ -37,19 +38,21 @@ class Monad m => TypeCheckArg m where typeCheckArg :: Expr -> m Expr
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
data CommandArguments = Exprs [(Expr,Float)] | Strings [String] | Term Term data CommandArguments = Exprs [Expr] | Strings [String] | Term Term
newtype CommandOutput = Piped (CommandArguments,String) ---- errors, etc newtype CommandOutput = Piped (CommandArguments,String) ---- errors, etc
-- ** Converting command output -- ** Converting command output
fromStrings ss = Piped (Strings ss, unlines ss) fromStrings ss = Piped (Strings ss, unlines ss)
fromExprs show_p es = Piped (Exprs es,unlines (map (\(e,p) -> (if show_p then (++) ("["++show p++"] ") else id) (showExpr [] e)) es)) fromExprs es = Piped (Exprs es,unlines (map (H.showExpr []) es))
fromString s = Piped (Strings [s], s) fromString s = Piped (Strings [s], s)
pipeWithMessage es msg = Piped (Exprs es,msg) pipeWithMessage es msg = Piped (Exprs es,msg)
pipeMessage msg = Piped (Exprs [],msg) pipeMessage msg = Piped (Exprs [],msg)
pipeExprs es = Piped (Exprs es,[]) -- only used in emptyCommandInfo pipeExprs es = Piped (Exprs es,[]) -- only used in emptyCommandInfo
void = Piped (Exprs [],"") void = Piped (Exprs [],"")
stringAsExpr = H.ELit . H.LStr -- should be a pattern macro
-- ** Converting command input -- ** Converting command input
toStrings args = toStrings args =
@@ -58,23 +61,23 @@ toStrings args =
Exprs es -> zipWith showAsString (True:repeat False) es Exprs es -> zipWith showAsString (True:repeat False) es
Term t -> [render t] Term t -> [render t]
where where
showAsString first (e,p) = showAsString first t =
case unStr e of case t of
Just s -> s H.ELit (H.LStr s) -> s
Nothing -> ['\n'|not first] ++ _ -> ['\n'|not first] ++
showExpr [] e ---newline needed in other cases than the first H.showExpr [] t ---newline needed in other cases than the first
toExprs args = toExprs args =
case args of case args of
Exprs es -> map fst es Exprs es -> es
Strings ss -> map mkStr ss Strings ss -> map stringAsExpr ss
Term t -> [mkStr (render t)] Term t -> [stringAsExpr (render t)]
toTerm args = toTerm args =
case args of case args of
Term t -> t Term t -> t
Strings ss -> string2term $ unwords ss -- hmm Strings ss -> string2term $ unwords ss -- hmm
Exprs es -> string2term $ unwords $ map (showExpr [] . fst) es -- hmm Exprs es -> string2term $ unwords $ map (H.showExpr []) es -- hmm
-- ** Creating documentation -- ** Creating documentation

View File

@@ -1,12 +1,16 @@
{-# LANGUAGE FlexibleInstances, UndecidableInstances #-} {-# LANGUAGE FlexibleInstances, UndecidableInstances #-}
module GF.Command.Commands ( module GF.Command.Commands (
HasPGF(..),pgfCommands, PGFEnv,HasPGFEnv(..),pgf,mos,pgfEnv,pgfCommands,
options,flags, options,flags,
) where ) where
import Prelude hiding (putStrLn) import Prelude hiding (putStrLn,(<>)) -- GHC 8.4.1 clash with Text.PrettyPrint
import PGF2 import PGF
import PGF2.Internal(writePGF)
import PGF.Internal(lookStartCat,functionsToCat,lookValCat,restrictPGF,hasLin)
import PGF.Internal(abstract,funs,cats,Expr(EFun)) ----
import PGF.Internal(ppFun,ppCat)
import PGF.Internal(optimizePGF)
import GF.Compile.Export import GF.Compile.Export
import GF.Compile.ToAPI import GF.Compile.ToAPI
@@ -24,25 +28,28 @@ import GF.Command.TreeOperations ---- temporary place for typecheck and compute
import GF.Data.Operations import GF.Data.Operations
import Data.Char import PGF.Internal (encodeFile)
import Data.List(intersperse,nub) import Data.List(intersperse,nub)
import Data.Maybe import Data.Maybe
import qualified Data.Map as Map import qualified Data.Map as Map
import GF.Text.Pretty import GF.Text.Pretty
import Data.List (sort) import Data.List (sort)
import Control.Monad(mplus) import qualified Control.Monad.Fail as Fail
--import Debug.Trace
class (Functor m,Monad m,MonadSIO m) => HasPGF m where getPGF :: m (Maybe PGF)
instance (Monad m,HasPGF m) => TypeCheckArg m where data PGFEnv = Env {pgf::PGF,mos::Map.Map Language Morpho}
typeCheckArg e = do mb_pgf <- getPGF
case mb_pgf of
Just pgf -> either fail
(return . fst)
(inferExpr pgf e)
Nothing -> fail "Import a grammar before using this command"
pgfCommands :: HasPGF m => Map.Map String (CommandInfo m) pgfEnv pgf = Env pgf mos
where mos = Map.fromList [(la,buildMorpho pgf la) | la <- languages pgf]
class (Functor m,Monad m,MonadSIO m) => HasPGFEnv m where getPGFEnv :: m PGFEnv
instance (Monad m,HasPGFEnv m,Fail.MonadFail m) => TypeCheckArg m where
typeCheckArg e = (either (fail . render . ppTcError) (return . fst)
. flip inferExpr e . pgf) =<< getPGFEnv
pgfCommands :: HasPGFEnv m => Map.Map String (CommandInfo m)
pgfCommands = Map.fromList [ pgfCommands = Map.fromList [
("aw", emptyCommandInfo { ("aw", emptyCommandInfo {
longname = "align_words", longname = "align_words",
@@ -55,7 +62,7 @@ pgfCommands = Map.fromList [
"by the view flag. The target format is png, unless overridden by the", "by the view flag. The target format is png, unless overridden by the",
"flag -format. Results from multiple trees are combined to pdf with convert (ImageMagick)." "flag -format. Results from multiple trees are combined to pdf with convert (ImageMagick)."
], ],
exec = needPGF $ \ opts arg pgf -> do exec = getEnv $ \ opts arg (Env pgf mos) -> do
let es = toExprs arg let es = toExprs arg
let langs = optLangs pgf opts let langs = optLangs pgf opts
if isOpt "giza" opts if isOpt "giza" opts
@@ -67,7 +74,7 @@ pgfCommands = Map.fromList [
let grph = if null es then [] else lsrc ++ "\n--end_source--\n\n"++ltrg++"\n-end_target--\n\n"++align let grph = if null es then [] else lsrc ++ "\n--end_source--\n\n"++ltrg++"\n-end_target--\n\n"++align
return $ fromString grph return $ fromString grph
else do else do
let grphs = map (graphvizWordAlignment langs graphvizDefaults) es let grphs = map (graphvizAlignment pgf langs) es
if isFlag "view" opts || isFlag "format" opts if isFlag "view" opts || isFlag "format" opts
then do then do
let view = optViewGraph opts let view = optViewGraph opts
@@ -89,7 +96,6 @@ pgfCommands = Map.fromList [
("view", "program to open the resulting file") ("view", "program to open the resulting file")
] ]
}), }),
("ca", emptyCommandInfo { ("ca", emptyCommandInfo {
longname = "clitic_analyse", longname = "clitic_analyse",
synopsis = "print the analyses of all words into stems and clitics", synopsis = "print the analyses of all words into stems and clitics",
@@ -100,17 +106,16 @@ pgfCommands = Map.fromList [
"by the flag '-clitics'. The list of stems is given as the list of words", "by the flag '-clitics'. The list of stems is given as the list of words",
"of the language given by the '-lang' flag." "of the language given by the '-lang' flag."
], ],
exec = needPGF $ \opts ts pgf -> do exec = getEnv $ \opts ts env -> case opts of
concr <- optLang pgf opts _ | isOpt "raw" opts ->
case opts of return . fromString .
_ | isOpt "raw" opts -> unlines . map (unwords . map (concat . intersperse "+")) .
return . fromString . map (getClitics (isInMorpho (optMorpho env opts)) (optClitics opts)) .
unlines . map (unwords . map (concat . intersperse "+")) . concatMap words $ toStrings ts
map (getClitics (not . null . lookupMorpho concr) (optClitics opts)) . _ ->
concatMap words $ toStrings ts return . fromStrings .
_ -> return . fromStrings . getCliticsText (isInMorpho (optMorpho env opts)) (optClitics opts) .
getCliticsText (not . null . lookupMorpho concr) (optClitics opts) . concatMap words $ toStrings ts,
concatMap words $ toStrings ts,
flags = [ flags = [
("clitics","the list of possible clitics (comma-separated, no spaces)"), ("clitics","the list of possible clitics (comma-separated, no spaces)"),
("lang", "the language of analysis") ("lang", "the language of analysis")
@@ -142,19 +147,19 @@ pgfCommands = Map.fromList [
], ],
flags = [ flags = [
("file","the file to be converted (suffix .gfe must be given)"), ("file","the file to be converted (suffix .gfe must be given)"),
("lang","the language in which to parse") ("lang","the language in which to parse"),
("probs","file with probabilities to rank the parses")
], ],
exec = needPGF $ \opts _ pgf -> do exec = getEnv $ \ opts _ env@(Env pgf mos) -> do
let file = optFile opts let file = optFile opts
pgf <- optProbs opts pgf
let printer = if (isOpt "api" opts) then exprToAPI else (showExpr []) let printer = if (isOpt "api" opts) then exprToAPI else (showExpr [])
concr <- optLang pgf opts let conf = configureExBased pgf (optMorpho env opts) (optLang pgf opts) printer
let conf = configureExBased pgf concr printer
(file',ws) <- restricted $ parseExamplesInGrammar conf file (file',ws) <- restricted $ parseExamplesInGrammar conf file
if null ws then return () else putStrLn ("unknown words: " ++ unwords ws) if null ws then return () else putStrLn ("unknown words: " ++ unwords ws)
return (fromString ("wrote " ++ file')), return (fromString ("wrote " ++ file')),
needsTypeCheck = False needsTypeCheck = False
}), }),
("gr", emptyCommandInfo { ("gr", emptyCommandInfo {
longname = "generate_random", longname = "generate_random",
synopsis = "generate random trees in the current abstract syntax", synopsis = "generate random trees in the current abstract syntax",
@@ -169,53 +174,54 @@ pgfCommands = Map.fromList [
explanation = unlines [ explanation = unlines [
"Generates a list of random trees, by default one tree.", "Generates a list of random trees, by default one tree.",
"If a tree argument is given, the command completes the Tree with values to", "If a tree argument is given, the command completes the Tree with values to",
"all metavariables in the tree. The generation can be biased by probabilities", "all metavariables in the tree. The generation can be biased by probabilities,",
"if the grammar was compiled with option -probs" "given in a file in the -probs flag."
],
options = [
("show_probs", "show the probability of each result")
], ],
flags = [ flags = [
("cat","generation category"), ("cat","generation category"),
("lang","uses only functions that have linearizations in all these languages"), ("lang","uses only functions that have linearizations in all these languages"),
("number","number of trees generated") ("number","number of trees generated"),
("depth","the maximum generation depth"),
("probs", "file with biased probabilities (format 'f 0.4' one by line)")
], ],
exec = needPGF $ \opts arg pgf -> do exec = getEnv $ \ opts arg (Env pgf mos) -> do
pgf <- optProbs opts (optRestricted opts pgf)
gen <- newStdGen gen <- newStdGen
let dp = valIntOpts "depth" 4 opts
let ts = case mexp (toExprs arg) of let ts = case mexp (toExprs arg) of
Just ex -> generateRandomFrom gen pgf ex Just ex -> generateRandomFromDepth gen pgf ex (Just dp)
Nothing -> generateRandom gen pgf (optType pgf opts) Nothing -> generateRandomDepth gen pgf (optType pgf opts) (Just dp)
returnFromExprs (isOpt "show_probs" opts) $ take (optNum opts) ts returnFromExprs $ take (optNum opts) ts
}), }),
("gt", emptyCommandInfo { ("gt", emptyCommandInfo {
longname = "generate_trees", longname = "generate_trees",
synopsis = "generates a list of trees, by default exhaustive", synopsis = "generates a list of trees, by default exhaustive",
explanation = unlines [ explanation = unlines [
"Generates all trees of a given category.", "Generates all trees of a given category. By default, ",
"the depth is limited to 4, but this can be changed by a flag.",
"If a Tree argument is given, the command completes the Tree with values", "If a Tree argument is given, the command completes the Tree with values",
"to all metavariables in the tree." "to all metavariables in the tree."
], ],
options = [
("show_probs", "show the probability of each result")
],
flags = [ flags = [
("cat","the generation category"), ("cat","the generation category"),
("depth","the maximum generation depth"),
("lang","excludes functions that have no linearization in this language"), ("lang","excludes functions that have no linearization in this language"),
("number","the number of trees generated") ("number","the number of trees generated")
], ],
examples = [ examples = [
mkEx "gt -- all trees in the startcat", mkEx "gt -- all trees in the startcat, to depth 4",
mkEx "gt -cat=NP -number=16 -- 16 trees in the category NP", mkEx "gt -cat=NP -number=16 -- 16 trees in the category NP",
mkEx "gt -cat=NP -depth=2 -- trees in the category NP to depth 2",
mkEx "gt (AdjCN ? (UseN ?)) -- trees of form (AdjCN ? (UseN ?))" mkEx "gt (AdjCN ? (UseN ?)) -- trees of form (AdjCN ? (UseN ?))"
], ],
exec = needPGF $ \opts arg pgf -> do exec = getEnv $ \ opts arg (Env pgf mos) -> do
let es = case mexp (toExprs arg) of let pgfr = optRestricted opts pgf
Just ex -> generateAllFrom pgf ex let dp = valIntOpts "depth" 4 opts
Nothing -> generateAll pgf (optType pgf opts) let ts = case mexp (toExprs arg) of
returnFromExprs (isOpt "show_probs" opts) $ takeOptNum opts es Just ex -> generateFromDepth pgfr ex (Just dp)
Nothing -> generateAllDepth pgfr (optType pgf opts) (Just dp)
returnFromExprs $ take (optNumInf opts) ts
}), }),
("i", emptyCommandInfo { ("i", emptyCommandInfo {
longname = "import", longname = "import",
synopsis = "import a grammar from source code or compiled .pgf file", synopsis = "import a grammar from source code or compiled .pgf file",
@@ -236,28 +242,33 @@ pgfCommands = Map.fromList [
("probs","file with biased probabilities for generation") ("probs","file with biased probabilities for generation")
], ],
options = [ options = [
-- ["gfo", "src", "no-cpu", "cpu", "quiet", "verbose"]
("retain","retain operations (used for cc command)"), ("retain","retain operations (used for cc command)"),
("src", "force compilation from source"), ("src", "force compilation from source"),
("v", "be verbose - show intermediate status information") ("v", "be verbose - show intermediate status information")
], ],
needsTypeCheck = False needsTypeCheck = False
}), }),
("l", emptyCommandInfo { ("l", emptyCommandInfo {
longname = "linearize", longname = "linearize",
synopsis = "convert an abstract syntax expression to string", synopsis = "convert an abstract syntax expression to string",
explanation = unlines [ explanation = unlines [
"Shows the linearization of a tree by the grammars in scope.", "Shows the linearization of a Tree by the grammars in scope.",
"The -lang flag can be used to restrict this to fewer languages.", "The -lang flag can be used to restrict this to fewer languages.",
"A sequence of string operations (see command ps) can be given", "A sequence of string operations (see command ps) can be given",
"as options, and works then like a pipe to the ps command, except", "as options, and works then like a pipe to the ps command, except",
"that it only affect the strings, not e.g. the table labels." "that it only affect the strings, not e.g. the table labels.",
"These can be given separately to each language with the unlexer flag",
"whose results are prepended to the other lexer flags. The value of the",
"unlexer flag is a space-separated list of comma-separated string operation",
"sequences; see example."
], ],
examples = [ examples = [
mkEx "l -lang=LangSwe,LangNor no_Utt -- linearize tree to LangSwe and LangNor", mkEx "l -lang=LangSwe,LangNor no_Utt -- linearize tree to LangSwe and LangNor",
mkEx "gr -lang=LangHin -cat=Cl | l -table -to_devanagari -- hindi table" mkEx "gr -lang=LangHin -cat=Cl | l -table -to_devanagari -- hindi table",
mkEx "l -unlexer=\"LangAra=to_arabic LangHin=to_devanagari\" -- different unlexers"
], ],
exec = needPGF $ \ opts ts pgf -> return . fromStrings . optLins pgf opts $ toExprs ts, exec = getEnv $ \ opts ts (Env pgf mos) -> return . fromStrings . optLins pgf opts $ toExprs ts,
options = [ options = [
("all", "show all forms and variants, one by line (cf. l -list)"), ("all", "show all forms and variants, one by line (cf. l -list)"),
("bracket","show tree structure with brackets and paths to nodes"), ("bracket","show tree structure with brackets and paths to nodes"),
@@ -265,13 +276,33 @@ pgfCommands = Map.fromList [
("list","show all forms and variants, comma-separated on one line (cf. l -all)"), ("list","show all forms and variants, comma-separated on one line (cf. l -all)"),
("multi","linearize to all languages (default)"), ("multi","linearize to all languages (default)"),
("table","show all forms labelled by parameters"), ("table","show all forms labelled by parameters"),
("tabtreebank","show the tree and its linearizations on a tab-separated line"),
("treebank","show the tree and tag linearizations with language names")
] ++ stringOpOptions,
flags = [
("lang","the languages of linearization (comma-separated, no spaces)"),
("unlexer","set unlexers separately to each language (space-separated)")
]
}),
("lc", emptyCommandInfo {
longname = "linearize_chunks",
synopsis = "linearize a tree that has metavariables in maximal chunks without them",
explanation = unlines [
"A hopefully temporary command, intended to work around the type checker that fails",
"trees where a function node is a metavariable."
],
examples = [
mkEx "l -lang=LangSwe,LangNor -chunks ? a b (? c d)"
],
exec = getEnv $ \ opts ts (Env pgf mos) -> return . fromStrings $ optLins pgf (opts ++ [OOpt "chunks"]) (toExprs ts),
options = [
("treebank","show the tree and tag linearizations with language names") ("treebank","show the tree and tag linearizations with language names")
] ++ stringOpOptions, ] ++ stringOpOptions,
flags = [ flags = [
("lang","the languages of linearization (comma-separated, no spaces)") ("lang","the languages of linearization (comma-separated, no spaces)")
] ],
needsTypeCheck = False
}), }),
("ma", emptyCommandInfo { ("ma", emptyCommandInfo {
longname = "morpho_analyse", longname = "morpho_analyse",
synopsis = "print the morphological analyses of all words in the string", synopsis = "print the morphological analyses of all words in the string",
@@ -279,20 +310,18 @@ pgfCommands = Map.fromList [
"Prints all the analyses of space-separated words in the input string,", "Prints all the analyses of space-separated words in the input string,",
"using the morphological analyser of the actual grammar (see command pg)" "using the morphological analyser of the actual grammar (see command pg)"
], ],
exec = needPGF $ \opts ts pgf -> do exec = getEnv $ \opts ts env -> case opts of
concr <- optLang pgf opts _ | isOpt "missing" opts ->
case opts of return . fromString . unwords .
_ | isOpt "missing" opts -> morphoMissing (optMorpho env opts) .
return . fromString . unwords . concatMap words $ toStrings ts
morphoMissing concr . _ | isOpt "known" opts ->
concatMap words $ toStrings ts return . fromString . unwords .
_ | isOpt "known" opts -> morphoKnown (optMorpho env opts) .
return . fromString . unwords . concatMap words $ toStrings ts
morphoKnown concr . _ -> return . fromString . unlines .
concatMap words $ toStrings ts map prMorphoAnalysis . concatMap (morphos env opts) .
_ -> return . fromString . unlines . concatMap words $ toStrings ts,
map prMorphoAnalysis . concatMap (morphos pgf opts) .
concatMap words $ toStrings ts,
flags = [ flags = [
("lang","the languages of analysis (comma-separated, no spaces)") ("lang","the languages of analysis (comma-separated, no spaces)")
], ],
@@ -306,16 +335,18 @@ pgfCommands = Map.fromList [
longname = "morpho_quiz", longname = "morpho_quiz",
synopsis = "start a morphology quiz", synopsis = "start a morphology quiz",
syntax = "mq (-cat=CAT)? (-probs=FILE)? TREE?", syntax = "mq (-cat=CAT)? (-probs=FILE)? TREE?",
exec = needPGF $ \ opts arg pgf -> do exec = getEnv $ \ opts arg (Env pgf mos) -> do
lang <- optLang pgf opts let lang = optLang pgf opts
let typ = optType pgf opts let typ = optType pgf opts
pgf <- optProbs opts pgf
let mt = mexp (toExprs arg) let mt = mexp (toExprs arg)
restricted $ morphologyQuiz mt pgf lang typ restricted $ morphologyQuiz mt pgf lang typ
return void, return void,
flags = [ flags = [
("lang","language of the quiz"), ("lang","language of the quiz"),
("cat","category of the quiz"), ("cat","category of the quiz"),
("number","maximum number of questions") ("number","maximum number of questions"),
("probs","file with biased probabilities for generation")
] ]
}), }),
@@ -326,25 +357,24 @@ pgfCommands = Map.fromList [
"Shows all trees returned by parsing a string in the grammars in scope.", "Shows all trees returned by parsing a string in the grammars in scope.",
"The -lang flag can be used to restrict this to fewer languages.", "The -lang flag can be used to restrict this to fewer languages.",
"The default start category can be overridden by the -cat flag.", "The default start category can be overridden by the -cat flag.",
"See also the ps command for lexing and character encoding." "See also the ps command for lexing and character encoding.",
], "",
exec = needPGF $ \opts ts pgf -> "The -openclass flag is experimental and allows some robustness in ",
return $ "the parser. For example if -openclass=\"A,N,V\" is given, the parser",
foldr (joinPiped . fromParse1 opts) void "will accept unknown adjectives, nouns and verbs with the resource grammar."
(concat [
[(s,parse concr (optType pgf opts) s) |
concr <- optLangs pgf opts]
| s <- toStrings ts]),
options = [
("show_probs", "show the probability of each result")
], ],
exec = getEnv $ \ opts ts (Env pgf mos) ->
return $ fromParse opts (concat [map ((,) s) (par pgf opts s) | s <- toStrings ts]),
flags = [ flags = [
("cat","target category of parsing"), ("cat","target category of parsing"),
("lang","the languages of parsing (comma-separated, no spaces)"), ("lang","the languages of parsing (comma-separated, no spaces)"),
("number","limit the results to the top N trees") ("openclass","list of open-class categories for robust parsing"),
("depth","maximal depth for proof search if the abstract syntax tree has meta variables")
],
options = [
("bracket","prints the bracketed string from the parser")
] ]
}), }),
("pg", emptyCommandInfo { ----- ("pg", emptyCommandInfo { -----
longname = "print_grammar", longname = "print_grammar",
synopsis = "print the actual grammar with the given printer", synopsis = "print the actual grammar with the given printer",
@@ -364,8 +394,9 @@ pgfCommands = Map.fromList [
" " ++ opt ++ "\t\t" ++ expl | " " ++ opt ++ "\t\t" ++ expl |
((opt,_),expl) <- outputFormatsExpl, take 1 expl /= "*" ((opt,_),expl) <- outputFormatsExpl, take 1 expl /= "*"
]), ]),
exec = needPGF $ \opts _ pgf -> prGrammar pgf opts, exec = getEnv $ \opts _ env -> prGrammar env opts,
flags = [ flags = [
--"cat",
("file", "set the file name when printing with -pgf option"), ("file", "set the file name when printing with -pgf option"),
("lang", "select languages for the some options (default all languages)"), ("lang", "select languages for the some options (default all languages)"),
("printer","select the printing format (see flag values above)") ("printer","select the printing format (see flag values above)")
@@ -385,7 +416,6 @@ pgfCommands = Map.fromList [
mkEx ("pg -funs | ? grep \" S ;\" -- show functions with value cat S") mkEx ("pg -funs | ? grep \" S ;\" -- show functions with value cat S")
] ]
}), }),
("pt", emptyCommandInfo { ("pt", emptyCommandInfo {
longname = "put_tree", longname = "put_tree",
syntax = "pt OPT? TREE", syntax = "pt OPT? TREE",
@@ -399,12 +429,11 @@ pgfCommands = Map.fromList [
examples = [ examples = [
mkEx "pt -compute (plus one two) -- compute value" mkEx "pt -compute (plus one two) -- compute value"
], ],
exec = needPGF $ \opts arg pgf -> exec = getEnv $ \ opts arg (Env pgf mos) ->
returnFromExprs False . takeOptNum opts . map (flip (,) 0) . treeOps pgf opts $ toExprs arg, returnFromExprs . takeOptNum opts . treeOps pgf opts $ toExprs arg,
options = treeOpOptions undefined{-pgf-}, options = treeOpOptions undefined{-pgf-},
flags = [("number","take at most this many trees")] ++ treeOpFlags undefined{-pgf-} flags = [("number","take at most this many trees")] ++ treeOpFlags undefined{-pgf-}
}), }),
("rf", emptyCommandInfo { ("rf", emptyCommandInfo {
longname = "read_file", longname = "read_file",
synopsis = "read string or tree input from a file", synopsis = "read string or tree input from a file",
@@ -417,9 +446,10 @@ pgfCommands = Map.fromList [
], ],
options = [ options = [
("lines","return the list of lines, instead of the singleton of all contents"), ("lines","return the list of lines, instead of the singleton of all contents"),
("paragraphs","return the list of paragraphs, as separated by empty lines"),
("tree","convert strings into trees") ("tree","convert strings into trees")
], ],
exec = needPGF $ \ opts _ pgf -> do exec = getEnv $ \ opts _ (Env pgf mos) -> do
let file = valStrOpts "file" "_gftmp" opts let file = valStrOpts "file" "_gftmp" opts
let exprs [] = ([],empty) let exprs [] = ([],empty)
exprs ((n,s):ls) | null s exprs ((n,s):ls) | null s
@@ -428,12 +458,12 @@ pgfCommands = Map.fromList [
Just e -> let (es,err) = exprs ls Just e -> let (es,err) = exprs ls
in case inferExpr pgf e of in case inferExpr pgf e of
Right (e,t) -> (e:es,err) Right (e,t) -> (e:es,err)
Left err -> (es,"on line" <+> n <> ':' $$ nest 2 err $$ err) Left tcerr -> (es,"on line" <+> n <> ':' $$ nest 2 (ppTcError tcerr) $$ err)
Nothing -> let (es,err) = exprs ls Nothing -> let (es,err) = exprs ls
in (es,"on line" <+> n <> ':' <+> "parse error" $$ err) in (es,"on line" <+> n <> ':' <+> "parse error" $$ err)
returnFromLines ls = case exprs ls of returnFromLines ls = case exprs ls of
(es, err) | null es -> return $ pipeMessage $ render (err $$ "no trees found") (es, err) | null es -> return $ pipeMessage $ render (err $$ "no trees found")
| otherwise -> return $ pipeWithMessage (map (flip (,) 0) es) (render err) | otherwise -> return $ pipeWithMessage es (render err)
s <- restricted $ readFile file s <- restricted $ readFile file
case opts of case opts of
@@ -442,26 +472,56 @@ pgfCommands = Map.fromList [
_ | isOpt "tree" opts -> _ | isOpt "tree" opts ->
returnFromLines [(1::Int,s)] returnFromLines [(1::Int,s)]
_ | isOpt "lines" opts -> return (fromStrings $ lines s) _ | isOpt "lines" opts -> return (fromStrings $ lines s)
_ | isOpt "paragraphs" opts -> return (fromStrings $ toParagraphs $ lines s)
_ -> return (fromString s), _ -> return (fromString s),
flags = [("file","the input file name")] flags = [("file","the input file name")]
}), }),
("rt", emptyCommandInfo {
longname = "rank_trees",
synopsis = "show trees in an order of decreasing probability",
explanation = unlines [
"Order trees from the most to the least probable, using either",
"even distribution in each category (default) or biased as specified",
"by the file given by flag -probs=FILE, where each line has the form",
"'function probability', e.g. 'youPol_Pron 0.01'."
],
exec = getEnv $ \ opts arg (Env pgf mos) -> do
let ts = toExprs arg
pgf <- optProbs opts pgf
let tds = rankTreesByProbs pgf ts
if isOpt "v" opts
then putStrLn $
unlines [showExpr [] t ++ "\t--" ++ show d | (t,d) <- tds]
else return ()
returnFromExprs $ map fst tds,
flags = [
("probs","probabilities from this file (format 'f 0.6' per line)")
],
options = [
("v","show all trees with their probability scores")
],
examples = [
mkEx "p \"you are here\" | rt -probs=probs | pt -number=1 -- most probable result"
]
}),
("tq", emptyCommandInfo { ("tq", emptyCommandInfo {
longname = "translation_quiz", longname = "translation_quiz",
syntax = "tq -from=LANG -to=LANG (-cat=CAT)? (-probs=FILE)? TREE?", syntax = "tq -from=LANG -to=LANG (-cat=CAT)? (-probs=FILE)? TREE?",
synopsis = "start a translation quiz", synopsis = "start a translation quiz",
exec = needPGF $ \ opts arg pgf -> do exec = getEnv $ \ opts arg (Env pgf mos) -> do
from <- optLangFlag "from" pgf opts let from = optLangFlag "from" pgf opts
to <- optLangFlag "to" pgf opts let to = optLangFlag "to" pgf opts
let typ = optType pgf opts let typ = optType pgf opts
let mt = mexp (toExprs arg) let mt = mexp (toExprs arg)
pgf <- optProbs opts pgf
restricted $ translationQuiz mt pgf from to typ restricted $ translationQuiz mt pgf from to typ
return void, return void,
flags = [ flags = [
("from","translate from this language"), ("from","translate from this language"),
("to","translate to this language"), ("to","translate to this language"),
("cat","translate in this category"), ("cat","translate in this category"),
("number","the maximum number of questions") ("number","the maximum number of questions"),
("probs","file with biased probabilities for generation")
], ],
examples = [ examples = [
mkEx ("tq -from=Eng -to=Swe -- any trees in startcat"), mkEx ("tq -from=Eng -to=Swe -- any trees in startcat"),
@@ -469,6 +529,7 @@ pgfCommands = Map.fromList [
] ]
}), }),
("vd", emptyCommandInfo { ("vd", emptyCommandInfo {
longname = "visualize_dependency", longname = "visualize_dependency",
synopsis = "show word dependency tree graphically", synopsis = "show word dependency tree graphically",
@@ -486,7 +547,7 @@ pgfCommands = Map.fromList [
"flag -format. Results from multiple trees are combined to pdf with convert (ImageMagick).", "flag -format. Results from multiple trees are combined to pdf with convert (ImageMagick).",
"See also 'vp -showdep' for another visualization of dependencies." "See also 'vp -showdep' for another visualization of dependencies."
], ],
exec = needPGF $ \ opts arg pgf -> do exec = getEnv $ \ opts arg (Env pgf mos) -> do
let absname = abstractName pgf let absname = abstractName pgf
let es = toExprs arg let es = toExprs arg
let debug = isOpt "v" opts let debug = isOpt "v" opts
@@ -499,8 +560,8 @@ pgfCommands = Map.fromList [
mclab <- case cnclabels of mclab <- case cnclabels of
"" -> return Nothing "" -> return Nothing
_ -> (Just . getCncDepLabels) `fmap` restricted (readFile cnclabels) _ -> (Just . getCncDepLabels) `fmap` restricted (readFile cnclabels)
concr <- optLang pgf opts let lang = optLang pgf opts
let grphs = map (graphvizDependencyTree outp debug mlab mclab concr) es let grphs = map (graphvizDependencyTree outp debug mlab mclab pgf lang) es
if isOpt "conll2latex" opts if isOpt "conll2latex" opts
then return $ fromString $ conlls2latexDoc $ stanzas $ unlines $ toStrings arg then return $ fromString $ conlls2latexDoc $ stanzas $ unlines $ toStrings arg
else if isFlag "view" opts && valStrOpts "output" "" opts == "latex" else if isFlag "view" opts && valStrOpts "output" "" opts == "latex"
@@ -535,6 +596,7 @@ pgfCommands = Map.fromList [
] ]
}), }),
("vp", emptyCommandInfo { ("vp", emptyCommandInfo {
longname = "visualize_parse", longname = "visualize_parse",
synopsis = "show parse tree graphically", synopsis = "show parse tree graphically",
@@ -546,8 +608,9 @@ pgfCommands = Map.fromList [
"by the view flag. The target format is png, unless overridden by the", "by the view flag. The target format is png, unless overridden by the",
"flag -format. Results from multiple trees are combined to pdf with convert (ImageMagick)." "flag -format. Results from multiple trees are combined to pdf with convert (ImageMagick)."
], ],
exec = needPGF $ \opts arg pgf -> do exec = getEnv $ \ opts arg (Env pgf mos) -> do
let es = toExprs arg let es = toExprs arg
let lang = optLang pgf opts
let gvOptions = GraphvizOptions {noLeaves = isOpt "noleaves" opts && not (isOpt "showleaves" opts), let gvOptions = GraphvizOptions {noLeaves = isOpt "noleaves" opts && not (isOpt "showleaves" opts),
noFun = isOpt "nofun" opts || not (isOpt "showfun" opts), noFun = isOpt "nofun" opts || not (isOpt "showfun" opts),
noCat = isOpt "nocat" opts && not (isOpt "showcat" opts), noCat = isOpt "nocat" opts && not (isOpt "showcat" opts),
@@ -560,11 +623,10 @@ pgfCommands = Map.fromList [
leafEdgeStyle = valStrOpts "leafedgestyle" "dashed" opts leafEdgeStyle = valStrOpts "leafedgestyle" "dashed" opts
} }
let depfile = valStrOpts "file" "" opts let depfile = valStrOpts "file" "" opts
concr <- optLang pgf opts
mlab <- case depfile of mlab <- case depfile of
"" -> return Nothing "" -> return Nothing
_ -> (Just . getDepLabels) `fmap` restricted (readFile depfile) _ -> (Just . getDepLabels) `fmap` restricted (readFile depfile)
let grphs = map (graphvizDependencyTree "dot" False mlab Nothing concr) es let grphs = map (graphvizParseTreeDep mlab pgf lang gvOptions) es
if isFlag "view" opts || isFlag "format" opts if isFlag "view" opts || isFlag "format" opts
then do then do
let view = optViewGraph opts let view = optViewGraph opts
@@ -599,6 +661,7 @@ pgfCommands = Map.fromList [
] ]
}), }),
("vt", emptyCommandInfo { ("vt", emptyCommandInfo {
longname = "visualize_tree", longname = "visualize_tree",
synopsis = "show a set of trees graphically", synopsis = "show a set of trees graphically",
@@ -611,7 +674,7 @@ pgfCommands = Map.fromList [
"flag -format. Results from multiple trees are combined to pdf with convert (ImageMagick).", "flag -format. Results from multiple trees are combined to pdf with convert (ImageMagick).",
"With option -mk, use for showing library style function names of form 'mkC'." "With option -mk, use for showing library style function names of form 'mkC'."
], ],
exec = needPGF $ \opts arg pgf -> exec = getEnv $ \ opts arg (Env pgf mos) ->
let es = toExprs arg in let es = toExprs arg in
if isOpt "mk" opts if isOpt "mk" opts
then return $ fromString $ unlines $ map (tree2mk pgf) es then return $ fromString $ unlines $ map (tree2mk pgf) es
@@ -623,7 +686,7 @@ pgfCommands = Map.fromList [
else do else do
let funs = not (isOpt "nofun" opts) let funs = not (isOpt "nofun" opts)
let cats = not (isOpt "nocat" opts) let cats = not (isOpt "nocat" opts)
let grphs = map (graphvizAbstractTree pgf (graphvizDefaults{noFun=funs,noCat=cats})) es let grphs = map (graphvizAbstractTree pgf (funs,cats)) es
if isFlag "view" opts || isFlag "format" opts if isFlag "view" opts || isFlag "format" opts
then do then do
let view = optViewGraph opts let view = optViewGraph opts
@@ -645,7 +708,6 @@ pgfCommands = Map.fromList [
("view","program to open the resulting file (default \"open\")") ("view","program to open the resulting file (default \"open\")")
] ]
}), }),
("ai", emptyCommandInfo { ("ai", emptyCommandInfo {
longname = "abstract_info", longname = "abstract_info",
syntax = "ai IDENTIFIER or ai EXPR", syntax = "ai IDENTIFIER or ai EXPR",
@@ -658,156 +720,205 @@ pgfCommands = Map.fromList [
"If a whole expression is given it prints the expression with refined", "If a whole expression is given it prints the expression with refined",
"metavariables and the type of the expression." "metavariables and the type of the expression."
], ],
exec = needPGF $ \opts arg pgf -> do exec = getEnv $ \ opts arg (Env pgf mos) -> do
case toExprs arg of case toExprs arg of
[e] -> case unApp e of [EFun id] -> case Map.lookup id (funs (abstract pgf)) of
Just (id, []) -> case functionType pgf id of Just fd -> do putStrLn $ render (ppFun id fd)
Just ty -> do putStrLn (showFun pgf id ty) let (_,_,_,prob) = fd
putStrLn ("Probability: "++show (treeProbability pgf e)) putStrLn ("Probability: "++show prob)
return void return void
Nothing -> case categoryContext pgf id of Nothing -> case Map.lookup id (cats (abstract pgf)) of
Just hypos -> do putStrLn ("cat "++id++if null hypos then "" else ' ':showContext [] hypos) Just cd -> do putStrLn $
let ls = [showFun pgf fn ty | fn <- functionsByCat pgf id, Just ty <- [functionType pgf fn]] render (ppCat id cd $$
if null ls if null (functionsToCat pgf id)
then return () then empty
else putStrLn (unlines ("":ls)) else ' ' $$
putStrLn ("Probability: "++show (categoryProbability pgf id)) vcat [ppFun fid (ty,0,Just ([],[]),0) | (fid,ty) <- functionsToCat pgf id] $$
return void ' ')
Nothing -> do putStrLn ("unknown category of function identifier "++show id) let (_,_,prob) = cd
return void putStrLn ("Probability: "++show prob)
_ -> case inferExpr pgf e of return void
Left err -> error err Nothing -> do putStrLn ("unknown category of function identifier "++show id)
Right (e,ty) -> do putStrLn ("Expression: "++showExpr [] e) return void
putStrLn ("Type: "++showType [] ty) [e] -> case inferExpr pgf e of
putStrLn ("Probability: "++show (treeProbability pgf e)) Left tcErr -> error $ render (ppTcError tcErr)
return void Right (e,ty) -> do putStrLn ("Expression: "++showExpr [] e)
putStrLn ("Type: "++showType [] ty)
putStrLn ("Probability: "++show (probTree pgf e))
return void
_ -> do putStrLn "a single identifier or expression is expected from the command" _ -> do putStrLn "a single identifier or expression is expected from the command"
return void, return void,
needsTypeCheck = False needsTypeCheck = False
}) })
] ]
where where
needPGF exec opts ts = do getEnv exec opts ts = liftSIO . exec opts ts =<< getPGFEnv
mb_pgf <- getPGF
case mb_pgf of par pgf opts s = case optOpenTypes opts of
Just pgf -> liftSIO $ exec opts ts pgf [] -> [parse_ pgf lang (optType pgf opts) (Just dp) s | lang <- optLangs pgf opts]
_ -> fail "Import a grammar before using this command" open_typs -> [parseWithRecovery pgf lang (optType pgf opts) open_typs (Just dp) s | lang <- optLangs pgf opts]
where
dp = valIntOpts "depth" 4 opts
fromParse opts = foldr (joinPiped . fromParse1 opts) void
joinPiped (Piped (es1,ms1)) (Piped (es2,ms2)) = Piped (jA es1 es2,ms1+++-ms2) joinPiped (Piped (es1,ms1)) (Piped (es2,ms2)) = Piped (jA es1 es2,ms1+++-ms2)
where where
jA (Exprs es1) (Exprs es2) = Exprs (es1++es2) jA (Exprs es1) (Exprs es2) = Exprs (es1++es2)
-- ^ fromParse1 always output Exprs
fromParse1 opts (s,po) = fromParse1 opts (s,(po,bs))
case po of | isOpt "bracket" opts = pipeMessage (showBracketedString bs)
ParseOk ts -> fromExprs (isOpt "show_probs" opts) (takeOptNum opts ts) | otherwise =
ParseFailed i t -> pipeMessage $ "The parser failed at token " case po of
++ show i ++": " ParseOk ts -> fromExprs ts
++ show t ParseFailed i -> pipeMessage $ "The parser failed at token "
ParseIncomplete -> pipeMessage "The sentence is not complete" ++ show i ++": "
++ show (words s !! max 0 (i-1))
-- ++ " in " ++ show s
ParseIncomplete -> pipeMessage "The sentence is not complete"
TypeError errs ->
pipeMessage . render $
"The parsing is successful but the type checking failed with error(s):"
$$ nest 2 (vcat (map (ppTcError . snd) errs))
optLins pgf opts ts = concatMap (optLin pgf opts) ts optLins pgf opts ts = case opts of
_ | isOpt "groups" opts ->
concatMap snd $ groupResults
[[(lang, s) | lang <- optLangs pgf opts,s <- linear pgf opts lang t] | t <- ts]
_ -> concatMap (optLin pgf opts) ts
optLin pgf opts t = optLin pgf opts t =
case opts of case opts of
_ | isOpt "treebank" opts && isOpt "chunks" opts -> _ | isOpt "treebank" opts && isOpt "chunks" opts ->
(abstractName pgf ++ ": " ++ showExpr [] t) : (showCId (abstractName pgf) ++ ": " ++ showExpr [] t) :
[lang ++ ": " ++ li | (lang,li) <- linChunks pgf opts t] --linear pgf opts lang t | lang <- optLangs pgf opts] [showCId lang ++ ": " ++ li | (lang,li) <- linChunks pgf opts t] --linear pgf opts lang t | lang <- optLangs pgf opts]
_ | isOpt "treebank" opts -> _ | isOpt "treebank" opts ->
(abstractName pgf ++ ": " ++ showExpr [] t) : (showCId (abstractName pgf) ++ ": " ++ showExpr [] t) :
[concreteName concr ++ ": " ++ s | concr <- optLangs pgf opts, s<-linear opts concr t] [showCId lang ++ ": " ++ s | lang <- optLangs pgf opts, s<-linear pgf opts lang t]
_ | isOpt "tabtreebank" opts ->
return $ concat $ intersperse "\t" $ (showExpr [] t) :
[s | lang <- optLangs pgf opts, s <- linear pgf opts lang t]
_ | isOpt "chunks" opts -> map snd $ linChunks pgf opts t _ | isOpt "chunks" opts -> map snd $ linChunks pgf opts t
_ -> [s | concr <- optLangs pgf opts, s <- linear opts concr t] _ -> [s | lang <- optLangs pgf opts, s<-linear pgf opts lang t]
linChunks pgf opts t = linChunks pgf opts t =
[(concreteName concr, unwords (intersperse "<+>" (map (unlines . linear opts concr) (treeChunks t)))) | concr <- optLangs pgf opts] [(lang, unwords (intersperse "<+>" (map (unlines . linear pgf opts lang) (treeChunks t)))) | lang <- optLangs pgf opts]
linear :: [Option] -> Concr -> Expr -> [String] linear :: PGF -> [Option] -> CId -> Expr -> [String]
linear opts concr = case opts of linear pgf opts lang = let unl = unlex opts lang in case opts of
_ | isOpt "all" opts -> concat . _ | isOpt "all" opts -> concat . -- intersperse [[]] .
map (map snd) . tabularLinearizeAll concr map (map (unl . snd)) . tabularLinearizes pgf lang
_ | isOpt "list" opts -> (:[]) . commaList . concat . _ | isOpt "list" opts -> (:[]) . commaList . concat .
map (map snd) . tabularLinearizeAll concr map (map (unl . snd)) . tabularLinearizes pgf lang
_ | isOpt "table" opts -> concat . _ | isOpt "table" opts -> concat . -- intersperse [[]] .
map (map (\(p,v) -> p+++":"+++v)) . tabularLinearizeAll concr map (map (\(p,v) -> p+++":"+++unl v)) . tabularLinearizes pgf lang
_ | isOpt "bracket" opts -> (:[]) . unwords . map showBracketedString . bracketedLinearize concr _ | isOpt "bracket" opts -> (:[]) . unwords . map showBracketedString . bracketedLinearize pgf lang
_ -> (:[]) . linearize concr _ -> (:[]) . unl . linearize pgf lang
-- replace each non-atomic constructor with mkC, where C is the val cat -- replace each non-atomic constructor with mkC, where C is the val cat
tree2mk pgf = showExpr [] . t2m where tree2mk pgf = showExpr [] . t2m where
t2m t = case unApp t of t2m t = case unApp t of
Just (cid,ts@(_:_)) -> mkApp (mk cid) (map t2m ts) Just (cid,ts@(_:_)) -> mkApp (mk cid) (map t2m ts)
_ -> t _ -> t
mk f = case functionType pgf f of mk = mkCId . ("mk" ++) . showCId . lookValCat (abstract pgf)
Just ty -> let (_,cat,_) = unType ty
in "mk" ++ cat unlex opts lang = stringOps Nothing (getUnlex opts lang ++ map prOpt opts) ----
Nothing -> f
getUnlex opts lang = case words (valStrOpts "unlexer" "" opts) of
lexs -> case lookup lang
[(mkCId la,tail le) | lex <- lexs, let (la,le) = span (/='=') lex, not (null le)] of
Just le -> chunks ',' le
_ -> []
commaList [] = [] commaList [] = []
commaList ws = concat $ head ws : map (", " ++) (tail ws) commaList ws = concat $ head ws : map (", " ++) (tail ws)
-- Proposed logic of coding in unlexing:
-- - If lang has no coding flag, or -to_utf8 is not in opts, just opts are used.
-- - If lang has flag coding=utf8, -to_utf8 is ignored.
-- - If lang has coding=other, and -to_utf8 is in opts, from_other is applied first.
-- THIS DOES NOT WORK UNFORTUNATELY - can't use the grammar flag properly
{-
unlexx pgf opts lang = {- trace (unwords optsC) $ -} stringOps Nothing optsC where ----
optsC = case lookConcrFlag pgf (mkCId lang) (mkCId "coding") of
Just (LStr "utf8") -> filter (/="to_utf8") $ map prOpt opts
Just (LStr other) | isOpt "to_utf8" opts ->
let cod = ("from_" ++ other)
in cod : filter (/=cod) (map prOpt opts)
_ -> map prOpt opts
-}
optRestricted opts pgf =
restrictPGF (\f -> and [hasLin pgf la f | la <- optLangs pgf opts]) pgf
optLang = optLangFlag "lang" optLang = optLangFlag "lang"
optLangs = optLangsFlag "lang" optLangs = optLangsFlag "lang"
optLangFlag flag pgf opts = optLangsFlag f pgf opts = case valStrOpts f "" opts of
case optLangsFlag flag pgf opts of "" -> languages pgf
[] -> fail "no language specified" lang -> map (completeLang pgf) (chunks ',' lang)
(l:ls) -> return l completeLang pgf la = let cla = (mkCId la) in
if elem cla (languages pgf)
then cla
else (mkCId (showCId (abstractName pgf) ++ la))
optLangsFlag flag pgf opts = optLangFlag f pgf opts = head $ optLangsFlag f pgf opts ++ [wildCId]
case valStrOpts flag "" opts of
"" -> Map.elems langs
str -> mapMaybe (completeLang pgf) (chunks ',' str)
where
langs = languages pgf
completeLang pgf la = optOpenTypes opts = case valStrOpts "openclass" "" opts of
mplus (Map.lookup la langs) "" -> []
(Map.lookup (abstractName pgf ++ la) langs) cats -> mapMaybe readType (chunks ',' cats)
optProbs opts pgf = case valStrOpts "probs" "" opts of
"" -> return pgf
file -> do
probs <- restricted $ readProbabilitiesFromFile file pgf
return (setProbabilities probs pgf)
optFile opts = valStrOpts "file" "_gftmp" opts optFile opts = valStrOpts "file" "_gftmp" opts
optType pgf opts = optType pgf opts =
let readOpt str = case readType str of let str = valStrOpts "cat" (showCId $ lookStartCat pgf) opts
Just ty -> case checkType pgf ty of in case readType str of
Left err -> error err Just ty -> case checkType pgf ty of
Right ty -> ty Left tcErr -> error $ render (ppTcError tcErr)
Nothing -> error ("Can't parse '"++str++"' as a type") Right ty -> ty
in maybeStrOpts "cat" (startCat pgf) readOpt opts Nothing -> error ("Can't parse '"++str++"' as a type")
optViewFormat opts = valStrOpts "format" "png" opts optViewFormat opts = valStrOpts "format" "png" opts
optViewGraph opts = valStrOpts "view" "open" opts optViewGraph opts = valStrOpts "view" "open" opts
optNum opts = valIntOpts "number" 1 opts optNum opts = valIntOpts "number" 1 opts
optNumInf opts = valIntOpts "number" 1000000000 opts ---- 10^9 optNumInf opts = valIntOpts "number" 1000000000 opts ---- 10^9
takeOptNum opts = take (optNumInf opts) takeOptNum opts = take (optNumInf opts)
returnFromExprs show_p es = returnFromExprs es = return $ case es of
return $ [] -> pipeMessage "no trees found"
case es of _ -> fromExprs es
[] -> pipeMessage "no trees found"
_ -> fromExprs show_p es
prGrammar pgf opts prGrammar (Env pgf mos) opts
| isOpt "pgf" opts = do | isOpt "pgf" opts = do
let outfile = valStrOpts "file" (abstractName pgf ++ ".pgf") opts let pgf1 = if isOpt "opt" opts then optimizePGF pgf else pgf
restricted $ writePGF outfile pgf let outfile = valStrOpts "file" (showCId (abstractName pgf) ++ ".pgf") opts
restricted $ encodeFile outfile pgf1
putStrLn $ "wrote file " ++ outfile putStrLn $ "wrote file " ++ outfile
return void return void
| isOpt "cats" opts = return $ fromString $ unwords $ categories pgf | isOpt "cats" opts = return $ fromString $ unwords $ map showCId $ categories pgf
| isOpt "funs" opts = return $ fromString $ unlines [showFun pgf f ty | f <- functions pgf, Just ty <- [functionType pgf f]] | isOpt "funs" opts = return $ fromString $ unlines $ map showFun $ funsigs pgf
| isOpt "fullform" opts = return $ fromString $ concatMap prFullFormLexicon $ optLangs pgf opts | isOpt "fullform" opts = return $ fromString $ concatMap (morpho mos "" prFullFormLexicon) $ optLangs pgf opts
| isOpt "langs" opts = return $ fromString $ unwords $ Map.keys $ languages pgf | isOpt "langs" opts = return $ fromString $ unwords $ map showCId $ languages pgf
| isOpt "lexc" opts = return $ fromString $ concatMap prLexcLexicon $ optLangs pgf opts | isOpt "lexc" opts = return $ fromString $ concatMap (morpho mos "" prLexcLexicon) $ optLangs pgf opts
| isOpt "missing" opts = return $ fromString $ unlines $ [unwords (concreteName concr:":":[f | f <- functions pgf, not (hasLinearization concr f)]) | | isOpt "missing" opts = return $ fromString $ unlines $ [unwords (showCId la:":": map showCId cs) |
concr <- optLangs pgf opts] la <- optLangs pgf opts, let cs = missingLins pgf la]
| isOpt "words" opts = return $ fromString $ concatMap prAllWords $ optLangs pgf opts | isOpt "words" opts = return $ fromString $ concatMap (morpho mos "" prAllWords) $ optLangs pgf opts
| otherwise = do fmt <- readOutputFormat (valStrOpts "printer" "pgf_pretty" opts) | otherwise = do fmt <- readOutputFormat (valStrOpts "printer" "pgf_pretty" opts)
return $ fromString $ concatMap snd $ exportPGF noOptions fmt pgf return $ fromString $ concatMap snd $ exportPGF noOptions fmt pgf
showFun pgf id ty = kwd++" "++ id ++ " : " ++ showType [] ty funsigs pgf = [(f,ty) | (f,(ty,_,_,_)) <- Map.assocs (funs (abstract pgf))]
where showFun (f,ty) = showCId f ++ " : " ++ showType [] ty ++ " ;"
kwd | functionIsDataCon pgf id = "data"
| otherwise = "fun"
morphos pgf opts s = morphos (Env pgf mos) opts s =
[(s,lookupMorpho concr s) | concr <- optLangs pgf opts] [(s,morpho mos [] (\mo -> lookupMorpho mo s) la) | la <- optLangs pgf opts]
morpho mos z f la = maybe z f $ Map.lookup la mos
optMorpho (Env pgf mos) opts = morpho mos (error "no morpho") id (head (optLangs pgf opts))
optClitics opts = case valStrOpts "clitics" "" opts of optClitics opts = case valStrOpts "clitics" "" opts of
"" -> [] "" -> []
@@ -820,28 +931,18 @@ pgfCommands = Map.fromList [
-- ps -f -g s returns g (f s) -- ps -f -g s returns g (f s)
treeOps pgf opts s = foldr app s (reverse opts) where treeOps pgf opts s = foldr app s (reverse opts) where
app (OOpt op) | Just (Left f) <- treeOp pgf op = f app (OOpt op) | Just (Left f) <- treeOp pgf op = f
app (OFlag op (VId x)) | Just (Right f) <- treeOp pgf op = f x app (OFlag op (VId x)) | Just (Right f) <- treeOp pgf op = f (mkCId x)
app _ = id app _ = id
morphoMissing :: Concr -> [String] -> [String]
morphoMissing = morphoClassify False
morphoKnown :: Concr -> [String] -> [String]
morphoKnown = morphoClassify True
morphoClassify :: Bool -> Concr -> [String] -> [String]
morphoClassify k concr ws = [w | w <- ws, k /= null (lookupMorpho concr w), notLiteral w] where
notLiteral w = not (all isDigit w)
treeOpOptions pgf = [(op,expl) | (op,(expl,Left _)) <- allTreeOps pgf] treeOpOptions pgf = [(op,expl) | (op,(expl,Left _)) <- allTreeOps pgf]
treeOpFlags pgf = [(op,expl) | (op,(expl,Right _)) <- allTreeOps pgf] treeOpFlags pgf = [(op,expl) | (op,(expl,Right _)) <- allTreeOps pgf]
translationQuiz :: Maybe Expr -> PGF -> Concr -> Concr -> Type -> IO () translationQuiz :: Maybe Expr -> PGF -> Language -> Language -> Type -> IO ()
translationQuiz mex pgf ig og typ = do translationQuiz mex pgf ig og typ = do
tts <- translationList mex pgf ig og typ infinity tts <- translationList mex pgf ig og typ infinity
mkQuiz "Welcome to GF Translation Quiz." tts mkQuiz "Welcome to GF Translation Quiz." tts
morphologyQuiz :: Maybe Expr -> PGF -> Concr -> Type -> IO () morphologyQuiz :: Maybe Expr -> PGF -> Language -> Type -> IO ()
morphologyQuiz mex pgf ig typ = do morphologyQuiz mex pgf ig typ = do
tts <- morphologyList mex pgf ig typ infinity tts <- morphologyList mex pgf ig typ infinity
mkQuiz "Welcome to GF Morphology Quiz." tts mkQuiz "Welcome to GF Morphology Quiz." tts
@@ -850,28 +951,30 @@ morphologyQuiz mex pgf ig typ = do
infinity :: Int infinity :: Int
infinity = 256 infinity = 256
prLexcLexicon :: Concr -> String prLexcLexicon :: Morpho -> String
prLexcLexicon concr = prLexcLexicon mo =
unlines $ "Multichar_Symbols":multichars:"":"LEXICON Root" : [prLexc l p ++ ":" ++ w ++ " # ;" | (w,lps) <- morpho, (l,p,_) <- lps] ++ ["END"] unlines $ "Multichar_Symbols":multichars:"":"LEXICON Root" : [prLexc l p ++ ":" ++ w ++ " # ;" | (w,lps) <- morpho, (l,p) <- lps] ++ ["END"]
where where
morpho = fullFormLexicon concr morpho = fullFormLexicon mo
prLexc l p = l ++ concat (mkTags (words p)) prLexc l p = showCId l ++ concat (mkTags (words p))
mkTags p = case p of mkTags p = case p of
"s":ws -> mkTags ws --- remove record field "s":ws -> mkTags ws --- remove record field
ws -> map ('+':) ws ws -> map ('+':) ws
multichars = unwords $ nub $ concat [mkTags (words p) | (w,lps) <- morpho, (l,p,_) <- lps] multichars = unwords $ nub $ concat [mkTags (words p) | (w,lps) <- morpho, (l,p) <- lps]
-- thick_A+(AAdj+Posit+Gen):thick's # ;
prFullFormLexicon :: Concr -> String prFullFormLexicon :: Morpho -> String
prFullFormLexicon concr = prFullFormLexicon mo =
unlines (map prMorphoAnalysis (fullFormLexicon concr)) unlines (map prMorphoAnalysis (fullFormLexicon mo))
prAllWords :: Concr -> String prAllWords :: Morpho -> String
prAllWords concr = prAllWords mo =
unwords [w | (w,_) <- fullFormLexicon concr] unwords [w | (w,_) <- fullFormLexicon mo]
prMorphoAnalysis :: (String,[(Lemma,Analysis)]) -> String
prMorphoAnalysis (w,lps) = prMorphoAnalysis (w,lps) =
unlines (w:[l ++ " : " ++ p ++ show prob | (l,p,prob) <- lps]) unlines (w:[showCId l ++ " : " ++ p | (l,p) <- lps])
viewGraphviz :: String -> String -> String -> [String] -> SIO CommandOutput viewGraphviz :: String -> String -> String -> [String] -> SIO CommandOutput
viewGraphviz view format name grphs = do viewGraphviz view format name grphs = do

View File

@@ -0,0 +1,831 @@
{-# LANGUAGE FlexibleInstances, UndecidableInstances #-}
module GF.Command.Commands2 (
PGFEnv,HasPGFEnv(..),pgf,concs,pgfEnv,emptyPGFEnv,pgfCommands,
options, flags,
) where
import Prelude hiding (putStrLn,(<>)) -- GHC 8.4.1 clash with Text.PrettyPrint
import PGF2
import qualified PGF as H
import GF.Compile.ToAPI(exprToAPI)
import GF.Infra.UseIO(writeUTF8File)
import GF.Infra.SIO(MonadSIO,liftSIO,putStrLn,restricted,restrictedSystem)
import GF.Command.Abstract
import GF.Command.CommandInfo
import GF.Data.Operations
import Data.List(intersperse,intersect,nub,sortBy)
import Data.Maybe
import qualified Data.Map as Map
import GF.Text.Pretty
import Control.Monad(mplus)
import qualified Control.Monad.Fail as Fail
data PGFEnv = Env {pgf::Maybe PGF,concs::Map.Map ConcName Concr}
pgfEnv pgf = Env (Just pgf) (languages pgf)
emptyPGFEnv = Env Nothing Map.empty
class (Fail.MonadFail m,MonadSIO m) => HasPGFEnv m where getPGFEnv :: m PGFEnv
instance (Monad m,HasPGFEnv m) => TypeCheckArg m where
typeCheckArg e = do env <- getPGFEnv
case pgf env of
Just gr -> either fail
(return . hsExpr . fst)
(inferExpr gr (cExpr e))
Nothing -> fail "Import a grammar before using this command"
pgfCommands :: HasPGFEnv m => Map.Map String (CommandInfo m)
pgfCommands = Map.fromList [
("aw", emptyCommandInfo {
longname = "align_words",
synopsis = "show word alignments between languages graphically",
explanation = unlines [
"Prints a set of strings in the .dot format (the graphviz format).",
"The graph can be saved in a file by the wf command as usual.",
"If the -view flag is defined, the graph is saved in a temporary file",
"which is processed by graphviz and displayed by the program indicated",
"by the flag. The target format is postscript, unless overridden by the",
"flag -format."
],
exec = needPGF $ \opts es env -> do
let cncs = optConcs env opts
if isOpt "giza" opts
then if length cncs == 2
then let giz = map (gizaAlignment pgf (snd (cncs !! 0)) (snd (cncs !! 1)) . cExpr) (toExprs es)
lsrc = unlines $ map (\(x,_,_) -> x) giz
ltrg = unlines $ map (\(_,x,_) -> x) giz
align = unlines $ map (\(_,_,x) -> x) giz
grph = if null (toExprs es) then [] else lsrc ++ "\n--end_source--\n\n"++ltrg++"\n-end_target--\n\n"++align
in return (fromString grph)
else error "For giza alignment you need exactly two languages"
else let gvOptions=graphvizDefaults{leafFont = valStrOpts "font" "" opts,
leafColor = valStrOpts "color" "" opts,
leafEdgeStyle = valStrOpts "edgestyle" "" opts
}
grph = if null (toExprs es) then [] else graphvizWordAlignment (map snd cncs) gvOptions (cExpr (head (toExprs es)))
in if isFlag "view" opts || isFlag "format" opts
then do let file s = "_grph." ++ s
let view = optViewGraph opts
let format = optViewFormat opts
restricted $ writeUTF8File (file "dot") grph
restrictedSystem $ "dot -T" ++ format ++ " " ++ file "dot" ++ " > " ++ file format
restrictedSystem $ view ++ " " ++ file format
return void
else return (fromString grph),
examples = [
("gr | aw" , "generate a tree and show word alignment as graph script"),
("gr | aw -view=\"open\"" , "generate a tree and display alignment on Mac"),
("gr | aw -view=\"eog\"" , "generate a tree and display alignment on Ubuntu"),
("gt | aw -giza | wf -file=aligns" , "generate trees, send giza alignments to file")
],
options = [
("giza", "show alignments in the Giza format; the first two languages")
],
flags = [
("format","format of the visualization file (default \"png\")"),
("lang", "alignments for this list of languages (default: all)"),
("view", "program to open the resulting file"),
("font", "font for the words"),
("color", "color for the words"),
("edgestyle", "the style for links between words")
]
}),
{-
("eb", emptyCommandInfo {
longname = "example_based",
syntax = "eb (-probs=FILE | -lang=LANG)* -file=FILE.gfe",
synopsis = "converts .gfe files to .gf files by parsing examples to trees",
explanation = unlines [
"Reads FILE.gfe and writes FILE.gf. Each expression of form",
"'%ex CAT QUOTEDSTRING' in FILE.gfe is replaced by a syntax tree.",
"This tree is the first one returned by the parser; a biased ranking",
"can be used to regulate the order. If there are more than one parses",
"the rest are shown in comments, with probabilities if the order is biased.",
"The probabilities flag and configuration file is similar to the commands",
"gr and rt. Notice that the command doesn't change the environment,",
"but the resulting .gf file must be imported separately."
],
options = [
("api","convert trees to overloaded API expressions (using Syntax not Lang)")
],
flags = [
("file","the file to be converted (suffix .gfe must be given)"),
("lang","the language in which to parse"),
("probs","file with probabilities to rank the parses")
],
exec = \env@(pgf, mos) opts _ -> do
let file = optFile opts
pgf <- optProbs opts pgf
let printer = if (isOpt "api" opts) then exprToAPI else (H.showExpr [])
let conf = configureExBased pgf (optMorpho env opts) (optLang pgf opts) printer
(file',ws) <- restricted $ parseExamplesInGrammar conf file
if null ws then return () else putStrLn ("unknown words: " ++ unwords ws)
return (fromString ("wrote " ++ file')),
needsTypeCheck = False
}),
-}
{-
("gr", emptyCommandInfo {
longname = "generate_random",
synopsis = "generate random trees in the current abstract syntax",
syntax = "gr [-cat=CAT] [-number=INT]",
examples = [
mkEx "gr -- one tree in the startcat of the current grammar",
mkEx "gr -cat=NP -number=16 -- 16 trees in the category NP",
mkEx "gr -lang=LangHin,LangTha -cat=Cl -- Cl, both in LangHin and LangTha",
mkEx "gr -probs=FILE -- generate with bias",
mkEx "gr (AdjCN ? (UseN ?)) -- generate trees of form (AdjCN ? (UseN ?))"
],
explanation = unlines [
"Generates a list of random trees, by default one tree.",
"If a tree argument is given, the command completes the Tree with values to",
"all metavariables in the tree. The generation can be biased by probabilities,",
"given in a file in the -probs flag."
],
flags = [
("cat","generation category"),
("lang","uses only functions that have linearizations in all these languages"),
("number","number of trees generated"),
("depth","the maximum generation depth"),
("probs", "file with biased probabilities (format 'f 0.4' one by line)")
],
exec = \env@(pgf, mos) opts xs -> do
pgf <- optProbs opts (optRestricted opts pgf)
gen <- newStdGen
let dp = valIntOpts "depth" 4 opts
let ts = case mexp xs of
Just ex -> H.generateRandomFromDepth gen pgf ex (Just dp)
Nothing -> H.generateRandomDepth gen pgf (optType pgf opts) (Just dp)
returnFromExprs $ take (optNum opts) ts
}),
-}
("gt", emptyCommandInfo {
longname = "generate_trees",
synopsis = "generates a list of trees, by default exhaustive",
flags = [("cat","the generation category"),
("number","the number of trees generated")],
examples = [
mkEx "gt -- all trees in the startcat",
mkEx "gt -cat=NP -number=16 -- 16 trees in the category NP"],
exec = needPGF $ \ opts _ env@(pgf,_) ->
let ts = map fst (generateAll pgf cat)
cat = optType pgf opts
in returnFromCExprs (takeOptNum opts ts),
needsTypeCheck = False
}),
("i", emptyCommandInfo {
longname = "import",
synopsis = "import a grammar from a compiled .pgf file",
explanation = unlines [
"Reads a grammar from a compiled .pgf file.",
"Old modules are discarded.",
{-
"The grammar parser depends on the file name suffix:",
" .cf context-free (labelled BNF) source",
" .ebnf extended BNF source",
" .gfm multi-module GF source",
" .gf normal GF source",
" .gfo compiled GF source",
-}
" .pgf precompiled grammar in Portable Grammar Format"
],
flags = [
-- ("probs","file with biased probabilities for generation")
],
options = [
-- ["gfo", "src", "no-cpu", "cpu", "quiet", "verbose"]
-- ("retain","retain operations (used for cc command)"),
-- ("src", "force compilation from source"),
-- ("v", "be verbose - show intermediate status information")
],
needsTypeCheck = False
}),
("l", emptyCommandInfo {
longname = "linearize",
synopsis = "convert an abstract syntax expression to string",
explanation = unlines [
"Shows the linearization of a Tree by the grammars in scope.",
"The -lang flag can be used to restrict this to fewer languages.",
"A sequence of string operations (see command ps) can be given",
"as options, and works then like a pipe to the ps command, except",
"that it only affect the strings, not e.g. the table labels.",
"These can be given separately to each language with the unlexer flag",
"whose results are prepended to the other lexer flags. The value of the",
"unlexer flag is a space-separated list of comma-separated string operation",
"sequences; see example."
],
examples = [
mkEx "l -lang=LangSwe,LangNor no_Utt -- linearize a tree to LangSwe and LangNor",
mkEx "gr -lang=LangHin -cat=Cl | l -table -to_devanagari -- hindi table",
mkEx "l -unlexer=\"LangAra=to_arabic LangHin=to_devanagari\" -- different unlexers"
],
exec = needPGF $ \ opts arg env ->
return . fromStrings . optLins env opts . map cExpr $ toExprs arg,
options = [
("all", "show all forms and variants, one by line (cf. l -list)"),
("bracket","show tree structure with brackets and paths to nodes"),
("groups", "all languages, grouped by lang, remove duplicate strings"),
("list","show all forms and variants, comma-separated on one line (cf. l -all)"),
("multi","linearize to all languages (default)"),
("table","show all forms labelled by parameters"),
("treebank","show the tree and tag linearizations with language names")
],
flags = [
("lang","the languages of linearization (comma-separated, no spaces)")
]
}),
("ma", emptyCommandInfo {
longname = "morpho_analyse",
synopsis = "print the morphological analyses of the (multiword) expression in the string",
explanation = unlines [
"Prints all the analyses of the (multiword) expression in the input string,",
"using the morphological analyser of the actual grammar (see command pg)"
],
exec = needPGF $ \opts args env ->
return ((fromString . unlines .
map prMorphoAnalysis . concatMap (morphos env opts) . toStrings) args),
flags = [
("lang","the languages of analysis (comma-separated, no spaces)")
]
}),
{-
("mq", emptyCommandInfo {
longname = "morpho_quiz",
synopsis = "start a morphology quiz",
syntax = "mq (-cat=CAT)? (-probs=FILE)? TREE?",
exec = \env@(pgf, mos) opts xs -> do
let lang = optLang pgf opts
let typ = optType pgf opts
pgf <- optProbs opts pgf
let mt = mexp xs
restricted $ morphologyQuiz mt pgf lang typ
return void,
flags = [
("lang","language of the quiz"),
("cat","category of the quiz"),
("number","maximum number of questions"),
("probs","file with biased probabilities for generation")
]
}),
-}
("p", emptyCommandInfo {
longname = "parse",
synopsis = "parse a string to abstract syntax expression",
explanation = unlines [
"Shows all trees returned by parsing a string in the grammars in scope.",
"The -lang flag can be used to restrict this to fewer languages.",
"The default start category can be overridden by the -cat flag.",
"See also the ps command for lexing and character encoding."
],
flags = [
("cat","target category of parsing"),
("lang","the languages of parsing (comma-separated, no spaces)"),
("number","maximum number of trees returned")
],
examples = [
mkEx "p \"this fish is fresh\" | l -lang=Swe -- try parsing with all languages and translate the successful parses to Swedish"
],
exec = needPGF $ \ opts ts env -> return . cParse env opts $ toStrings ts
}),
("pg", emptyCommandInfo {
longname = "print_grammar",
synopsis = "prints different information about the grammar",
exec = needPGF $ \opts _ env -> prGrammar env opts,
options = [
("cats", "show just the names of abstract syntax categories"),
("fullform", "print the fullform lexicon"),
("funs", "show just the names and types of abstract syntax functions"),
("langs", "show just the names of top concrete syntax modules"),
("lexc", "print the lexicon in Xerox LEXC format"),
("missing","show just the names of functions that have no linearization"),
("words", "print the list of words")
],
flags = [
("lang","the languages that need to be printed")
],
examples = [
mkEx "pg -langs -- show the names of top concrete syntax modules",
mkEx "pg -funs | ? grep \" S ;\" -- show functions with value cat S"
]
}),
{-
("pt", emptyCommandInfo {
longname = "put_tree",
syntax = "pt OPT? TREE",
synopsis = "return a tree, possibly processed with a function",
explanation = unlines [
"Returns a tree obtained from its argument tree by applying",
"tree processing functions in the order given in the command line",
"option list. Thus 'pt -f -g s' returns g (f s). Typical tree processors",
"are type checking and semantic computation."
],
examples = [
mkEx "pt -compute (plus one two) -- compute value",
mkEx "p \"4 dogs love 5 cats\" | pt -transfer=digits2numeral | l -- four...five..."
],
exec = \env@(pgf, mos) opts ->
returnFromExprs . takeOptNum opts . treeOps pgf opts,
options = treeOpOptions undefined{-pgf-},
flags = [("number","take at most this many trees")] ++ treeOpFlags undefined{-pgf-}
}),
-}
("rf", emptyCommandInfo {
longname = "read_file",
synopsis = "read string or tree input from a file",
explanation = unlines [
"Reads input from file. The filename must be in double quotes.",
"The input is interpreted as a string by default, and can hence be",
"piped e.g. to the parse command. The option -tree interprets the",
"input as a tree, which can be given e.g. to the linearize command.",
"The option -lines will result in a list of strings or trees, one by line."
],
options = [
("lines","return the list of lines, instead of the singleton of all contents"),
("tree","convert strings into trees")
],
exec = needPGF $ \opts _ env@(pgf, mos) -> do
let file = optFile opts
let exprs [] = ([],empty)
exprs ((n,s):ls) | null s
= exprs ls
exprs ((n,s):ls) = case readExpr s of
Just e -> let (es,err) = exprs ls
in case inferExpr pgf e of
Right (e,t) -> (e:es,err)
Left msg -> (es,"on line" <+> n <> ':' $$ msg $$ err)
Nothing -> let (es,err) = exprs ls
in (es,"on line" <+> n <> ':' <+> "parse error" $$ err)
returnFromLines ls = case exprs ls of
(es, err) | null es -> return $ pipeMessage $ render (err $$ "no trees found")
| otherwise -> return $ pipeWithMessage (map hsExpr es) (render err)
s <- restricted $ readFile file
case opts of
_ | isOpt "lines" opts && isOpt "tree" opts ->
returnFromLines (zip [1::Int ..] (lines s))
_ | isOpt "tree" opts ->
returnFromLines [(1::Int,s)]
_ | isOpt "lines" opts -> return (fromStrings $ lines s)
_ -> return (fromString s),
flags = [("file","the input file name")]
}),
("rt", emptyCommandInfo {
longname = "rank_trees",
synopsis = "show trees in an order of decreasing probability",
explanation = unlines [
"Order trees from the most to the least probable, using either",
"even distribution in each category (default) or biased as specified",
"by the file given by flag -probs=FILE, where each line has the form",
"'function probability', e.g. 'youPol_Pron 0.01'."
],
exec = needPGF $ \opts es env@(pgf, _) -> do
let tds = sortBy (\(_,p) (_,q) -> compare p q)
[(t, treeProbability pgf t) | t <- map cExpr (toExprs es)]
if isOpt "v" opts
then putStrLn $
unlines [PGF2.showExpr [] t ++ "\t--" ++ show d | (t,d) <- tds]
else return ()
returnFromExprs $ map (hsExpr . fst) tds,
flags = [
("probs","probabilities from this file (format 'f 0.6' per line)")
],
options = [
("v","show all trees with their probability scores")
],
examples = [
mkEx "p \"you are here\" | rt -probs=probs | pt -number=1 -- most probable result"
]
}),
{-
("tq", emptyCommandInfo {
longname = "translation_quiz",
syntax = "tq -from=LANG -to=LANG (-cat=CAT)? (-probs=FILE)? TREE?",
synopsis = "start a translation quiz",
exec = \env@(pgf, mos) opts xs -> do
let from = optLangFlag "from" pgf opts
let to = optLangFlag "to" pgf opts
let typ = optType pgf opts
let mt = mexp xs
pgf <- optProbs opts pgf
restricted $ translationQuiz mt pgf from to typ
return void,
flags = [
("from","translate from this language"),
("to","translate to this language"),
("cat","translate in this category"),
("number","the maximum number of questions"),
("probs","file with biased probabilities for generation")
],
examples = [
mkEx ("tq -from=Eng -to=Swe -- any trees in startcat"),
mkEx ("tq -from=Eng -to=Swe (AdjCN (PositA ?2) (UseN ?)) -- only trees of this form")
]
}),
("vd", emptyCommandInfo {
longname = "visualize_dependency",
synopsis = "show word dependency tree graphically",
explanation = unlines [
"Prints a dependency tree in the .dot format (the graphviz format, default)",
"or the CoNLL/MaltParser format (flag -output=conll for training, malt_input",
"for unanalysed input).",
"By default, the last argument is the head of every abstract syntax",
"function; moreover, the head depends on the head of the function above.",
"The graph can be saved in a file by the wf command as usual.",
"If the -view flag is defined, the graph is saved in a temporary file",
"which is processed by graphviz and displayed by the program indicated",
"by the flag. The target format is png, unless overridden by the",
"flag -format."
],
exec = \env@(pgf, mos) opts es -> do
let debug = isOpt "v" opts
let file = valStrOpts "file" "" opts
let outp = valStrOpts "output" "dot" opts
mlab <- case file of
"" -> return Nothing
_ -> (Just . H.getDepLabels . lines) `fmap` restricted (readFile file)
let lang = optLang pgf opts
let grphs = unlines $ map (H.graphvizDependencyTree outp debug mlab Nothing pgf lang) es
if isFlag "view" opts || isFlag "format" opts then do
let file s = "_grphd." ++ s
let view = optViewGraph opts
let format = optViewFormat opts
restricted $ writeUTF8File (file "dot") grphs
restrictedSystem $ "dot -T" ++ format ++ " " ++ file "dot" ++ " > " ++ file format
restrictedSystem $ view ++ " " ++ file format
return void
else return $ fromString grphs,
examples = [
mkEx "gr | vd -- generate a tree and show dependency tree in .dot",
mkEx "gr | vd -view=open -- generate a tree and display dependency tree on a Mac",
mkEx "gr -number=1000 | vd -file=dep.labels -output=malt -- generate training treebank",
mkEx "gr -number=100 | vd -file=dep.labels -output=malt_input -- generate test sentences"
],
options = [
("v","show extra information")
],
flags = [
("file","configuration file for labels per fun, format 'fun l1 ... label ... l2'"),
("format","format of the visualization file (default \"png\")"),
("output","output format of graph source (default \"dot\")"),
("view","program to open the resulting file (default \"open\")"),
("lang","the language of analysis")
]
}),
-}
("vp", emptyCommandInfo {
longname = "visualize_parse",
synopsis = "show parse tree graphically",
explanation = unlines [
"Prints a parse tree in the .dot format (the graphviz format).",
"The graph can be saved in a file by the wf command as usual.",
"If the -view flag is defined, the graph is saved in a temporary file",
"which is processed by graphviz and displayed by the program indicated",
"by the flag. The target format is png, unless overridden by the",
"flag -format."
],
exec = needPGF $ \opts arg env@(pgf, concs) ->
do let es = toExprs arg
let concs = optConcs env opts
let gvOptions=graphvizDefaults{noLeaves = isOpt "noleaves" opts && not (isOpt "showleaves" opts),
noFun = isOpt "nofun" opts || not (isOpt "showfun" opts),
noCat = isOpt "nocat" opts && not (isOpt "showcat" opts),
nodeFont = valStrOpts "nodefont" "" opts,
leafFont = valStrOpts "leaffont" "" opts,
nodeColor = valStrOpts "nodecolor" "" opts,
leafColor = valStrOpts "leafcolor" "" opts,
nodeEdgeStyle = valStrOpts "nodeedgestyle" "solid" opts,
leafEdgeStyle = valStrOpts "leafedgestyle" "dashed" opts
}
let grph= if null es || null concs
then []
else graphvizParseTree (snd (head concs)) gvOptions (cExpr (head es))
if isFlag "view" opts || isFlag "format" opts then do
let file s = "_grph." ++ s
let view = optViewGraph opts
let format = optViewFormat opts
restricted $ writeUTF8File (file "dot") grph
restrictedSystem $ "dot -T" ++ format ++ " " ++ file "dot" ++ " > " ++ file format
restrictedSystem $ view ++ " " ++ file format
return void
else return $ fromString grph,
examples = [
mkEx "p -lang=Eng \"John walks\" | vp -- generate a tree and show parse tree as .dot script",
mkEx "gr | vp -view=\"open\" -- generate a tree and display parse tree on a Mac"
],
options = [
("showcat","show categories in the tree nodes (default)"),
("nocat","don't show categories"),
("showfun","show function names in the tree nodes"),
("nofun","don't show function names (default)"),
("showleaves","show the leaves of the tree (default)"),
("noleaves","don't show the leaves of the tree (i.e., only the abstract tree)")
],
flags = [
("lang","the language to visualize"),
("format","format of the visualization file (default \"png\")"),
("view","program to open the resulting file (default \"open\")"),
("nodefont","font for tree nodes (default: Times -- graphviz standard font)"),
("leaffont","font for tree leaves (default: nodefont)"),
("nodecolor","color for tree nodes (default: black -- graphviz standard color)"),
("leafcolor","color for tree leaves (default: nodecolor)"),
("nodeedgestyle","edge style between tree nodes (solid/dashed/dotted/bold, default: solid)"),
("leafedgestyle","edge style for links to leaves (solid/dashed/dotted/bold, default: dashed)")
]
}),
("vt", emptyCommandInfo {
longname = "visualize_tree",
synopsis = "show a set of trees graphically",
explanation = unlines [
"Prints a set of trees in the .dot format (the graphviz format).",
"The graph can be saved in a file by the wf command as usual.",
"If the -view flag is defined, the graph is saved in a temporary file",
"which is processed by graphviz and displayed by the program indicated",
"by the flag. The target format is postscript, unless overridden by the",
"flag -format."
],
exec = needPGF $ \opts arg env@(pgf, _) ->
let es = toExprs arg in
if isOpt "api" opts
then do
mapM_ (putStrLn . exprToAPI) es
return void
else do
let gvOptions=graphvizDefaults{noFun = isOpt "nofun" opts,
noCat = isOpt "nocat" opts,
nodeFont = valStrOpts "nodefont" "" opts,
nodeColor = valStrOpts "nodecolor" "" opts,
nodeEdgeStyle = valStrOpts "nodeedgestyle" "solid" opts
}
let grph = unlines (map (graphvizAbstractTree pgf gvOptions . cExpr) es)
if isFlag "view" opts || isFlag "format" opts then do
let file s = "_grph." ++ s
let view = optViewGraph opts
let format = optViewFormat opts
restricted $ writeUTF8File (file "dot") grph
restrictedSystem $ "dot -T" ++ format ++ " " ++ file "dot" ++ " > " ++ file format
restrictedSystem $ view ++ " " ++ file format
return void
else return $ fromString grph,
examples = [
mkEx "p \"hello\" | vt -- parse a string and show trees as graph script",
mkEx "p \"hello\" | vt -view=\"open\" -- parse a string and display trees on a Mac"
],
options = [
("api", "show the tree with function names converted to 'mkC' with value cats C"),
("nofun","don't show functions but only categories"),
("nocat","don't show categories but only functions")
],
flags = [
("format","format of the visualization file (default \"png\")"),
("view","program to open the resulting file (default \"open\")"),
("nodefont","font for tree nodes (default: Times -- graphviz standard font)"),
("nodecolor","color for tree nodes (default: black -- graphviz standard color)"),
("nodeedgestyle","edge style between tree nodes (solid/dashed/dotted/bold, default: solid)")
]
}),
("ai", emptyCommandInfo {
longname = "abstract_info",
syntax = "ai IDENTIFIER or ai EXPR",
synopsis = "Provides an information about a function, an expression or a category from the abstract syntax",
explanation = unlines [
"The command has one argument which is either function, expression or",
"a category defined in the abstract syntax of the current grammar. ",
"If the argument is a function then its type is printed out.",
"If it is a category then the category definition is printed.",
"If a whole expression is given it prints the expression with refined",
"metavariables and the type of the expression."
],
exec = needPGF $ \opts args env@(pgf,cncs) ->
case map cExpr (toExprs args) of
[e] -> case unApp e of
Just (id,[]) -> return (fromString
(case functionType pgf id of
Just ty -> showFun id ty
Nothing -> let funs = functionsByCat pgf id
in showCat id funs))
where
showCat c funs = "cat "++c++
" ;\n\n"++
unlines [showFun f ty| f<-funs,
Just ty <- [functionType pgf f]]
showFun f ty = "fun "++f++" : "++showType [] ty++" ;"
_ -> case inferExpr pgf e of
Left msg -> error msg
Right (e,ty) -> do putStrLn ("Expression: "++PGF2.showExpr [] e)
putStrLn ("Type: "++PGF2.showType [] ty)
putStrLn ("Probability: "++show (treeProbability pgf e))
return void
_ -> do putStrLn "a single function name or category name is expected"
return void,
needsTypeCheck = False
})
]
where
cParse env@(pgf,_) opts ss =
parsed [ parse cnc cat s | s<-ss,(lang,cnc)<-cncs]
where
cat = optType pgf opts
cncs = optConcs env opts
parsed rs = Piped (Exprs ts,unlines msgs)
where
ts = [hsExpr t|ParseOk ts<-rs,(t,p)<-takeOptNum opts ts]
msgs = concatMap mkMsg rs
mkMsg (ParseOk ts) = (map (PGF2.showExpr [] . fst).takeOptNum opts) ts
mkMsg (ParseFailed _ tok) = ["Parse failed: "++tok]
mkMsg (ParseIncomplete) = ["The sentence is incomplete"]
optLins env opts ts = case opts of
_ | isOpt "groups" opts ->
concatMap snd $ groupResults
[[(lang, s) | (lang,concr) <- optConcs env opts,s <- linear opts lang concr t] | t <- ts]
_ -> concatMap (optLin env opts) ts
optLin env@(pgf,_) opts t =
case opts of
_ | isOpt "treebank" opts ->
(abstractName pgf ++ ": " ++ PGF2.showExpr [] t) :
[lang ++ ": " ++ s | (lang,concr) <- optConcs env opts, s<-linear opts lang concr t]
_ -> [s | (lang,concr) <- optConcs env opts, s<-linear opts lang concr t]
linear :: [Option] -> ConcName -> Concr -> PGF2.Expr -> [String]
linear opts lang concr = case opts of
_ | isOpt "all" opts -> concat . map (map snd) . tabularLinearizeAll concr
_ | isOpt "list" opts -> (:[]) . commaList .
concatMap (map snd) . tabularLinearizeAll concr
_ | isOpt "table" opts -> concatMap (map (\(p,v) -> p+++":"+++v)) . tabularLinearizeAll concr
_ | isOpt "bracket" opts -> (:[]) . unwords . map showBracketedString . bracketedLinearize concr
_ -> (:[]) . linearize concr
groupResults :: [[(ConcName,String)]] -> [(ConcName,[String])]
groupResults = Map.toList . foldr more Map.empty . start . concat
where
start ls = [(l,[s]) | (l,s) <- ls]
more (l,s) =
Map.insertWith (\ [x] xs -> if elem x xs then xs else (x : xs)) l s
optConcs = optConcsFlag "lang"
optConcsFlag f (pgf,cncs) opts =
case valStrOpts f "" opts of
"" -> Map.toList cncs
lang -> mapMaybe pickLang (chunks ',' lang)
where
pickLang l = pick l `mplus` pick fl
where
fl = abstractName pgf++l
pick l = (,) l `fmap` Map.lookup l cncs
{-
-- replace each non-atomic constructor with mkC, where C is the val cat
tree2mk pgf = H.showExpr [] . t2m where
t2m t = case H.unApp t of
Just (cid,ts@(_:_)) -> H.mkApp (mk cid) (map t2m ts)
_ -> t
mk = H.mkCId . ("mk" ++) . H.showCId . H.lookValCat (H.abstract pgf)
unlex opts lang = stringOps Nothing (getUnlex opts lang ++ map prOpt opts) ----
getUnlex opts lang = case words (valStrOpts "unlexer" "" opts) of
lexs -> case lookup lang
[(H.mkCId la,tail le) | lex <- lexs, let (la,le) = span (/='=') lex, not (null le)] of
Just le -> chunks ',' le
_ -> []
-}
commaList [] = []
commaList ws = concat $ head ws : map (", " ++) (tail ws)
optFile opts = valStrOpts "file" "_gftmp" opts
optType pgf opts =
case listFlags "cat" opts of
v:_ -> let str = valueString v
in case readType str of
Just ty -> case checkType pgf ty of
Left msg -> error msg
Right ty -> ty
Nothing -> error ("Can't parse '"++str++"' as a type")
_ -> startCat pgf
optViewFormat opts = valStrOpts "format" "png" opts
optViewGraph opts = valStrOpts "view" "open" opts
{-
optNum opts = valIntOpts "number" 1 opts
-}
optNumInf opts = valIntOpts "number" 1000000000 opts ---- 10^9
takeOptNum opts = take (optNumInf opts)
returnFromCExprs = returnFromExprs . map hsExpr
returnFromExprs es =
return $ case es of
[] -> pipeMessage "no trees found"
_ -> fromExprs es
prGrammar env@(pgf,cncs) opts
| isOpt "langs" opts = return . fromString . unwords $ (map fst (optConcs env opts))
| isOpt "cats" opts = return . fromString . unwords $ categories pgf
| isOpt "funs" opts = return . fromString . unwords $ functions pgf
| isOpt "missing" opts = return . fromString . unwords $
[f | f <- functions pgf, not (and [hasLinearization concr f | (_,concr) <- optConcs env opts])]
| isOpt "fullform" opts = return $ fromString $ concatMap (prFullFormLexicon . snd) $ optConcs env opts
| isOpt "words" opts = return $ fromString $ concatMap (prAllWords . snd) $ optConcs env opts
| isOpt "lexc" opts = return $ fromString $ concatMap (prLexcLexicon . snd) $ optConcs env opts
| otherwise = return void
gizaAlignment pgf src_cnc tgt_cnc e =
let src_res = alignWords src_cnc e
tgt_res = alignWords tgt_cnc e
alignment = [show i++"-"++show j | (i,(_,src_fids)) <- zip [0..] src_res, (j,(_,tgt_fids)) <- zip [0..] tgt_res, not (null (intersect src_fids tgt_fids))]
in (unwords (map fst src_res), unwords (map fst tgt_res), unwords alignment)
morphos env opts s =
[(s,res) | (lang,concr) <- optConcs env opts, let res = lookupMorpho concr s, not (null res)]
{-
mexp xs = case xs of
t:_ -> Just t
_ -> Nothing
-}
-- ps -f -g s returns g (f s)
{-
treeOps pgf opts s = foldr app s (reverse opts) where
app (OOpt op) | Just (Left f) <- treeOp pgf op = f
app (OFlag op (VId x)) | Just (Right f) <- treeOp pgf op = f (H.mkCId x)
app _ = id
treeOpOptions pgf = [(op,expl) | (op,(expl,Left _)) <- allTreeOps pgf]
treeOpFlags pgf = [(op,expl) | (op,(expl,Right _)) <- allTreeOps pgf]
translationQuiz :: Maybe H.Expr -> H.PGF -> H.Language -> H.Language -> H.Type -> IO ()
translationQuiz mex pgf ig og typ = do
tts <- translationList mex pgf ig og typ infinity
mkQuiz "Welcome to GF Translation Quiz." tts
morphologyQuiz :: Maybe H.Expr -> H.PGF -> H.Language -> H.Type -> IO ()
morphologyQuiz mex pgf ig typ = do
tts <- morphologyList mex pgf ig typ infinity
mkQuiz "Welcome to GF Morphology Quiz." tts
-- | the maximal number of precompiled quiz problems
infinity :: Int
infinity = 256
-}
prLexcLexicon :: Concr -> String
prLexcLexicon concr =
unlines $ "Multichar_Symbols":multichars:"":"LEXICON Root" : [prLexc l p ++ ":" ++ w ++ " # ;" | (w,lps) <- morpho, (l,p,_) <- lps] ++ ["END"]
where
morpho = fullFormLexicon concr
prLexc l p = l ++ concat (mkTags (words p))
mkTags p = case p of
"s":ws -> mkTags ws --- remove record field
ws -> map ('+':) ws
multichars = unwords $ nub $ concat [mkTags (words p) | (w,lps) <- morpho, (l,p,_) <- lps]
-- thick_A+(AAdj+Posit+Gen):thick's # ;
prFullFormLexicon :: Concr -> String
prFullFormLexicon concr =
unlines (map prMorphoAnalysis (fullFormLexicon concr))
prAllWords :: Concr -> String
prAllWords concr =
unwords [w | (w,_) <- fullFormLexicon concr]
prMorphoAnalysis :: (String,[MorphoAnalysis]) -> String
prMorphoAnalysis (w,lps) =
unlines (w:[fun ++ " : " ++ cat | (fun,cat,p) <- lps])
hsExpr c =
case unApp c of
Just (f,cs) -> H.mkApp (H.mkCId f) (map hsExpr cs)
_ -> case unStr c of
Just str -> H.mkStr str
_ -> case unInt c of
Just n -> H.mkInt n
_ -> case unFloat c of
Just d -> H.mkFloat d
_ -> error $ "GF.Command.Commands2.hsExpr "++show c
cExpr e =
case H.unApp e of
Just (f,es) -> mkApp (H.showCId f) (map cExpr es)
_ -> case H.unStr e of
Just str -> mkStr str
_ -> case H.unInt e of
Just n -> mkInt n
_ -> case H.unFloat e of
Just d -> mkFloat d
_ -> error $ "GF.Command.Commands2.cExpr "++show e
needPGF exec opts ts =
do Env mb_pgf cncs <- getPGFEnv
case mb_pgf of
Just pgf -> liftSIO $ exec opts ts (pgf,cncs)
_ -> fail "Import a grammar before using this command"

View File

@@ -3,6 +3,7 @@
-- elsewhere -- elsewhere
module GF.Command.CommonCommands where module GF.Command.CommonCommands where
import Data.List(sort) import Data.List(sort)
import Data.Char (isSpace)
import GF.Command.CommandInfo import GF.Command.CommandInfo
import qualified Data.Map as Map import qualified Data.Map as Map
import GF.Infra.SIO import GF.Infra.SIO
@@ -15,7 +16,7 @@ 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 PGF2(showExpr) import qualified PGF as H(showCId,showExpr,toATree,toTrie,Trie(..))
extend old new = Map.union (Map.fromList new) old -- Map.union is left-biased extend old new = Map.union (Map.fromList new) old -- Map.union is left-biased
@@ -101,7 +102,9 @@ commonCommands = fmap (mapCommandExec liftSIO) $ Map.fromList [
"To see transliteration tables, use command ut." "To see transliteration tables, use command ut."
], ],
examples = [ examples = [
-- mkEx "l (EAdd 3 4) | ps -code -- linearize code-like output",
mkEx "l (EAdd 3 4) | ps -unlexcode -- linearize code-like output", mkEx "l (EAdd 3 4) | ps -unlexcode -- linearize code-like output",
-- mkEx "ps -lexer=code | p -cat=Exp -- parse code-like input",
mkEx "ps -lexcode | p -cat=Exp -- parse code-like input", mkEx "ps -lexcode | p -cat=Exp -- parse code-like input",
mkEx "gr -cat=QCl | l | ps -bind -- linearization output from LangFin", mkEx "gr -cat=QCl | l | ps -bind -- linearization output from LangFin",
mkEx "ps -to_devanagari \"A-p\" -- show Devanagari in UTF8 terminal", mkEx "ps -to_devanagari \"A-p\" -- show Devanagari in UTF8 terminal",
@@ -114,11 +117,13 @@ commonCommands = fmap (mapCommandExec liftSIO) $ Map.fromList [
let (os,fs) = optsAndFlags opts let (os,fs) = optsAndFlags opts
trans <- optTranslit opts trans <- optTranslit opts
if isOpt "lines" opts case opts of
then return $ fromStrings $ map (trans . stringOps (envFlag fs) (map prOpt os)) $ toStrings x _ | isOpt "lines" opts -> return $ fromStrings $ map (trans . stringOps (envFlag fs) (map prOpt os)) $ toStrings x
else return ((fromString . trans . stringOps (envFlag fs) (map prOpt os) . toString) x), _ | isOpt "paragraphs" opts -> return $ fromStrings $ map (trans . stringOps (envFlag fs) (map prOpt os)) $ toParagraphs $ toStrings x
_ -> return ((fromString . trans . stringOps (envFlag fs) (map prOpt os) . toString) x),
options = [ options = [
("lines","apply the operation separately to each input line, returning a list of lines") ("lines","apply the operation separately to each input line, returning a list of lines"),
("paragraphs","apply separately to each input paragraph (as separated by empty lines), returning a list of lines")
] ++ ] ++
stringOpOptions, stringOpOptions,
flags = [ flags = [
@@ -173,6 +178,12 @@ commonCommands = fmap (mapCommandExec liftSIO) $ Map.fromList [
mkEx "gt | l | ? wc -- generate trees, linearize, and count words" mkEx "gt | l | ? wc -- generate trees, linearize, and count words"
] ]
}), }),
("tt", emptyCommandInfo {
longname = "to_trie",
syntax = "to_trie",
synopsis = "combine a list of trees into a trie",
exec = \ _ -> return . fromString . trie . toExprs
}),
("ut", emptyCommandInfo { ("ut", emptyCommandInfo {
longname = "unicode_table", longname = "unicode_table",
synopsis = "show a transliteration table for a unicode character set", synopsis = "show a transliteration table for a unicode character set",
@@ -220,6 +231,7 @@ envFlag fs =
_ -> Nothing _ -> Nothing
stringOpOptions = sort $ [ stringOpOptions = sort $ [
("bind","bind tokens separated by Prelude.BIND, i.e. &+"),
("chars","lexer that makes every non-space character a token"), ("chars","lexer that makes every non-space character a token"),
("from_cp1251","decode from cp1251 (Cyrillic used in Bulgarian resource)"), ("from_cp1251","decode from cp1251 (Cyrillic used in Bulgarian resource)"),
("from_utf8","decode from utf8 (default)"), ("from_utf8","decode from utf8 (default)"),
@@ -244,6 +256,27 @@ stringOpOptions = sort $ [
("to_" ++ p, "from GF " ++ n ++ " transliteration to unicode")] | ("to_" ++ p, "from GF " ++ n ++ " transliteration to unicode")] |
(p,n) <- transliterationPrintNames] (p,n) <- transliterationPrintNames]
trie = render . pptss . H.toTrie . map H.toATree
where
pptss [ts] = "*"<+>nest 2 (ppts ts)
pptss tss = vcat [i<+>nest 2 (ppts ts)|(i,ts)<-zip [(1::Int)..] tss]
ppts = vcat . map ppt
ppt t =
case t of
H.Oth e -> pp (H.showExpr [] e)
H.Ap f [[]] -> pp (H.showCId f)
H.Ap f tss -> H.showCId f $$ nest 2 (pptss tss)
-- ** Converting command input -- ** Converting command input
toString = unwords . toStrings toString = unwords . toStrings
toLines = unlines . toStrings toLines = unlines . toStrings
toParagraphs = map (unwords . words) . toParas
where
toParas ls = case break (all isSpace) ls of
([],[]) -> []
([],_:ll) -> toParas ll
(l, []) -> [unwords l]
(l, _:ll) -> unwords l : toParas ll

View File

@@ -1,7 +1,7 @@
module GF.Command.Importing (importGrammar, importSource) where module GF.Command.Importing (importGrammar, importSource) where
import PGF2 import PGF
import PGF2.Internal(unionPGF) import PGF.Internal(optimizePGF,unionPGF,msgUnionPGF)
import GF.Compile import GF.Compile
import GF.Compile.Multi (readMulti) import GF.Compile.Multi (readMulti)
@@ -17,16 +17,14 @@ import GF.Data.ErrM
import System.FilePath import System.FilePath
import qualified Data.Set as Set import qualified Data.Set as Set
import qualified Data.Map as Map
import Control.Monad(foldM)
-- import a grammar in an environment where it extends an existing grammar -- import a grammar in an environment where it extends an existing grammar
importGrammar :: Maybe PGF -> Options -> [FilePath] -> IO (Maybe PGF) importGrammar :: PGF -> Options -> [FilePath] -> IO PGF
importGrammar pgf0 _ [] = return pgf0 importGrammar pgf0 _ [] = return pgf0
importGrammar pgf0 opts files = importGrammar pgf0 opts files =
case takeExtensions (last files) of case takeExtensions (last files) of
".cf" -> fmap Just $ importCF opts files getBNFCRules bnfc2cf ".cf" -> importCF opts files getBNFCRules bnfc2cf
".ebnf" -> fmap Just $ importCF opts files getEBNFRules ebnf2cf ".ebnf" -> importCF opts files getEBNFRules ebnf2cf
".gfm" -> do ".gfm" -> do
ascss <- mapM readMulti files ascss <- mapM readMulti files
let cs = concatMap snd ascss let cs = concatMap snd ascss
@@ -38,15 +36,14 @@ importGrammar pgf0 opts files =
Bad msg -> do putStrLn ('\n':'\n':msg) Bad msg -> do putStrLn ('\n':'\n':msg)
return pgf0 return pgf0
".pgf" -> do ".pgf" -> do
mapM readPGF files >>= foldM ioUnionPGF pgf0 pgf2 <- mapM readPGF files >>= return . foldl1 unionPGF
ioUnionPGF pgf0 pgf2
ext -> die $ "Unknown filename extension: " ++ show ext ext -> die $ "Unknown filename extension: " ++ show ext
ioUnionPGF :: Maybe PGF -> PGF -> IO (Maybe PGF) ioUnionPGF :: PGF -> PGF -> IO PGF
ioUnionPGF Nothing two = return (Just two) ioUnionPGF one two = case msgUnionPGF one two of
ioUnionPGF (Just one) two = (pgf, Just msg) -> putStrLn msg >> return pgf
case unionPGF one two of (pgf,_) -> return pgf
Nothing -> putStrLn "Abstract changed, previous concretes discarded." >> return (Just two)
Just pgf -> return (Just pgf)
importSource :: Options -> [FilePath] -> IO SourceGrammar importSource :: Options -> [FilePath] -> IO SourceGrammar
importSource opts files = fmap (snd.snd) (batchCompile opts files) importSource opts files = fmap (snd.snd) (batchCompile opts files)
@@ -59,6 +56,7 @@ importCF opts files get convert = impCF
startCat <- case rules of startCat <- case rules of
(Rule cat _ _ : _) -> return cat (Rule cat _ _ : _) -> return cat
_ -> fail "empty CFG" _ -> fail "empty CFG"
probs <- maybe (return Map.empty) readProbabilitiesFromFile (flag optProbsFile opts) let pgf = cf2pgf (last files) (mkCFG startCat Set.empty rules)
let pgf = cf2pgf opts (last files) (mkCFG startCat Set.empty rules) probs probs <- maybe (return . defaultProbabilities) readProbabilitiesFromFile (flag optProbsFile opts) pgf
return pgf return $ setProbabilities probs
$ if flag optOptimizePGF opts then optimizePGF pgf else pgf

View File

@@ -6,11 +6,13 @@ module GF.Command.Interpreter (
import GF.Command.CommandInfo import GF.Command.CommandInfo
import GF.Command.Abstract import GF.Command.Abstract
import GF.Command.Parse import GF.Command.Parse
import PGF.Internal(Expr(..))
import GF.Infra.UseIO(putStrLnE) import GF.Infra.UseIO(putStrLnE)
import PGF2
import Control.Monad(when) import Control.Monad(when)
import qualified Data.Map as Map import qualified Data.Map as Map
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 ()
@@ -53,8 +56,17 @@ interpretPipe env cs = do
-- | macro definition applications: replace ?i by (exps !! i) -- | macro definition applications: replace ?i by (exps !! i)
appCommand :: CommandArguments -> Command -> Command appCommand :: CommandArguments -> Command -> Command
appCommand args c@(Command i os arg) = case arg of appCommand args c@(Command i os arg) = case arg of
AExpr e -> Command i os (AExpr (exprSubstitute e (toExprs args))) AExpr e -> Command i os (AExpr (app e))
_ -> c _ -> c
where
xs = toExprs args
app e = case e of
EAbs b x e -> EAbs b x (app e)
EApp e1 e2 -> EApp (app e1) (app e2)
ELit l -> ELit l
EMeta i -> xs !! i
EFun x -> EFun x
-- | return the trees to be sent in pipe, and the output possibly printed -- | return the trees to be sent in pipe, and the output possibly printed
--interpret :: CommandEnv -> [Expr] -> Command -> SIO CommandOutput --interpret :: CommandEnv -> [Expr] -> Command -> SIO CommandOutput
@@ -101,4 +113,4 @@ getCommandTrees env needsTypeCheck a args =
ATerm t -> return (Term t) ATerm t -> return (Term t)
ANoArg -> return args -- use piped ANoArg -> return args -- use piped
where where
one e = return (Exprs [(e,0)]) -- ignore piped one e = return (Exprs [e]) -- ignore piped

View File

@@ -1,6 +1,6 @@
module GF.Command.Parse(readCommandLine, pCommand) where module GF.Command.Parse(readCommandLine, pCommand) where
import PGF2(pExpr,pIdent) import PGF(pExpr,pIdent)
import GF.Grammar.Parser(runPartial,pTerm) import GF.Grammar.Parser(runPartial,pTerm)
import GF.Command.Abstract import GF.Command.Abstract
@@ -22,7 +22,7 @@ pCommandLine =
pPipe = sepBy1 (skipSpaces >> pCommand) (skipSpaces >> char '|') pPipe = sepBy1 (skipSpaces >> pCommand) (skipSpaces >> char '|')
pCommand = (do pCommand = (do
cmd <- readS_to_P pIdent <++ (char '%' >> fmap ('%':) (readS_to_P pIdent)) cmd <- pIdent <++ (char '%' >> fmap ('%':) pIdent)
skipSpaces skipSpaces
opts <- sepBy pOption skipSpaces opts <- sepBy pOption skipSpaces
arg <- if getCommandOp cmd == "cc" then pArgTerm else pArgument arg <- if getCommandOp cmd == "cc" then pArgTerm else pArgument
@@ -37,7 +37,7 @@ pCommand = (do
pOption = do pOption = do
char '-' char '-'
flg <- readS_to_P pIdent flg <- pIdent
option (OOpt flg) (fmap (OFlag flg) (char '=' >> pValue)) option (OOpt flg) (fmap (OFlag flg) (char '=' >> pValue))
pValue = do pValue = do
@@ -52,9 +52,9 @@ pFilename = liftM2 (:) (satisfy isFileFirst) (munch (not . isSpace)) where
pArgument = pArgument =
option ANoArg option ANoArg
(fmap AExpr (readS_to_P pExpr) (fmap AExpr pExpr
<++ <++
(skipSpaces >> char '%' >> fmap AMacro (readS_to_P pIdent))) (skipSpaces >> char '%' >> fmap AMacro pIdent))
pArgTerm = ATerm `fmap` readS_to_P sTerm pArgTerm = ATerm `fmap` readS_to_P sTerm
where where

View File

@@ -4,15 +4,15 @@ module GF.Command.TreeOperations (
treeChunks treeChunks
) where ) where
import PGF2(Expr,PGF,Fun,compute,mkApp,unApp,unapply,unMeta,exprSize,exprFunctions) import PGF(Expr,PGF,CId,compute,mkApp,unApp,unapply,unMeta,exprSize,exprFunctions)
import Data.List import Data.List
type TreeOp = [Expr] -> [Expr] type TreeOp = [Expr] -> [Expr]
treeOp :: PGF -> String -> Maybe (Either TreeOp (Fun -> TreeOp)) treeOp :: PGF -> String -> Maybe (Either TreeOp (CId -> TreeOp))
treeOp pgf f = fmap snd $ lookup f $ allTreeOps pgf treeOp pgf f = fmap snd $ lookup f $ allTreeOps pgf
allTreeOps :: PGF -> [(String,(String,Either TreeOp (Fun -> TreeOp)))] allTreeOps :: PGF -> [(String,(String,Either TreeOp (CId -> TreeOp)))]
allTreeOps pgf = [ allTreeOps pgf = [
("compute",("compute by using semantic definitions (def)", ("compute",("compute by using semantic definitions (def)",
Left $ map (compute pgf))), Left $ map (compute pgf))),

View File

@@ -1,6 +1,7 @@
module GF.Compile (compileToPGF, link, batchCompile, srcAbsName) where module GF.Compile (compileToPGF, compileToLPGF, link, linkl, batchCompile, srcAbsName) where
import GF.Compile.GrammarToPGF(grammar2PGF) import GF.Compile.GrammarToPGF(mkCanon2pgf)
import GF.Compile.GrammarToLPGF(mkCanon2lpgf)
import GF.Compile.ReadFiles(ModEnv,getOptionsFromFile,getAllFiles, import GF.Compile.ReadFiles(ModEnv,getOptionsFromFile,getAllFiles,
importsOfModule) importsOfModule)
import GF.CompileOne(compileOne) import GF.CompileOne(compileOne)
@@ -14,7 +15,7 @@ import GF.Infra.UseIO(IOE,FullPath,liftIO,getLibraryDirectory,putIfVerb,
justModuleName,extendPathEnv,putStrE,putPointE) justModuleName,extendPathEnv,putStrE,putPointE)
import GF.Data.Operations(raise,(+++),err) import GF.Data.Operations(raise,(+++),err)
import Control.Monad(foldM,when,(<=<)) import Control.Monad(foldM,when,(<=<),filterM)
import GF.System.Directory(doesFileExist,getModificationTime) import GF.System.Directory(doesFileExist,getModificationTime)
import System.FilePath((</>),isRelative,dropFileName) import System.FilePath((</>),isRelative,dropFileName)
import qualified Data.Map as Map(empty,insert,elems) --lookup import qualified Data.Map as Map(empty,insert,elems) --lookup
@@ -22,23 +23,37 @@ import Data.List(nub)
import Data.Time(UTCTime) import Data.Time(UTCTime)
import GF.Text.Pretty(render,($$),(<+>),nest) import GF.Text.Pretty(render,($$),(<+>),nest)
import PGF2(PGF,readProbabilitiesFromFile) import PGF.Internal(optimizePGF)
import PGF(PGF,defaultProbabilities,setProbabilities,readProbabilitiesFromFile)
import LPGF(LPGF)
-- | Compiles a number of source files and builds a 'PGF' structure for them. -- | Compiles a number of source files and builds a 'PGF' structure for them.
-- This is a composition of 'link' and 'batchCompile'. -- This is a composition of 'link' and 'batchCompile'.
compileToPGF :: Options -> [FilePath] -> IOE PGF compileToPGF :: Options -> [FilePath] -> IOE PGF
compileToPGF opts fs = link opts . snd =<< batchCompile opts fs compileToPGF opts fs = link opts . snd =<< batchCompile opts fs
compileToLPGF :: Options -> [FilePath] -> IOE LPGF
compileToLPGF opts fs = linkl opts . snd =<< batchCompile opts fs
-- | Link a grammar into a 'PGF' that can be used to 'PGF.linearize' and -- | Link a grammar into a 'PGF' that can be used to 'PGF.linearize' and
-- 'PGF.parse' with the "PGF" run-time system. -- 'PGF.parse' with the "PGF" run-time system.
link :: Options -> (ModuleName,Grammar) -> IOE PGF link :: Options -> (ModuleName,Grammar) -> IOE PGF
link opts (cnc,gr) = link opts (cnc,gr) =
putPointE Normal opts "linking ... " $ do putPointE Normal opts "linking ... " $ do
let abs = srcAbsName gr cnc let abs = srcAbsName gr cnc
probs <- liftIO (maybe (return Map.empty) readProbabilitiesFromFile (flag optProbsFile opts)) pgf <- mkCanon2pgf opts gr abs
pgf <- grammar2PGF opts gr abs probs probs <- liftIO (maybe (return . defaultProbabilities) readProbabilitiesFromFile (flag optProbsFile opts) pgf)
when (verbAtLeast opts Normal) $ putStrE "OK" when (verbAtLeast opts Normal) $ putStrE "OK"
return pgf return $ setProbabilities probs
$ if flag optOptimizePGF opts then optimizePGF pgf else pgf
-- | Link a grammar into a 'LPGF' that can be used for linearization only.
linkl :: Options -> (ModuleName,Grammar) -> IOE LPGF
linkl opts (cnc,gr) =
putPointE Normal opts "linking ... " $ do
let abs = srcAbsName gr cnc
lpgf <- mkCanon2lpgf opts gr abs
return lpgf
-- | Returns the name of the abstract syntax corresponding to the named concrete syntax -- | Returns the name of the abstract syntax corresponding to the named concrete syntax
srcAbsName gr cnc = err (const cnc) id $ abstractOfConcrete gr cnc srcAbsName gr cnc = err (const cnc) id $ abstractOfConcrete gr cnc
@@ -76,10 +91,14 @@ compileModule opts1 env@(_,rfs) file =
do file <- getRealFile file do file <- getRealFile file
opts0 <- getOptionsFromFile file opts0 <- getOptionsFromFile file
let curr_dir = dropFileName file let curr_dir = dropFileName file
lib_dir <- getLibraryDirectory (addOptions opts0 opts1) lib_dirs <- getLibraryDirectory (addOptions opts0 opts1)
let opts = addOptions (fixRelativeLibPaths curr_dir lib_dir opts0) opts1 let opts = addOptions (fixRelativeLibPaths curr_dir lib_dirs opts0) opts1
-- putIfVerb opts $ "curr_dir:" +++ show curr_dir ----
-- putIfVerb opts $ "lib_dir:" +++ show lib_dirs ----
ps0 <- extendPathEnv opts ps0 <- extendPathEnv opts
let ps = nub (curr_dir : ps0) let ps = nub (curr_dir : ps0)
-- putIfVerb opts $ "options from file: " ++ show opts0
-- putIfVerb opts $ "augmented options: " ++ show opts
putIfVerb opts $ "module search path:" +++ show ps ---- putIfVerb opts $ "module search path:" +++ show ps ----
files <- getAllFiles opts ps rfs file files <- getAllFiles opts ps rfs file
putIfVerb opts $ "files to read:" +++ show files ---- putIfVerb opts $ "files to read:" +++ show files ----
@@ -92,13 +111,17 @@ compileModule opts1 env@(_,rfs) file =
if exists if exists
then return file then return file
else if isRelative file else if isRelative file
then do lib_dir <- getLibraryDirectory opts1 then do
let file1 = lib_dir </> file lib_dirs <- getLibraryDirectory opts1
exists <- doesFileExist file1 let candidates = [ lib_dir </> file | lib_dir <- lib_dirs ]
if exists putIfVerb opts1 (render ("looking for: " $$ nest 2 candidates))
then return file1 file1s <- filterM doesFileExist candidates
else raise (render ("None of these files exists:" $$ nest 2 (file $$ file1))) case length file1s of
else raise (render ("File" <+> file <+> "does not exist.")) 0 -> raise (render ("Unable to find: " $$ nest 2 candidates))
1 -> do return $ head file1s
_ -> do putIfVerb opts1 ("matched multiple candidates: " +++ show file1s)
return $ head file1s
else raise (render ("File" <+> file <+> "does not exist"))
compileOne' :: Options -> CompileEnv -> FullPath -> IOE CompileEnv compileOne' :: Options -> CompileEnv -> FullPath -> IOE CompileEnv
compileOne' opts env@(gr,_) = extendCompileEnv env <=< compileOne opts gr compileOne' opts env@(gr,_) = extendCompileEnv env <=< compileOne opts gr

View File

@@ -1,110 +1,99 @@
{-# LANGUAGE FlexibleContexts, ImplicitParams #-} {-# LANGUAGE FlexibleContexts #-}
module GF.Compile.CFGtoPGF (cf2pgf) where module GF.Compile.CFGtoPGF (cf2pgf) where
import GF.Grammar.CFG import GF.Grammar.CFG
import GF.Infra.UseIO import GF.Infra.UseIO
import GF.Infra.Option
import GF.Compile.OptimizePGF
import PGF2 import PGF
import PGF2.Internal import PGF.Internal
import qualified Data.Set as Set import qualified Data.Set as Set
import qualified Data.Map as Map import qualified Data.Map as Map
import qualified Data.IntMap as IntMap import qualified Data.IntMap as IntMap
import Data.Array.IArray import Data.Array.IArray
import Data.List import Data.List
import Data.Maybe(fromMaybe)
-------------------------- --------------------------
-- the compiler ---------- -- the compiler ----------
-------------------------- --------------------------
cf2pgf :: Options -> FilePath -> ParamCFG -> Map.Map Fun Double -> PGF cf2pgf :: FilePath -> ParamCFG -> PGF
cf2pgf opts fpath cf probs = cf2pgf fpath cf =
build (let abstr = cf2abstr cf probs let pgf = PGF Map.empty aname (cf2abstr cf) (Map.singleton cname (cf2concr cf))
in newPGF [] aname abstr [(cname, cf2concr opts abstr cf)]) in updateProductionIndices pgf
where where
name = justModuleName fpath name = justModuleName fpath
aname = name ++ "Abs" aname = mkCId (name ++ "Abs")
cname = name cname = mkCId name
cf2abstr :: (?builder :: Builder s) => ParamCFG -> Map.Map Fun Double -> B s AbstrInfo cf2abstr :: ParamCFG -> Abstr
cf2abstr cfg probs = newAbstr aflags acats afuns cf2abstr cfg = Abstr aflags afuns acats
where where
aflags = [("startcat", LStr (fst (cfgStartCat cfg)))] aflags = Map.singleton (mkCId "startcat") (LStr (fst (cfgStartCat cfg)))
acats = [(c', [], toLogProb (fromMaybe 0 (Map.lookup c' probs))) | cat <- allCats' cfg, let c' = cat2id cat] acats = Map.fromList [(cat, ([], [(0,mkRuleName rule) | rule <- rules], 0))
afuns = [(f', dTyp [hypo Explicit "_" (dTyp [] (cat2id c) []) | NonTerminal c <- ruleRhs rule] (cat2id (ruleLhs rule)) [], 0, [], toLogProb (fromMaybe 0 (Map.lookup f' funs_probs))) | (cat,rules) <- (Map.toList . Map.fromListWith (++))
| rule <- allRules cfg [(cat2id cat, catRules cfg cat) |
, let f' = mkRuleName rule] cat <- allCats' cfg]]
afuns = Map.fromList [(mkRuleName rule, (cftype [cat2id c | NonTerminal c <- ruleRhs rule] (cat2id (ruleLhs rule)), 0, Nothing, 0))
| rule <- allRules cfg]
funs_probs = (Map.fromList . concat . Map.elems . fmap pad . Map.fromListWith (++)) cat2id = mkCId . fst
[(cat,[(f',Map.lookup f' probs)]) | rule <- allRules cfg,
let cat = cat2id (ruleLhs rule),
let f' = mkRuleName rule]
where
pad :: [(a,Maybe Double)] -> [(a,Double)]
pad pfs = [(f,fromMaybe deflt mb_p) | (f,mb_p) <- pfs]
where
deflt = case length [f | (f,Nothing) <- pfs] of
0 -> 0
n -> max 0 ((1 - sum [d | (f,Just d) <- pfs]) / fromIntegral n)
toLogProb = realToFrac . negate . log cf2concr :: ParamCFG -> Concr
cf2concr cfg = Concr Map.empty Map.empty
cat2id = fst cncfuns lindefsrefs lindefsrefs
sequences productions
cf2concr :: (?builder :: Builder s) => Options -> B s AbstrInfo -> ParamCFG -> B s ConcrInfo IntMap.empty Map.empty
cf2concr opts abstr cfg = cnccats
let (lindefs',linrefs',productions',cncfuns',sequences',cnccats') = IntMap.empty
(if flag optOptimizePGF opts then optimizePGF (fst (cfgStartCat cfg)) else id) totalCats
(lindefsrefs,lindefsrefs,IntMap.toList productions,cncfuns,sequences,cnccats)
in newConcr abstr [] []
lindefs' linrefs'
productions' cncfuns'
sequences' cnccats' totalCats
where where
cats = allCats' cfg cats = allCats' cfg
rules = allRules cfg rules = allRules cfg
idSeq = [SymCat 0 0] sequences0 = Set.fromList (listArray (0,0) [SymCat 0 0] :
sequences0 = Set.fromList (idSeq :
map mkSequence rules) map mkSequence rules)
sequences = Set.toList sequences0 sequences = listArray (0,Set.size sequences0-1) (Set.toList sequences0)
idFun = ("_",[Set.findIndex idSeq sequences0]) idFun = CncFun wildCId (listArray (0,0) [seqid])
where
seq = listArray (0,0) [SymCat 0 0]
seqid = binSearch seq sequences (bounds sequences)
((fun_cnt,cncfuns0),productions0) = mapAccumL (convertRule cs) (1,[idFun]) rules ((fun_cnt,cncfuns0),productions0) = mapAccumL (convertRule cs) (1,[idFun]) rules
productions = foldl addProd IntMap.empty (concat (productions0++coercions)) productions = foldl addProd IntMap.empty (concat (productions0++coercions))
cncfuns = reverse cncfuns0 cncfuns = listArray (0,fun_cnt-1) (reverse cncfuns0)
lbls = ["s"] lbls = listArray (0,0) ["s"]
(fid,cnccats) = (mapAccumL mkCncCat 0 . Map.toList . Map.fromListWith max) (fid,cnccats0) = (mapAccumL mkCncCat 0 . Map.toList . Map.fromListWith max)
[(c,p) | (c,ps) <- cats, p <- ps] [(c,p) | (c,ps) <- cats, p <- ps]
((totalCats,cs), coercions) = mapAccumL mkCoercions (fid,Map.empty) cats ((totalCats,cs), coercions) = mapAccumL mkCoercions (fid,Map.empty) cats
cnccats = Map.fromList cnccats0
lindefsrefs = map mkLinDefRef cats lindefsrefs =
IntMap.fromList (map mkLinDefRef cats)
convertRule cs (funid,funs) rule = convertRule cs (funid,funs) rule =
let args = [PArg [] (cat2arg c) | NonTerminal c <- ruleRhs rule] let args = [PArg [] (cat2arg c) | NonTerminal c <- ruleRhs rule]
prod = PApply funid args prod = PApply funid args
seqid = Set.findIndex (mkSequence rule) sequences0 seqid = binSearch (mkSequence rule) sequences (bounds sequences)
fun = (mkRuleName rule, [seqid]) fun = CncFun (mkRuleName rule) (listArray (0,0) [seqid])
funid' = funid+1 funid' = funid+1
in funid' `seq` ((funid',fun:funs),let (c,ps) = ruleLhs rule in [(cat2fid c p, prod) | p <- ps]) in funid' `seq` ((funid',fun:funs),let (c,ps) = ruleLhs rule in [(cat2fid c p, prod) | p <- ps])
mkSequence rule = snd $ mapAccumL convertSymbol 0 (ruleRhs rule) mkSequence rule = listArray (0,length syms-1) syms
where where
syms = snd $ mapAccumL convertSymbol 0 (ruleRhs rule)
convertSymbol d (NonTerminal (c,_)) = (d+1,if c `elem` ["Int","Float","String"] then SymLit d 0 else SymCat d 0) convertSymbol d (NonTerminal (c,_)) = (d+1,if c `elem` ["Int","Float","String"] then SymLit d 0 else SymCat d 0)
convertSymbol d (Terminal t) = (d, SymKS t) convertSymbol d (Terminal t) = (d, SymKS t)
mkCncCat fid (cat,n) mkCncCat fid (cat,n)
| cat == "Int" = (fid, (cat, fidInt, fidInt, lbls)) | cat == "Int" = (fid, (mkCId cat, CncCat fidInt fidInt lbls))
| cat == "Float" = (fid, (cat, fidFloat, fidFloat, lbls)) | cat == "Float" = (fid, (mkCId cat, CncCat fidFloat fidFloat lbls))
| cat == "String" = (fid, (cat, fidString, fidString, lbls)) | cat == "String" = (fid, (mkCId cat, CncCat fidString fidString lbls))
| otherwise = let fid' = fid+n+1 | otherwise = let fid' = fid+n+1
in fid' `seq` (fid', (cat, fid, fid+n, lbls)) in fid' `seq` (fid', (mkCId cat,CncCat fid (fid+n) lbls))
mkCoercions (fid,cs) c@(cat,[p]) = ((fid,cs),[]) mkCoercions (fid,cs) c@(cat,[p]) = ((fid,cs),[])
mkCoercions (fid,cs) c@(cat,ps ) = mkCoercions (fid,cs) c@(cat,ps ) =
@@ -116,13 +105,22 @@ cf2concr opts abstr cfg =
addProd prods (fid,prod) = addProd prods (fid,prod) =
case IntMap.lookup fid prods of case IntMap.lookup fid prods of
Just set -> IntMap.insert fid (prod:set) prods Just set -> IntMap.insert fid (Set.insert prod set) prods
Nothing -> IntMap.insert fid [prod] prods Nothing -> IntMap.insert fid (Set.singleton prod) prods
binSearch v arr (i,j)
| i <= j = case compare v (arr ! k) of
LT -> binSearch v arr (i,k-1)
EQ -> k
GT -> binSearch v arr (k+1,j)
| otherwise = error "binSearch"
where
k = (i+j) `div` 2
cat2fid cat p = cat2fid cat p =
case [start | (cat',start,_,_) <- cnccats, cat == cat'] of case Map.lookup (mkCId cat) cnccats of
(start:_) -> fid+p Just (CncCat fid _ _) -> fid+p
_ -> error "cat2fid" _ -> error "cat2fid"
cat2arg c@(cat,[p]) = cat2fid cat p cat2arg c@(cat,[p]) = cat2fid cat p
cat2arg c@(cat,ps ) = cat2arg c@(cat,ps ) =
@@ -133,5 +131,4 @@ cf2concr opts abstr cfg =
mkRuleName rule = mkRuleName rule =
case ruleName rule of case ruleName rule of
CFObj n _ -> n CFObj n _ -> n
_ -> "_" _ -> wildCId

View File

@@ -21,6 +21,7 @@
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
module GF.Compile.CheckGrammar(checkModule) where module GF.Compile.CheckGrammar(checkModule) where
import Prelude hiding ((<>)) -- GHC 8.4.1 clash with Text.PrettyPrint
import GF.Infra.Ident import GF.Infra.Ident
import GF.Infra.Option import GF.Infra.Option
@@ -259,30 +260,18 @@ checkInfo opts cwd sgr (m,mo) c info = checkInModule cwd mo NoLoc empty $ do
return (ResOverload os [(y,x) | (x,y) <- tysts']) return (ResOverload os [(y,x) | (x,y) <- tysts'])
ResParam (Just (L loc pcs)) _ -> do ResParam (Just (L loc pcs)) _ -> do
(vs,pcs) <- chIn loc "parameter type" $ ts <- chIn loc "parameter type" $
mkParams 0 [] pcs liftM concat $ mapM mkPar pcs
return (ResParam (Just (L loc pcs)) (Just vs)) return (ResParam (Just (L loc pcs)) (Just ts))
ResValue (L loc ty) _ ->
chIn loc "operation" $ do
let (_,Cn x) = typeFormCnc ty
is = case Map.lookup x (jments mo) of
Just (ResParam (Just (L _ pcs)) _) -> [i | (f,_,i) <- pcs, f == c]
_ -> []
case is of
[i] -> return (ResValue (L loc ty) i)
_ -> checkError (pp "Failed to find the value index for parameter" <+> pp c)
_ -> return info _ -> return info
where where
gr = prependModule sgr (m,mo) gr = prependModule sgr (m,mo)
chIn loc cat = checkInModule cwd mo loc ("Happened in" <+> cat <+> c) chIn loc cat = checkInModule cwd mo loc ("Happened in" <+> cat <+> c)
mkParams i vs [] = return (vs,[]) mkPar (f,co) = do
mkParams i vs ((f,co,_):pcs) = do vs <- liftM sequence $ mapM (\(_,_,ty) -> allParamValues gr ty) co
vs0 <- liftM combinations $ mapM (\(_,_,ty) -> allParamValues gr ty) co return $ map (mkApp (QC (m,f))) vs
(vs,pcs) <- mkParams (i + length vs0) (vs ++ map (mkApp (QC (m,f))) vs0) pcs
return (vs,(f,co,i):pcs)
checkUniq xss = case xss of checkUniq xss = case xss of
x:y:xs x:y:xs

View File

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

View File

@@ -5,6 +5,7 @@ module GF.Compile.Compute.ConcreteNew
normalForm, normalForm,
Value(..), Bind(..), Env, value2term, eval, vapply Value(..), Bind(..), Env, value2term, eval, vapply
) where ) where
import Prelude hiding ((<>)) -- GHC 8.4.1 clash with Text.PrettyPrint
import GF.Grammar hiding (Env, VGen, VApp, VRecType) import GF.Grammar hiding (Env, VGen, VApp, VRecType)
import GF.Grammar.Lookup(lookupResDefLoc,allParamValues) import GF.Grammar.Lookup(lookupResDefLoc,allParamValues)
@@ -14,7 +15,7 @@ import GF.Grammar.Lockfield(isLockLabel,lockRecType) --unlockRecord,lockLabel
import GF.Compile.Compute.Value hiding (Error) import GF.Compile.Compute.Value hiding (Error)
import GF.Compile.Compute.Predef(predef,predefName,delta) import GF.Compile.Compute.Predef(predef,predefName,delta)
import GF.Data.Str(Str,glueStr,str2strings,str,sstr,plusStr,strTok) import GF.Data.Str(Str,glueStr,str2strings,str,sstr,plusStr,strTok)
import GF.Data.Operations(Err,err,errIn,maybeErr,combinations,mapPairsM) import GF.Data.Operations(Err,err,errIn,maybeErr,mapPairsM)
import GF.Data.Utilities(mapFst,mapSnd) import GF.Data.Utilities(mapFst,mapSnd)
import GF.Infra.Option import GF.Infra.Option
import Control.Monad(ap,liftM,liftM2) -- ,unless,mplus import Control.Monad(ap,liftM,liftM2) -- ,unless,mplus
@@ -290,9 +291,17 @@ glue env (v1,v2) = glu v1 v2
vt v = case value2term loc (local env) v of vt v = case value2term loc (local env) v of
Left i -> Error ('#':show i) Left i -> Error ('#':show i)
Right t -> t Right t -> t
in error . render $ originalMsg = render $ ppL loc (hang "unsupported token gluing" 4
ppL loc (hang "unsupported token gluing:" 4 (Glue (vt v1) (vt v2)))
(Glue (vt v1) (vt v2))) term = render $ pp $ Glue (vt v1) (vt v2)
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 -- | to get a string from a value that represents a sequence of terminals
@@ -317,7 +326,7 @@ strsFromValue 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]
] ]
VFV ts -> concat # mapM strsFromValue ts VFV ts -> concat # mapM strsFromValue ts
VStrs ts -> concat # mapM strsFromValue ts VStrs ts -> concat # mapM strsFromValue ts
@@ -545,7 +554,7 @@ value2term' stop loc xs v0 =
linPattVars p = linPattVars p =
if null dups if null dups
then return pvs then return pvs
else fail.render $ hang "Pattern is not linear:" 4 (ppPatt Unqualified 0 p) 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 where
allpvs = allPattVars p allpvs = allPattVars p
pvs = nub allpvs pvs = nub allpvs

View File

@@ -1,6 +1,6 @@
module GF.Compile.Compute.Value where module GF.Compile.Compute.Value where
import GF.Grammar.Grammar(Label,Type,MetaId,Patt,QIdent) import GF.Grammar.Grammar(Label,Type,MetaId,Patt,QIdent)
import PGF2(BindType) import PGF.Internal(BindType)
import GF.Infra.Ident(Ident) import GF.Infra.Ident(Ident)
import Text.Show.Functions() import Text.Show.Functions()
import Data.Ix(Ix) import Data.Ix(Ix)

View File

@@ -3,7 +3,11 @@ module GF.Compile.ExampleBased (
configureExBased configureExBased
) where ) where
import PGF2 import PGF
--import PGF.Probabilistic
--import PGF.Morphology
--import GF.Compile.ToAPI
import Data.List import Data.List
parseExamplesInGrammar :: ExConfiguration -> FilePath -> IO (FilePath,[String]) parseExamplesInGrammar :: ExConfiguration -> FilePath -> IO (FilePath,[String])
@@ -33,38 +37,47 @@ convertFile conf src file = do
(ex, end) = break (=='"') (tail exend) (ex, end) = break (=='"') (tail exend)
in ((unwords (words cat),ex), tail end) -- quotes ignored in ((unwords (words cat),ex), tail end) -- quotes ignored
pgf = resource_pgf conf pgf = resource_pgf conf
morpho = resource_morpho conf
lang = language conf lang = language conf
convEx (cat,ex) = do convEx (cat,ex) = do
appn "(" appn "("
let typ = maybe (error "no valid cat") id $ readType cat let typ = maybe (error "no valid cat") id $ readType cat
ws <- case parse lang typ ex of ws <- case fst (parse_ pgf lang typ (Just 4) ex) of
ParseFailed _ _ -> do ParseFailed _ -> do
let ws = morphoMissing morpho (words ex)
appv ("WARNING: cannot parse example " ++ ex) appv ("WARNING: cannot parse example " ++ ex)
case ws of
[] -> return ()
_ -> appv (" missing words: " ++ unwords ws)
return ws
TypeError _ ->
return [] return []
ParseIncomplete -> ParseIncomplete ->
return [] return []
ParseOk ts -> ParseOk ts ->
case ts of case rank ts of
(t:tt) -> do (t:tt) -> do
if null tt if null tt
then return () then return ()
else appv ("WARNING: ambiguous example " ++ ex) else appv ("WARNING: ambiguous example " ++ ex)
appn (printExp conf (fst t)) appn t
mapM_ (appn . (" --- " ++) . printExp conf . fst) tt mapM_ (appn . (" --- " ++)) tt
appn ")" appn ")"
return [] return []
return ws return ws
rank ts = [printExp conf t ++ " -- " ++ show p | (t,p) <- rankTreesByProbs pgf ts]
appf = appendFile file appf = appendFile file
appn s = appf s >> appf "\n" appn s = appf s >> appf "\n"
appv s = appn ("--- " ++ s) >> putStrLn s appv s = appn ("--- " ++ s) >> putStrLn s
data ExConfiguration = ExConf { data ExConfiguration = ExConf {
resource_pgf :: PGF, resource_pgf :: PGF,
resource_morpho :: Morpho,
verbose :: Bool, verbose :: Bool,
language :: Concr, language :: Language,
printExp :: Expr -> String printExp :: Tree -> String
} }
configureExBased :: PGF -> Concr -> (Expr -> String) -> ExConfiguration configureExBased :: PGF -> Morpho -> Language -> (Tree -> String) -> ExConfiguration
configureExBased pgf concr pr = ExConf pgf False concr pr configureExBased pgf morpho lang pr = ExConf pgf morpho False lang pr

View File

@@ -1,10 +1,14 @@
module GF.Compile.Export where module GF.Compile.Export where
import PGF2 import PGF
import PGF.Internal(ppPGF)
import GF.Compile.PGFtoHaskell import GF.Compile.PGFtoHaskell
--import GF.Compile.PGFtoAbstract --import GF.Compile.PGFtoAbstract
import GF.Compile.PGFtoJava import GF.Compile.PGFtoJava
import GF.Compile.PGFtoProlog
import GF.Compile.PGFtoJS
import GF.Compile.PGFtoJSON import GF.Compile.PGFtoJSON
import GF.Compile.PGFtoPython
import GF.Infra.Option import GF.Infra.Option
--import GF.Speech.CFG --import GF.Speech.CFG
import GF.Speech.PGFToCFG import GF.Speech.PGFToCFG
@@ -18,7 +22,6 @@ import GF.Speech.SLF
import GF.Speech.PrRegExp import GF.Speech.PrRegExp
import Data.Maybe import Data.Maybe
import qualified Data.Map as Map
import System.FilePath import System.FilePath
import GF.Text.Pretty import GF.Text.Pretty
@@ -32,12 +35,15 @@ exportPGF :: Options
-> [(FilePath,String)] -- ^ List of recommended file names and contents. -> [(FilePath,String)] -- ^ List of recommended file names and contents.
exportPGF opts fmt pgf = exportPGF opts fmt pgf =
case fmt of case fmt of
FmtPGFPretty -> multi "txt" (showPGF) FmtPGFPretty -> multi "txt" (render . ppPGF)
FmtCanonicalGF -> [] -- canon "gf" (render80 . abstract2canonical) FmtCanonicalGF -> [] -- canon "gf" (render80 . abstract2canonical)
FmtCanonicalJson-> [] FmtCanonicalJson-> []
FmtJavaScript -> multi "js" pgf2js
FmtJSON -> multi "json" pgf2json FmtJSON -> multi "json" pgf2json
FmtPython -> multi "py" pgf2python
FmtHaskell -> multi "hs" (grammar2haskell opts name) FmtHaskell -> multi "hs" (grammar2haskell opts name)
FmtJava -> multi "java" (grammar2java opts name) FmtJava -> multi "java" (grammar2java opts name)
FmtProlog -> multi "pl" grammar2prolog
FmtBNF -> single "bnf" bnfPrinter FmtBNF -> single "bnf" bnfPrinter
FmtEBNF -> single "ebnf" (ebnfPrinter opts) FmtEBNF -> single "ebnf" (ebnfPrinter opts)
FmtSRGS_XML -> single "grxml" (srgsXmlPrinter opts) FmtSRGS_XML -> single "grxml" (srgsXmlPrinter opts)
@@ -51,13 +57,20 @@ exportPGF opts fmt pgf =
FmtRegExp -> single "rexp" regexpPrinter FmtRegExp -> single "rexp" regexpPrinter
FmtFA -> single "dot" slfGraphvizPrinter FmtFA -> single "dot" slfGraphvizPrinter
where where
name = fromMaybe (abstractName pgf) (flag optName opts) name = fromMaybe (showCId (abstractName pgf)) (flag optName opts)
multi :: String -> (PGF -> String) -> [(FilePath,String)] multi :: String -> (PGF -> String) -> [(FilePath,String)]
multi ext pr = [(name <.> ext, pr pgf)] multi ext pr = [(name <.> ext, pr pgf)]
-- canon ext pr = [("canonical"</>name<.>ext,pr pgf)] -- canon ext pr = [("canonical"</>name<.>ext,pr pgf)]
single :: String -> (PGF -> Concr -> String) -> [(FilePath,String)] single :: String -> (PGF -> CId -> String) -> [(FilePath,String)]
single ext pr = [(concreteName cnc <.> ext, pr pgf cnc) | cnc <- Map.elems (languages pgf)] single ext pr = [(showCId cnc <.> ext, pr pgf cnc) | cnc <- languages pgf]
-- | Get the name of the concrete syntax to generate output from.
-- FIXME: there should be an option to change this.
outputConcr :: PGF -> CId
outputConcr pgf = case languages pgf of
[] -> error "No concrete syntax."
cnc:_ -> cnc

View File

@@ -1,10 +1,10 @@
{-# LANGUAGE CPP #-}
module GF.Compile.GenerateBC(generateByteCode) where module GF.Compile.GenerateBC(generateByteCode) where
import GF.Grammar import GF.Grammar
import GF.Grammar.Lookup(lookupAbsDef,lookupFunType) import GF.Grammar.Lookup(lookupAbsDef,lookupFunType)
import GF.Data.Operations import GF.Data.Operations
import PGF2.Internal(CodeLabel,Instr(..),IVal(..),TailInfo(..),Literal(..)) import PGF(CId,utf8CId)
import PGF.Internal(CodeLabel,Instr(..),IVal(..),TailInfo(..),Literal(..))
import qualified Data.Map as Map import qualified Data.Map as Map
import Data.List(nub,mapAccumL) import Data.List(nub,mapAccumL)
import Data.Maybe(fromMaybe) import Data.Maybe(fromMaybe)
@@ -63,7 +63,7 @@ compileEquations gr arity st (i:is) eqs fl bs = whilePP eqs Map.empty
case_instr t = case_instr t =
case t of case t of
(Q (_,id)) -> CASE (showIdent id) (Q (_,id)) -> CASE (i2i id)
(EInt n) -> CASE_LIT (LInt n) (EInt n) -> CASE_LIT (LInt n)
(K s) -> CASE_LIT (LStr s) (K s) -> CASE_LIT (LStr s)
(EFloat d) -> CASE_LIT (LFlt d) (EFloat d) -> CASE_LIT (LFlt d)
@@ -105,7 +105,7 @@ compileFun gr eval st vs (App e1 e2) h0 bs args =
compileFun gr eval st vs (Q (m,id)) h0 bs args = compileFun gr eval st vs (Q (m,id)) h0 bs args =
case lookupAbsDef gr m id of case lookupAbsDef gr m id of
Ok (_,Just _) Ok (_,Just _)
-> (h0,bs,eval st (GLOBAL (showIdent id)) args) -> (h0,bs,eval st (GLOBAL (i2i id)) args)
_ -> let Ok ty = lookupFunType gr m id _ -> let Ok ty = lookupFunType gr m id
(ctxt,_,_) = typeForm ty (ctxt,_,_) = typeForm ty
c_arity = length ctxt c_arity = length ctxt
@@ -114,14 +114,14 @@ compileFun gr eval st vs (Q (m,id)) h0 bs args =
diff = c_arity-n_args diff = c_arity-n_args
in if diff <= 0 in if diff <= 0
then if n_args == 0 then if n_args == 0
then (h0,bs,eval st (GLOBAL (showIdent id)) []) then (h0,bs,eval st (GLOBAL (i2i id)) [])
else let h1 = h0 + 2 + n_args else let h1 = h0 + 2 + n_args
in (h1,bs,PUT_CONSTR (showIdent id):is1++eval st (HEAP h0) []) in (h1,bs,PUT_CONSTR (i2i id):is1++eval st (HEAP h0) [])
else let h1 = h0 + 1 + n_args else let h1 = h0 + 1 + n_args
is2 = [SET (FREE_VAR i) | i <- [0..n_args-1]] ++ [SET (ARG_VAR (i+1)) | i <- [0..diff-1]] is2 = [SET (FREE_VAR i) | i <- [0..n_args-1]] ++ [SET (ARG_VAR (i+1)) | i <- [0..diff-1]]
b = CHECK_ARGS diff : b = CHECK_ARGS diff :
ALLOC (c_arity+2) : ALLOC (c_arity+2) :
PUT_CONSTR (showIdent id) : PUT_CONSTR (i2i id) :
is2 ++ is2 ++
TUCK (ARG_VAR 0) diff : TUCK (ARG_VAR 0) diff :
EVAL (HEAP h0) (TailCall diff) : EVAL (HEAP h0) (TailCall diff) :
@@ -167,16 +167,16 @@ compileFun gr eval st vs e _ _ _ = error (show e)
compileArg gr st vs (Q(m,id)) h0 bs = compileArg gr st vs (Q(m,id)) h0 bs =
case lookupAbsDef gr m id of case lookupAbsDef gr m id of
Ok (_,Just _) -> (h0,bs,GLOBAL (showIdent id),[]) Ok (_,Just _) -> (h0,bs,GLOBAL (i2i id),[])
_ -> let Ok ty = lookupFunType gr m id _ -> let Ok ty = lookupFunType gr m id
(ctxt,_,_) = typeForm ty (ctxt,_,_) = typeForm ty
c_arity = length ctxt c_arity = length ctxt
in if c_arity == 0 in if c_arity == 0
then (h0,bs,GLOBAL (showIdent id),[]) then (h0,bs,GLOBAL (i2i id),[])
else let is2 = [SET (ARG_VAR (i+1)) | i <- [0..c_arity-1]] else let is2 = [SET (ARG_VAR (i+1)) | i <- [0..c_arity-1]]
b = CHECK_ARGS c_arity : b = CHECK_ARGS c_arity :
ALLOC (c_arity+2) : ALLOC (c_arity+2) :
PUT_CONSTR (showIdent id) : PUT_CONSTR (i2i id) :
is2 ++ is2 ++
TUCK (ARG_VAR 0) c_arity : TUCK (ARG_VAR 0) c_arity :
EVAL (HEAP h0) (TailCall c_arity) : EVAL (HEAP h0) (TailCall c_arity) :
@@ -224,12 +224,12 @@ compileArg gr st vs e h0 bs =
diff = c_arity-n_args diff = c_arity-n_args
in if diff <= 0 in if diff <= 0
then let h2 = h1 + 2 + n_args then let h2 = h1 + 2 + n_args
in (h2,bs1,HEAP h1,is1 ++ (PUT_CONSTR (showIdent id) : is2)) in (h2,bs1,HEAP h1,is1 ++ (PUT_CONSTR (i2i id) : is2))
else let h2 = h1 + 1 + n_args else let h2 = h1 + 1 + n_args
is2 = [SET (FREE_VAR i) | i <- [0..n_args-1]] ++ [SET (ARG_VAR (i+1)) | i <- [0..diff-1]] is2 = [SET (FREE_VAR i) | i <- [0..n_args-1]] ++ [SET (ARG_VAR (i+1)) | i <- [0..diff-1]]
b = CHECK_ARGS diff : b = CHECK_ARGS diff :
ALLOC (c_arity+2) : ALLOC (c_arity+2) :
PUT_CONSTR (showIdent id) : PUT_CONSTR (i2i id) :
is2 ++ is2 ++
TUCK (ARG_VAR 0) diff : TUCK (ARG_VAR 0) diff :
EVAL (HEAP h0) (TailCall diff) : EVAL (HEAP h0) (TailCall diff) :
@@ -298,6 +298,9 @@ freeVars xs (Vr x)
| not (elem x xs) = [x] | not (elem x xs) = [x]
freeVars xs e = collectOp (freeVars xs) e freeVars xs e = collectOp (freeVars xs) e
i2i :: Ident -> CId
i2i = utf8CId . ident2utf8
push_is :: Int -> Int -> [IVal] -> [IVal] push_is :: Int -> Int -> [IVal] -> [IVal]
push_is i 0 is = is push_is i 0 is = is
push_is i n is = ARG_VAR i : push_is (i-1) (n-1) is push_is i n is = ARG_VAR i : push_is (i-1) (n-1) is

View File

@@ -13,9 +13,8 @@ module GF.Compile.GeneratePMCFG
(generatePMCFG, pgfCncCat, addPMCFG, resourceValues (generatePMCFG, pgfCncCat, addPMCFG, resourceValues
) where ) where
import qualified PGF2 as PGF2 --import PGF.CId
import qualified PGF2.Internal as PGF2 import PGF.Internal as PGF(CncCat(..),Symbol(..),fidVar)
import PGF2.Internal(Symbol(..),fidVar)
import GF.Infra.Option import GF.Infra.Option
import GF.Grammar hiding (Env, mkRecord, mkTable) import GF.Grammar hiding (Env, mkRecord, mkTable)
@@ -42,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
@@ -69,7 +69,7 @@ mapAccumWithKeyM f a m = do let xs = Map.toAscList m
--addPMCFG :: Options -> SourceGrammar -> GlobalEnv -> Maybe FilePath -> Ident -> Ident -> SeqSet -> Ident -> Info -> IOE (SeqSet, Info) --addPMCFG :: Options -> SourceGrammar -> GlobalEnv -> Maybe FilePath -> Ident -> Ident -> SeqSet -> Ident -> Info -> IOE (SeqSet, Info)
addPMCFG opts gr cenv opath am cm seqs id (CncFun mty@(Just (cat,cont,val)) mlin@(Just (L loc term)) mprn Nothing) = do addPMCFG opts gr cenv opath am cm seqs id (GF.Grammar.CncFun mty@(Just (cat,cont,val)) mlin@(Just (L loc term)) mprn Nothing) = do
--when (verbAtLeast opts Verbose) $ ePutStr ("\n+ "++showIdent id++" ...") --when (verbAtLeast opts Verbose) $ ePutStr ("\n+ "++showIdent id++" ...")
let pres = protoFCat gr res val let pres = protoFCat gr res val
pargs = [protoFCat gr (snd $ catSkeleton ty) lincat | ((_,_,ty),(_,_,lincat)) <- zip ctxt cont] pargs = [protoFCat gr (snd $ catSkeleton ty) lincat | ((_,_,ty),(_,_,lincat)) <- zip ctxt cont]
@@ -93,7 +93,7 @@ addPMCFG opts gr cenv opath am cm seqs id (CncFun mty@(Just (cat,cont,val)) mlin
ePutStr ("\n+ "++showIdent id++" "++show (product (map catFactor pargs))) ePutStr ("\n+ "++showIdent id++" "++show (product (map catFactor pargs)))
seqs1 `seq` stats `seq` return () seqs1 `seq` stats `seq` return ()
when (verbAtLeast opts Verbose) $ ePutStr (" "++show stats) when (verbAtLeast opts Verbose) $ ePutStr (" "++show stats)
return (seqs1,CncFun mty mlin mprn (Just pmcfg)) return (seqs1,GF.Grammar.CncFun mty mlin mprn (Just pmcfg))
where where
(ctxt,res,_) = err bug typeForm (lookupFunType gr am id) (ctxt,res,_) = err bug typeForm (lookupFunType gr am id)
@@ -103,11 +103,11 @@ addPMCFG opts gr cenv opath am cm seqs id (CncFun mty@(Just (cat,cont,val)) mlin
newArgs = map getFIds newArgs' newArgs = map getFIds newArgs'
in addFunction env0 newCat fun newArgs in addFunction env0 newCat fun newArgs
addPMCFG opts gr cenv opath am cm seqs id (CncCat mty@(Just (L _ lincat)) addPMCFG opts gr cenv opath am cm seqs id (GF.Grammar.CncCat mty@(Just (L _ lincat))
mdef@(Just (L loc1 def)) mdef@(Just (L loc1 def))
mref@(Just (L loc2 ref)) mref@(Just (L loc2 ref))
mprn mprn
Nothing) = do Nothing) = do
let pcat = protoFCat gr (am,id) lincat let pcat = protoFCat gr (am,id) lincat
pvar = protoFCat gr (MN identW,cVar) typeStr pvar = protoFCat gr (MN identW,cVar) typeStr
@@ -132,7 +132,7 @@ addPMCFG opts gr cenv opath am cm seqs id (CncCat mty@(Just (L _ lincat))
let pmcfg = getPMCFG pmcfgEnv2 let pmcfg = getPMCFG pmcfgEnv2
when (verbAtLeast opts Verbose) $ ePutStr ("\n+ "++showIdent id++" "++show (catFactor pcat)) when (verbAtLeast opts Verbose) $ ePutStr ("\n+ "++showIdent id++" "++show (catFactor pcat))
seqs2 `seq` pmcfg `seq` return (seqs2,CncCat mty mdef mref mprn (Just pmcfg)) seqs2 `seq` pmcfg `seq` return (seqs2,GF.Grammar.CncCat mty mdef mref mprn (Just pmcfg))
where where
addLindef lins (newCat', newArgs') env0 = addLindef lins (newCat', newArgs') env0 =
let [newCat] = getFIds newCat' let [newCat] = getFIds newCat'
@@ -158,15 +158,12 @@ convert opts gr cenv loc term ty@(_,val) pargs =
args = map Vr vars args = map Vr vars
vars = map (\(bt,x,t) -> x) context vars = map (\(bt,x,t) -> x) context
pgfCncCat :: SourceGrammar -> PGF2.Cat -> Type -> Int -> (PGF2.Cat,Int,Int,[String]) pgfCncCat :: SourceGrammar -> Type -> Int -> CncCat
pgfCncCat gr id lincat index = pgfCncCat gr lincat index =
let ((_,size),schema) = computeCatRange gr lincat let ((_,size),schema) = computeCatRange gr lincat
in ( id in PGF.CncCat index (index+size-1)
, index (mkArray (map (renderStyle style{mode=OneLineMode} . ppPath)
, index+size-1 (getStrPaths schema)))
, map (renderStyle style{mode=OneLineMode} . ppPath)
(getStrPaths schema)
)
where where
getStrPaths :: Schema Identity s c -> [Path] getStrPaths :: Schema Identity s c -> [Path]
getStrPaths = collect CNil [] getStrPaths = collect CNil []
@@ -200,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
@@ -475,7 +475,7 @@ goV (CPar t) rpath ss = restrictHead (reversePath rpath) t >> return ss
---------------------------------------------------------------------- ----------------------------------------------------------------------
-- SeqSet -- SeqSet
type SeqSet = Map.Map [Symbol] SeqId type SeqSet = Map.Map Sequence SeqId
addSequencesB :: SeqSet -> Branch (Value [Symbol]) -> (SeqSet, Branch (Value SeqId)) addSequencesB :: SeqSet -> Branch (Value [Symbol]) -> (SeqSet, Branch (Value SeqId))
addSequencesB seqs (Case nr path bs) = let !(seqs1,bs1) = mapAccumL' (\seqs (trm,b) -> let !(seqs',b') = addSequencesB seqs b addSequencesB seqs (Case nr path bs) = let !(seqs1,bs1) = mapAccumL' (\seqs (trm,b) -> let !(seqs',b') = addSequencesB seqs b
@@ -504,11 +504,13 @@ mapAccumL' f s (x:xs) = (s'',y:ys)
!(s'',ys) = mapAccumL' f s' xs !(s'',ys) = mapAccumL' f s' xs
addSequence :: SeqSet -> [Symbol] -> (SeqSet,SeqId) addSequence :: SeqSet -> [Symbol] -> (SeqSet,SeqId)
addSequence seqs seq = addSequence seqs lst =
case Map.lookup seq seqs of case Map.lookup seq seqs of
Just id -> (seqs,id) Just id -> (seqs,id)
Nothing -> let !last_seq = Map.size seqs Nothing -> let !last_seq = Map.size seqs
in (Map.insert seq last_seq seqs, last_seq) in (Map.insert seq last_seq seqs, last_seq)
where
seq = mkArray lst
------------------------------------------------------------ ------------------------------------------------------------
@@ -616,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

View File

@@ -50,13 +50,20 @@ getSourceModule opts file0 =
Right (i,mi0) -> Right (i,mi0) ->
do liftIO $ removeTemp tmp do liftIO $ removeTemp tmp
let mi =mi0 {mflags=mflags mi0 `addOptions` opts, msrc=file0} let mi =mi0 {mflags=mflags mi0 `addOptions` opts, msrc=file0}
case renameEncoding `fmap` flag optEncoding (mflags mi0) of optCoding' = renameEncoding `fmap` flag optEncoding (mflags mi0)
Just coding' -> case (optCoding,optCoding') of
when (coding/=coding') $ {-
(Nothing,Nothing) ->
unless (BS.all isAscii raw) $
ePutStrLn $ file0++":\n Warning: default encoding has changed from Latin-1 to UTF-8"
-}
(_,Just coding') ->
when (coding/=coding') $
raise $ "Encoding mismatch: "++coding++" /= "++coding' raise $ "Encoding mismatch: "++coding++" /= "++coding'
where coding = maybe defaultEncoding renameEncoding optCoding where coding = maybe defaultEncoding renameEncoding optCoding
_ -> return () _ -> return ()
return (i,mi) --liftIO $ transcodeModule' (i,mi) -- old lexer
return (i,mi) -- new lexer
getBNFCRules :: Options -> FilePath -> IOE [BNFCRule] getBNFCRules :: Options -> FilePath -> IOE [BNFCRule]
getBNFCRules opts fpath = do getBNFCRules opts fpath = do

View File

@@ -17,14 +17,15 @@ 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,prefixIdent,showIdent,isWildIdent)
import GF.Infra.Option(optionsPGF) import GF.Infra.Option(Options, optionsPGF)
import PGF2.Internal(Literal(..)) import PGF.Internal(Literal(..))
import GF.Compile.Compute.ConcreteNew(normalForm,resourceValues) import GF.Compile.Compute.ConcreteNew(normalForm,resourceValues)
import GF.Grammar.Canonical as C import GF.Grammar.Canonical as C
import Debug.Trace import Debug.Trace
-- | 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 -> SourceGrammar -> C.Grammar
grammar2canonical opts absname gr = grammar2canonical opts absname gr =
Grammar (abstract2canonical absname gr) Grammar (abstract2canonical absname gr)
(map snd (concretes2canonical opts absname gr)) (map snd (concretes2canonical opts absname gr))
@@ -353,9 +354,9 @@ paramType gr q@(_,n) =
[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 = LabelId . render -- hmm
modId (MN m) = ModId (showIdent m) modId (MN m) = ModId (showIdent m)

View File

@@ -0,0 +1,447 @@
module GF.Compile.GrammarToLPGF (mkCanon2lpgf) where
import LPGF (LPGF (..))
import qualified LPGF as L
import PGF.CId
import GF.Grammar.Grammar
import qualified GF.Grammar.Canonical as C
import GF.Compile.GrammarToCanonical (grammar2canonical)
import GF.Data.Operations (ErrorMonad (..))
import qualified GF.Data.IntMapBuilder as IntMapBuilder
import GF.Infra.Option (Options)
import GF.Infra.UseIO (IOE)
import GF.Text.Pretty (pp, render)
import Control.Applicative ((<|>))
import Control.Monad (when, unless, forM, forM_)
import qualified Control.Monad.State as CMS
import Data.Either (lefts, rights)
import qualified Data.IntMap as IntMap
import Data.List (elemIndex)
import qualified Data.List as L
import qualified Data.Map.Strict as Map
import Data.Maybe (fromJust, isJust)
import System.Environment (lookupEnv)
import System.FilePath ((</>), (<.>))
import Text.Printf (printf)
import qualified Debug.Trace
trace x = Debug.Trace.trace ("> " ++ show x) (return ())
mkCanon2lpgf :: Options -> SourceGrammar -> ModuleName -> IOE LPGF
mkCanon2lpgf opts gr am = do
debug <- isJust <$> lookupEnv "DEBUG"
when debug $ do
ppCanonical debugDir canon
dumpCanonical debugDir canon
(an,abs) <- mkAbstract ab
cncs <- mapM (mkConcrete debug) cncs
let lpgf = LPGF {
L.absname = an,
L.abstract = abs,
L.concretes = Map.fromList cncs
}
when debug $ ppLPGF debugDir lpgf
return lpgf
where
canon@(C.Grammar ab cncs) = grammar2canonical opts am gr
mkAbstract :: (ErrorMonad err) => C.Abstract -> err (CId, L.Abstract)
mkAbstract (C.Abstract modId flags cats funs) = return (mdi2i modId, L.Abstract {})
mkConcrete :: (ErrorMonad err) => Bool -> C.Concrete -> err (CId, L.Concrete)
mkConcrete debug (C.Concrete modId absModId flags params' lincats lindefs) = do
let
(C.Abstract _ _ _ funs) = ab
params = inlineParamAliases params'
-- Builds maps for lookups
paramValueMap :: Map.Map C.ParamId C.ParamDef -- constructor -> definition
paramValueMap = Map.fromList [ (v,d) | d@(C.ParamDef _ vs) <- params, (C.Param v _) <- vs ]
lincatMap :: Map.Map C.CatId C.LincatDef
lincatMap = Map.fromList [ (cid,d) | d@(C.LincatDef cid _) <- lincats ]
funMap :: Map.Map C.FunId C.FunDef
funMap = Map.fromList [ (fid,d) | d@(C.FunDef fid _) <- funs ]
-- | Lookup paramdef, providing dummy fallback when not found
-- Workaround for https://github.com/GrammaticalFramework/gf-core/issues/100
lookupParamDef :: C.ParamId -> Either String C.ParamDef
lookupParamDef pid = case Map.lookup pid paramValueMap of
Just d -> Right d
Nothing ->
-- Left $ printf "Cannot find param definition: %s" (show pid)
Right $ C.ParamDef (C.ParamId (C.Unqual "DUMMY")) [C.Param pid []]
-- | Lookup lintype for a function
lookupLinType :: C.FunId -> Either String C.LinType
lookupLinType funId = do
fun <- m2e (printf "Cannot find type for: %s" (show funId)) (Map.lookup funId funMap)
let (C.FunDef _ (C.Type _ (C.TypeApp catId _))) = fun
lincat <- m2e (printf "Cannot find lincat for: %s" (show catId)) (Map.lookup catId lincatMap)
let (C.LincatDef _ lt) = lincat
return lt
-- | Lookup lintype for a function's argument
lookupLinTypeArg :: C.FunId -> Int -> Either String C.LinType
lookupLinTypeArg funId argIx = do
fun <- m2e (printf "Cannot find type for: %s" (show funId)) (Map.lookup funId funMap)
let (C.FunDef _ (C.Type args _)) = fun
let (C.TypeBinding _ (C.Type _ (C.TypeApp catId _))) = args !! argIx
lincat <- m2e (printf "Cannot find lincat for: %s" (show catId)) (Map.lookup catId lincatMap)
let (C.LincatDef _ lt) = lincat
return lt
-- Filter out record fields from definitions which don't appear in lincat.
-- Workaround for https://github.com/GrammaticalFramework/gf-core/issues/101
cleanupRecordFields :: C.LinValue -> C.LinType -> C.LinValue
cleanupRecordFields (C.RecordValue rrvs) (C.RecordType rrs) =
let defnFields = Map.fromList [ (lid, lt) | (C.RecordRow lid lt) <- rrs ]
in C.RecordValue
[ C.RecordRow lid lv'
| C.RecordRow lid lv <- rrvs
, Map.member lid defnFields
, let Just lt = Map.lookup lid defnFields
, let lv' = cleanupRecordFields lv lt
]
cleanupRecordFields lv _ = lv
lindefs' =
[ C.LinDef funId varIds linValue'
| (C.LinDef funId varIds linValue) <- lindefs
, let Right linType = lookupLinType funId
, let linValue' = cleanupRecordFields linValue linType
]
es = map mkLin lindefs'
lins = Map.fromList $ rights es
-- | Main code generation function
mkLin :: C.LinDef -> Either String (CId, L.LinFun)
mkLin (C.LinDef funId varIds linValue) = do
-- when debug $ trace funId
(lf, _) <- val2lin linValue
return (fi2i funId, lf)
where
val2lin :: C.LinValue -> Either String (L.LinFun, Maybe C.LinType)
val2lin lv = case lv of
C.ConcatValue v1 v2 -> do
(v1',t1) <- val2lin v1
(v2',t2) <- val2lin v2
return (L.Concat v1' v2', t1 <|> t2) -- t1 else t2
C.LiteralValue ll -> case ll of
C.FloatConstant f -> return (L.Token $ show f, Just C.FloatType)
C.IntConstant i -> return (L.Token $ show i, Just C.IntType)
C.StrConstant s -> return (L.Token s, Just C.StrType)
C.ErrorValue err -> return (L.Error err, Nothing)
C.ParamConstant (C.Param pid lvs) -> do
let
collectProjections :: C.LinValue -> Either String [L.LinFun]
collectProjections (C.ParamConstant (C.Param pid lvs)) = do
def <- lookupParamDef pid
let (C.ParamDef tpid defpids) = def
pidIx <- eitherElemIndex pid [ p | C.Param p _ <- defpids ]
rest <- mapM collectProjections lvs
return $ L.Ix (pidIx+1) : concat rest
collectProjections lv = do
(lf,_) <- val2lin lv
return [lf]
lfs <- collectProjections lv
let term = L.Tuple lfs
def <- lookupParamDef pid
let (C.ParamDef tpid _) = def
return (term, Just $ C.ParamType (C.ParamTypeId tpid))
C.PredefValue (C.PredefId pid) -> case pid of
"BIND" -> return (L.Bind, Nothing)
"SOFT_BIND" -> return (L.Bind, Nothing)
"SOFT_SPACE" -> return (L.Space, Nothing)
"CAPIT" -> return (L.Capit, Nothing)
"ALL_CAPIT" -> return (L.AllCapit, Nothing)
_ -> Left $ printf "Unknown predef function: %s" pid
C.RecordValue rrvs -> do
let rrvs' = sortRecordRows rrvs
ts <- sequence [ val2lin lv | C.RecordRow lid lv <- rrvs' ]
return (L.Tuple (map fst ts), Just $ C.RecordType [ C.RecordRow lid lt | (C.RecordRow lid _, (_, Just lt)) <- zip rrvs' ts])
C.TableValue lt trvs -> do
-- group the rows by "left-most" value
let
groupRow :: C.TableRowValue -> C.TableRowValue -> Bool
groupRow (C.TableRow p1 _) (C.TableRow p2 _) = groupPattern p1 p2
groupPattern :: C.LinPattern -> C.LinPattern -> Bool
groupPattern p1 p2 = case (p1,p2) of
(C.ParamPattern (C.Param pid1 _), C.ParamPattern (C.Param pid2 _)) -> pid1 == pid2 -- compare only constructors
(C.RecordPattern (C.RecordRow lid1 patt1:_), C.RecordPattern (C.RecordRow lid2 patt2:_)) -> groupPattern patt1 patt2 -- lid1 == lid2 necessarily
_ -> error $ printf "Mismatched patterns in grouping:\n%s\n%s" (show p1) (show p2)
grps :: [[C.TableRowValue]]
grps = L.groupBy groupRow trvs
-- remove one level of depth and recurse
let
handleGroup :: [C.TableRowValue] -> Either String (L.LinFun, Maybe C.LinType)
handleGroup [C.TableRow patt lv] =
case reducePattern patt of
Just patt' -> do
(lf,lt) <- handleGroup [C.TableRow patt' lv]
return (L.Tuple [lf],lt)
Nothing -> val2lin lv
handleGroup rows = do
let rows' = map reduceRow rows
val2lin (C.TableValue lt rows') -- lt is wrong here, but is unused
reducePattern :: C.LinPattern -> Maybe C.LinPattern
reducePattern patt =
case patt of
C.ParamPattern (C.Param _ []) -> Nothing
C.ParamPattern (C.Param _ patts) -> Just $ C.ParamPattern (C.Param pid' patts')
where
C.ParamPattern (C.Param pid1 patts1) = head patts
pid' = pid1
patts' = patts1 ++ tail patts
C.RecordPattern [] -> Nothing
C.RecordPattern (C.RecordRow lid patt:rrs) ->
case reducePattern patt of
Just patt' -> Just $ C.RecordPattern (C.RecordRow lid patt':rrs)
Nothing -> if null rrs then Nothing else Just $ C.RecordPattern rrs
_ -> error $ printf "Unhandled pattern in reducing: %s" (show patt)
reduceRow :: C.TableRowValue -> C.TableRowValue
reduceRow (C.TableRow patt lv) =
let Just patt' = reducePattern patt
in C.TableRow patt' lv
-- ts :: [(L.LinFun, Maybe C.LinType)]
ts <- mapM handleGroup grps
-- return
let typ = case ts of
(_, Just tst):_ -> Just $ C.TableType lt tst
_ -> Nothing
return (L.Tuple (map fst ts), typ)
-- TODO TuplePattern, WildPattern?
C.TupleValue lvs -> do
ts <- mapM val2lin lvs
return (L.Tuple (map fst ts), Just $ C.TupleType (map (fromJust.snd) ts))
C.VariantValue [] -> return (L.Empty, Nothing) -- TODO Just C.StrType ?
C.VariantValue (vr:_) -> val2lin vr -- NOTE variants not supported, just pick first
C.VarValue (C.VarValueId (C.Unqual v)) -> do
ix <- eitherElemIndex (C.VarId v) varIds
lt <- lookupLinTypeArg funId ix
return (L.Argument (ix+1), Just lt)
C.PreValue pts df -> do
pts' <- forM pts $ \(pfxs, lv) -> do
(lv', _) <- val2lin lv
return (pfxs, lv')
(df', lt) <- val2lin df
return (L.Pre pts' df', lt)
C.Projection v1 lblId -> do
(v1', mtyp) <- val2lin v1
-- find label index in argument type
let Just (C.RecordType rrs) = mtyp
let rrs' = [ lid | C.RecordRow lid _ <- rrs ]
-- lblIx <- eitherElemIndex lblId rrs'
let
lblIx = case eitherElemIndex lblId rrs' of
Right x -> x
Left _ -> 0 -- corresponds to Prelude.False
-- lookup lintype for record row
let C.RecordRow _ lt = rrs !! lblIx
return (L.Projection v1' (L.Ix (lblIx+1)), Just lt)
C.Selection v1 v2 -> do
(v1', t1) <- val2lin v1
(v2', t2) <- val2lin v2
let Just (C.TableType t11 t12) = t1 -- t11 == t2
return (L.Projection v1' v2', Just t12)
-- C.CommentedValue cmnt lv -> val2lin lv
C.CommentedValue cmnt lv -> case cmnt of
"impossible" -> val2lin lv >>= \(_, typ) -> return (L.Empty, typ)
_ -> val2lin lv
v -> Left $ printf "val2lin not implemented for: %s" (show v)
unless (null $ lefts es) (raise $ unlines (lefts es))
let maybeOptimise = if debug then id else extractStrings
let concr = maybeOptimise $ L.Concrete {
L.toks = IntMap.empty,
L.lins = lins
}
return (mdi2i modId, concr)
-- | Remove ParamAliasDefs by inlining their definitions
inlineParamAliases :: [C.ParamDef] -> [C.ParamDef]
inlineParamAliases defs = if null aliases then defs else map rp' pdefs
where
(aliases,pdefs) = L.partition isParamAliasDef defs
rp' :: C.ParamDef -> C.ParamDef
rp' (C.ParamDef pid pids) = C.ParamDef pid (map rp'' pids)
rp' (C.ParamAliasDef _ _) = error "inlineParamAliases called on ParamAliasDef" -- impossible
rp'' :: C.ParamValueDef -> C.ParamValueDef
rp'' (C.Param pid pids) = C.Param pid (map rp''' pids)
rp''' :: C.ParamId -> C.ParamId
rp''' pid = case L.find (\(C.ParamAliasDef p _) -> p == pid) aliases of
Just (C.ParamAliasDef _ (C.ParamType (C.ParamTypeId p))) -> p
_ -> pid
-- | Always put 's' reocord field first, then sort alphabetically.
-- Workaround for https://github.com/GrammaticalFramework/gf-core/issues/102
-- Based on GF.Granmar.Macros.sortRec
sortRecordRows :: [C.RecordRowValue] -> [C.RecordRowValue]
sortRecordRows = L.sortBy ordLabel
where
ordLabel (C.RecordRow (C.LabelId l1) _) (C.RecordRow (C.LabelId l2) _) =
case (l1,l2) of
("s",_) -> LT
(_,"s") -> GT
(s1,s2) -> compare s1 s2
-- sortRecord :: C.LinValue -> C.LinValue
-- sortRecord (C.RecordValue rrvs) = C.RecordValue (sortRecordRows rrvs)
-- sortRecord lv = lv
isParamAliasDef :: C.ParamDef -> Bool
isParamAliasDef (C.ParamAliasDef _ _) = True
isParamAliasDef _ = False
isParamType :: C.LinType -> Bool
isParamType (C.ParamType _) = True
isParamType _ = False
isRecordType :: C.LinType -> Bool
isRecordType (C.RecordType _) = True
isRecordType _ = False
-- | Find all token strings, put them in a map and replace with token indexes
extractStrings :: L.Concrete -> L.Concrete
extractStrings concr = L.Concrete { L.toks = toks', L.lins = lins' }
where
imb = IntMapBuilder.fromIntMap (L.toks concr)
(lins',imb') = CMS.runState (go0 (L.lins concr)) imb
toks' = IntMapBuilder.toIntMap imb'
go0 :: Map.Map CId L.LinFun -> CMS.State (IntMapBuilder.IMB String) (Map.Map CId L.LinFun)
go0 mp = do
xs <- mapM (\(cid,lin) -> go lin >>= \lin' -> return (cid,lin')) (Map.toList mp)
return $ Map.fromList xs
go :: L.LinFun -> CMS.State (IntMapBuilder.IMB String) L.LinFun
go lf = case lf of
L.Token str -> do
imb <- CMS.get
let (ix,imb') = IntMapBuilder.insert' str imb
CMS.put imb'
return $ L.TokenIx ix
L.Pre pts df -> do
-- pts' <- mapM (\(pfxs,lv) -> go lv >>= \lv' -> return (pfxs,lv')) pts
pts' <- forM pts $ \(pfxs,lv) -> do
imb <- CMS.get
let str = show pfxs
let (ix,imb') = IntMapBuilder.insert' str imb
CMS.put imb'
lv' <- go lv
return (ix,lv')
df' <- go df
return $ L.PreIx pts' df'
L.Concat s t -> do
s' <- go s
t' <- go t
return $ L.Concat s' t'
L.Tuple ts -> do
ts' <- mapM go ts
return $ L.Tuple ts'
L.Projection t u -> do
t' <- go t
u' <- go u
return $ L.Projection t' u'
t -> return t
-- | Convert Maybe to Either value with error
m2e :: String -> Maybe a -> Either String a
m2e err = maybe (Left err) Right
-- | Wrap elemIndex into Either value
eitherElemIndex :: (Eq a, Show a) => a -> [a] -> Either String Int
eitherElemIndex x xs = m2e (printf "Cannot find: %s in %s" (show x) (show xs)) (elemIndex x xs)
mdi2s :: C.ModId -> String
mdi2s (C.ModId i) = i
mdi2i :: C.ModId -> CId
mdi2i (C.ModId i) = mkCId i
fi2i :: C.FunId -> CId
fi2i (C.FunId i) = mkCId i
-- Debugging
debugDir :: FilePath
debugDir = "DEBUG"
-- | Pretty-print canonical grammars to file
ppCanonical :: FilePath -> C.Grammar -> IO ()
ppCanonical path (C.Grammar ab cncs) = do
let (C.Abstract modId flags cats funs) = ab
writeFile (path </> mdi2s modId <.> "canonical.gf") (render $ pp ab)
forM_ cncs $ \cnc@(C.Concrete modId absModId flags params lincats lindefs) ->
writeFile' (path </> mdi2s modId <.> "canonical.gf") (render $ pp cnc)
-- | Dump canonical grammars to file
dumpCanonical :: FilePath -> C.Grammar -> IO ()
dumpCanonical path (C.Grammar ab cncs) = do
let (C.Abstract modId flags cats funs) = ab
let body = unlines $ map show cats ++ [""] ++ map show funs
writeFile' (path </> mdi2s modId <.> "canonical.dump") body
forM_ cncs $ \(C.Concrete modId absModId flags params lincats lindefs) -> do
let body = unlines $ concat [
map show params,
[""],
map show lincats,
[""],
map show lindefs
]
writeFile' (path </> mdi2s modId <.> "canonical.dump") body
-- | Pretty-print LPGF to file
ppLPGF :: FilePath -> LPGF -> IO ()
ppLPGF path lpgf =
forM_ (Map.toList $ L.concretes lpgf) $ \(cid,concr) ->
writeFile' (path </> showCId cid <.> "lpgf.txt") (L.render $ L.pp concr)
-- | Dump LPGF to file
dumpLPGF :: FilePath -> LPGF -> IO ()
dumpLPGF path lpgf =
forM_ (Map.toList $ L.concretes lpgf) $ \(cid,concr) -> do
let body = unlines $ map show (Map.toList $ L.lins concr)
writeFile' (path </> showCId cid <.> "lpgf.dump") body
-- | Write a file and report it to console
writeFile' :: FilePath -> String -> IO ()
writeFile' p b = do
writeFile p b
putStrLn $ "Wrote " ++ p

View File

@@ -1,14 +1,17 @@
{-# LANGUAGE ImplicitParams, BangPatterns, FlexibleContexts, MagicHash #-} {-# LANGUAGE BangPatterns, FlexibleContexts #-}
module GF.Compile.GrammarToPGF (grammar2PGF) where module GF.Compile.GrammarToPGF (mkCanon2pgf) where
--import GF.Compile.Export
import GF.Compile.GeneratePMCFG import GF.Compile.GeneratePMCFG
import GF.Compile.GenerateBC import GF.Compile.GenerateBC
import GF.Compile.OptimizePGF
import PGF2 hiding (mkType) import PGF(CId,mkCId,utf8CId)
import PGF2.Internal import PGF.Internal(fidInt,fidFloat,fidString,fidVar)
import PGF.Internal(updateProductionIndices)
import qualified PGF.Internal as C
import qualified PGF.Internal as D
import GF.Grammar.Predef import GF.Grammar.Predef
import GF.Grammar.Grammar hiding (Production) import GF.Grammar.Grammar
import qualified GF.Grammar.Lookup as Look import qualified GF.Grammar.Lookup as Look
import qualified GF.Grammar as A import qualified GF.Grammar as A
import qualified GF.Grammar.Macros as GM import qualified GF.Grammar.Macros as GM
@@ -19,141 +22,111 @@ import GF.Infra.UseIO (IOE)
import GF.Data.Operations import GF.Data.Operations
import Data.List import Data.List
import Data.Char
import qualified Data.Set as Set import qualified Data.Set as Set
import qualified Data.Map as Map import qualified Data.Map as Map
import qualified Data.IntMap as IntMap import qualified Data.IntMap as IntMap
import Data.Array.IArray import Data.Array.IArray
import Data.Maybe(fromMaybe)
import GHC.Prim
import GHC.Base(getTag)
grammar2PGF :: Options -> SourceGrammar -> ModuleName -> Map.Map PGF2.Fun Double -> IO PGF mkCanon2pgf :: Options -> SourceGrammar -> ModuleName -> IOE D.PGF
grammar2PGF opts gr am probs = do mkCanon2pgf opts gr am = do
cnc_infos <- getConcreteInfos gr am (an,abs) <- mkAbstr am
return $ cncs <- mapM mkConcr (allConcretes gr am)
build (let gflags = if flag optSplitPGF opts return $ updateProductionIndices (D.PGF Map.empty an abs (Map.fromList cncs))
then [("split", LStr "true")]
else []
(an,abs) = mkAbstr am probs
cncs = map (mkConcr opts abs) cnc_infos
in newPGF gflags an abs cncs)
where where
cenv = resourceValues opts gr cenv = resourceValues opts gr
aflags = err (const noOptions) mflags (lookupModule gr am)
mkAbstr :: (?builder :: Builder s) => ModuleName -> Map.Map PGF2.Fun Double -> (AbsName, B s AbstrInfo) mkAbstr am = return (mi2i am, D.Abstr flags funs cats)
mkAbstr am probs = (mi2i am, newAbstr flags cats funs)
where where
aflags = err (const noOptions) mflags (lookupModule gr am)
adefs = adefs =
[((cPredefAbs,c), AbsCat (Just (L NoLoc []))) | c <- [cFloat,cInt,cString]] ++ [((cPredefAbs,c), AbsCat (Just (L NoLoc []))) | c <- [cFloat,cInt,cString]] ++
Look.allOrigInfos gr am Look.allOrigInfos gr am
flags = optionsPGF aflags flags = Map.fromList [(mkCId f,x) | (f,x) <- optionsPGF aflags]
toLogProb = realToFrac . negate . log funs = Map.fromList [(i2i f, (mkType [] ty, arity, mkDef gr arity mdef, 0)) |
cats = [(c', snd (mkContext [] cont), toLogProb (fromMaybe 0 (Map.lookup c' probs))) |
((m,c),AbsCat (Just (L _ cont))) <- adefs, let c' = i2i c]
funs = [(f', mkType [] ty, arity, bcode, toLogProb (fromMaybe 0 (Map.lookup f' funs_probs))) |
((m,f),AbsFun (Just (L _ ty)) ma mdef _) <- adefs, ((m,f),AbsFun (Just (L _ ty)) ma mdef _) <- adefs,
let arity = mkArity ma mdef ty, let arity = mkArity ma mdef ty]
let bcode = mkDef gr arity mdef,
let f' = i2i f]
funs_probs = (Map.fromList . concat . Map.elems . fmap pad . Map.fromListWith (++)) cats = Map.fromList [(i2i c, (snd (mkContext [] cont),catfuns c, 0)) |
[(i2i cat,[(i2i f,Map.lookup f' probs)]) | ((m,f),AbsFun (Just (L _ ty)) _ _ _) <- adefs, ((m,c),AbsCat (Just (L _ cont))) <- adefs]
let (_,(_,cat),_) = GM.typeForm ty,
let f' = i2i f]
where
pad :: [(a,Maybe Double)] -> [(a,Double)]
pad pfs = [(f,fromMaybe deflt mb_p) | (f,mb_p) <- pfs]
where
deflt = case length [f | (f,Nothing) <- pfs] of
0 -> 0
n -> max 0 ((1 - sum [d | (f,Just d) <- pfs]) / fromIntegral n)
mkConcr opts abs (cm,ex_seqs,cdefs) = catfuns cat =
[(0,i2i f) | ((m,f),AbsFun (Just (L _ ty)) _ _ (Just True)) <- adefs, snd (GM.valCat ty) == cat]
mkConcr cm = do
let cflags = err (const noOptions) mflags (lookupModule gr cm) let cflags = err (const noOptions) mflags (lookupModule gr cm)
ciCmp | flag optCaseSensitive cflags = compare ciCmp | flag optCaseSensitive cflags = compare
| otherwise = compareCaseInsensitive | otherwise = C.compareCaseInsensitve
flags = optionsPGF aflags (ex_seqs,cdefs) <- addMissingPMCFGs
Map.empty
([((cPredefAbs,c), CncCat (Just (L NoLoc GM.defLinType)) Nothing Nothing Nothing Nothing) | c <- [cInt,cFloat,cString]] ++
Look.allOrigInfos gr cm)
seqs = (mkSetArray . Set.fromList . concat) $ let flags = Map.fromList [(mkCId f,x) | (f,x) <- optionsPGF cflags]
(elems (ex_seqs :: Array SeqId [Symbol]) : [maybe [] elems (mseqs mi) | (m,mi) <- allExtends gr cm])
seqs = (mkArray . C.sortNubBy ciCmp . concat) $
(Map.keys ex_seqs : [maybe [] elems (mseqs mi) | (m,mi) <- allExtends gr cm])
ex_seqs_arr = mkMapArray ex_seqs :: Array SeqId Sequence
!(!fid_cnt1,!cnccats) = genCncCats gr am cm cdefs !(!fid_cnt1,!cnccats) = genCncCats gr am cm cdefs
cnccat_ranges = Map.fromList (map (\(cid,s,e,_) -> (cid,(s,e))) cnccats)
!(!fid_cnt2,!productions,!lindefs,!linrefs,!cncfuns) !(!fid_cnt2,!productions,!lindefs,!linrefs,!cncfuns)
= genCncFuns gr am cm ex_seqs ciCmp seqs cdefs fid_cnt1 cnccat_ranges = genCncFuns gr am cm ex_seqs_arr ciCmp seqs cdefs fid_cnt1 cnccats
printnames = genPrintNames cdefs printnames = genPrintNames cdefs
return (mi2i cm, D.Concr flags
startCat = (fromMaybe "S" (flag optStartCat aflags)) printnames
cncfuns
(lindefs',linrefs',productions',cncfuns',sequences',cnccats') = lindefs
(if flag optOptimizePGF opts then optimizePGF startCat else id) linrefs
(lindefs,linrefs,productions,cncfuns,elems seqs,cnccats) seqs
productions
in (mi2i cm, newConcr abs IntMap.empty
flags Map.empty
printnames cnccats
lindefs' IntMap.empty
linrefs' fid_cnt2)
productions'
cncfuns'
sequences'
cnccats'
fid_cnt2)
getConcreteInfos gr am = mapM flatten (allConcretes gr am)
where where
flatten cm = do
(seqs,infos) <- addMissingPMCFGs cm Map.empty
(lit_infos ++ Look.allOrigInfos gr cm)
return (cm,mkMapArray seqs :: Array SeqId [Symbol],infos)
lit_infos = [((cPredefAbs,c), CncCat (Just (L NoLoc GM.defLinType)) Nothing Nothing Nothing Nothing) | c <- [cInt,cFloat,cString]]
-- if some module was compiled with -no-pmcfg, then -- if some module was compiled with -no-pmcfg, then
-- we have to create the PMCFG code just before linking -- we have to create the PMCFG code just before linking
addMissingPMCFGs cm seqs [] = return (seqs,[]) addMissingPMCFGs seqs [] = return (seqs,[])
addMissingPMCFGs cm seqs (((m,id), info):is) = do addMissingPMCFGs seqs (((m,id), info):is) = do
(seqs,info) <- addPMCFG opts gr cenv Nothing am cm seqs id info (seqs,info) <- addPMCFG opts gr cenv Nothing am cm seqs id info
(seqs,infos) <- addMissingPMCFGs cm seqs is (seqs,is ) <- addMissingPMCFGs seqs is
return (seqs, ((m,id), info) : infos) return (seqs, ((m,id), info) : is)
i2i :: Ident -> String i2i :: Ident -> CId
i2i = showIdent i2i = utf8CId . ident2utf8
mi2i :: ModuleName -> String mi2i :: ModuleName -> CId
mi2i (MN i) = i2i i mi2i (MN i) = i2i i
mkType :: (?builder :: Builder s) => [Ident] -> A.Type -> B s PGF2.Type mkType :: [Ident] -> A.Type -> C.Type
mkType scope t = mkType scope t =
case GM.typeForm t of case GM.typeForm t of
(hyps,(_,cat),args) -> let (scope',hyps') = mkContext scope hyps (hyps,(_,cat),args) -> let (scope',hyps') = mkContext scope hyps
in dTyp hyps' (i2i cat) (map (mkExp scope') args) in C.DTyp hyps' (i2i cat) (map (mkExp scope') args)
mkExp :: (?builder :: Builder s) => [Ident] -> A.Term -> B s Expr mkExp :: [Ident] -> A.Term -> C.Expr
mkExp scope t = mkExp scope t =
case t of case t of
Q (_,c) -> eFun (i2i c) Q (_,c) -> C.EFun (i2i c)
QC (_,c) -> eFun (i2i c) QC (_,c) -> C.EFun (i2i c)
Vr x -> case lookup x (zip scope [0..]) of Vr x -> case lookup x (zip scope [0..]) of
Just i -> eVar i Just i -> C.EVar i
Nothing -> eMeta 0 Nothing -> C.EMeta 0
Abs b x t-> eAbs b (i2i x) (mkExp (x:scope) t) Abs b x t-> C.EAbs b (i2i x) (mkExp (x:scope) t)
App t1 t2-> eApp (mkExp scope t1) (mkExp scope t2) App t1 t2-> C.EApp (mkExp scope t1) (mkExp scope t2)
EInt i -> eLit (LInt (fromIntegral i)) EInt i -> C.ELit (C.LInt (fromIntegral i))
EFloat f -> eLit (LFlt f) EFloat f -> C.ELit (C.LFlt f)
K s -> eLit (LStr s) K s -> C.ELit (C.LStr s)
Meta i -> eMeta i Meta i -> C.EMeta i
_ -> eMeta 0 _ -> C.EMeta 0
{-
mkPatt scope p = mkPatt scope p =
case p of case p of
A.PP (_,c) ps->let (scope',ps') = mapAccumL mkPatt scope ps A.PP (_,c) ps->let (scope',ps') = mapAccumL mkPatt scope ps
@@ -168,64 +141,67 @@ mkPatt scope p =
A.PImplArg p-> let (scope',p') = mkPatt scope p A.PImplArg p-> let (scope',p') = mkPatt scope p
in (scope',C.PImplArg p') in (scope',C.PImplArg p')
A.PTilde t -> ( scope,C.PTilde (mkExp scope t)) A.PTilde t -> ( scope,C.PTilde (mkExp scope t))
-}
mkContext :: (?builder :: Builder s) => [Ident] -> A.Context -> ([Ident],[B s PGF2.Hypo]) mkContext :: [Ident] -> A.Context -> ([Ident],[C.Hypo])
mkContext scope hyps = mapAccumL (\scope (bt,x,ty) -> let ty' = mkType scope ty mkContext scope hyps = mapAccumL (\scope (bt,x,ty) -> let ty' = mkType scope ty
in if x == identW in if x == identW
then ( scope,hypo bt (i2i x) ty') then ( scope,(bt,i2i x,ty'))
else (x:scope,hypo bt (i2i x) ty')) scope hyps else (x:scope,(bt,i2i x,ty'))) scope hyps
mkDef gr arity (Just eqs) = generateByteCode gr arity eqs mkDef gr arity (Just eqs) = Just ([C.Equ ps' (mkExp scope' e) | L _ (ps,e) <- eqs, let (scope',ps') = mapAccumL mkPatt [] ps]
mkDef gr arity Nothing = [] ,generateByteCode gr arity eqs
)
mkDef gr arity Nothing = Nothing
mkArity (Just a) _ ty = a -- known arity, i.e. defined function mkArity (Just a) _ ty = a -- known arity, i.e. defined function
mkArity Nothing (Just _) ty = 0 -- defined function with no arity - must be an axiom mkArity Nothing (Just _) ty = 0 -- defined function with no arity - must be an axiom
mkArity Nothing _ ty = let (ctxt, _, _) = GM.typeForm ty -- constructor mkArity Nothing _ ty = let (ctxt, _, _) = GM.typeForm ty -- constructor
in length ctxt in length ctxt
genCncCats gr am cm cdefs = mkCncCats 0 cdefs genCncCats gr am cm cdefs =
let (index,cats) = mkCncCats 0 cdefs
in (index, Map.fromList cats)
where where
mkCncCats index [] = (index,[]) mkCncCats index [] = (index,[])
mkCncCats index (((m,id),CncCat (Just (L _ lincat)) _ _ _ _):cdefs) mkCncCats index (((m,id),CncCat (Just (L _ lincat)) _ _ _ _):cdefs)
| id == cInt = | id == cInt =
let cc = pgfCncCat gr (i2i id) lincat fidInt let cc = pgfCncCat gr lincat fidInt
(index',cats) = mkCncCats index cdefs (index',cats) = mkCncCats index cdefs
in (index', cc : cats) in (index', (i2i id,cc) : cats)
| id == cFloat = | id == cFloat =
let cc = pgfCncCat gr (i2i id) lincat fidFloat let cc = pgfCncCat gr lincat fidFloat
(index',cats) = mkCncCats index cdefs (index',cats) = mkCncCats index cdefs
in (index', cc : cats) in (index', (i2i id,cc) : cats)
| id == cString = | id == cString =
let cc = pgfCncCat gr (i2i id) lincat fidString let cc = pgfCncCat gr lincat fidString
(index',cats) = mkCncCats index cdefs (index',cats) = mkCncCats index cdefs
in (index', cc : cats) in (index', (i2i id,cc) : cats)
| otherwise = | otherwise =
let cc@(_, _s, e, _) = pgfCncCat gr (i2i id) lincat index let cc@(C.CncCat _s e _) = pgfCncCat gr lincat index
(index',cats) = mkCncCats (e+1) cdefs (index',cats) = mkCncCats (e+1) cdefs
in (index', cc : cats) in (index', (i2i id,cc) : cats)
mkCncCats index (_ :cdefs) = mkCncCats index cdefs mkCncCats index (_ :cdefs) = mkCncCats index cdefs
genCncFuns :: Grammar genCncFuns :: Grammar
-> ModuleName -> ModuleName
-> ModuleName -> ModuleName
-> Array SeqId [Symbol] -> Array SeqId Sequence
-> ([Symbol] -> [Symbol] -> Ordering) -> (Sequence -> Sequence -> Ordering)
-> Array SeqId [Symbol] -> Array SeqId Sequence
-> [(QIdent, Info)] -> [(QIdent, Info)]
-> FId -> FId
-> Map.Map PGF2.Cat (Int,Int) -> Map.Map CId D.CncCat
-> (FId, -> (FId,
[(FId, [Production])], IntMap.IntMap (Set.Set D.Production),
[(FId, [FunId])], IntMap.IntMap [FunId],
[(FId, [FunId])], IntMap.IntMap [FunId],
[(PGF2.Fun,[SeqId])]) Array FunId D.CncFun)
genCncFuns gr am cm ex_seqs ciCmp seqs cdefs fid_cnt cnccat_ranges = genCncFuns gr am cm ex_seqs ciCmp seqs cdefs fid_cnt cnccats =
let (fid_cnt1,funs_cnt1,funs1,lindefs,linrefs) = mkCncCats cdefs fid_cnt 0 [] IntMap.empty IntMap.empty let (fid_cnt1,funs_cnt1,funs1,lindefs,linrefs) = mkCncCats cdefs fid_cnt 0 [] IntMap.empty IntMap.empty
(fid_cnt2,funs_cnt2,funs2,prods0) = mkCncFuns cdefs fid_cnt1 funs_cnt1 funs1 lindefs Map.empty IntMap.empty (fid_cnt2,funs_cnt2,funs2,prods) = mkCncFuns cdefs fid_cnt1 funs_cnt1 funs1 lindefs Map.empty IntMap.empty
prods = [(fid,Set.toList prodSet) | (fid,prodSet) <- IntMap.toList prods0] in (fid_cnt2,prods,lindefs,linrefs,array (0,funs_cnt2-1) funs2)
in (fid_cnt2,prods,IntMap.toList lindefs,IntMap.toList linrefs,reverse funs2)
where where
mkCncCats [] fid_cnt funs_cnt funs lindefs linrefs = mkCncCats [] fid_cnt funs_cnt funs lindefs linrefs =
(fid_cnt,funs_cnt,funs,lindefs,linrefs) (fid_cnt,funs_cnt,funs,lindefs,linrefs)
mkCncCats (((m,id),CncCat _ _ _ _ (Just (PMCFG prods0 funs0))):cdefs) fid_cnt funs_cnt funs lindefs linrefs = mkCncCats (((m,id),CncCat _ _ _ _ (Just (PMCFG prods0 funs0))):cdefs) fid_cnt funs_cnt funs lindefs linrefs =
let !funs_cnt' = let (s_funid, e_funid) = bounds funs0 let !funs_cnt' = let (s_funid, e_funid) = bounds funs0
@@ -234,13 +210,14 @@ genCncFuns gr am cm ex_seqs ciCmp seqs cdefs fid_cnt cnccat_ranges =
linrefs' = foldl' (toLinRef (am,id) funs_cnt) linrefs prods0 linrefs' = foldl' (toLinRef (am,id) funs_cnt) linrefs prods0
funs' = foldl' (toCncFun funs_cnt (m,mkLinDefId id)) funs (assocs funs0) funs' = foldl' (toCncFun funs_cnt (m,mkLinDefId id)) funs (assocs funs0)
in mkCncCats cdefs fid_cnt funs_cnt' funs' lindefs' linrefs' in mkCncCats cdefs fid_cnt funs_cnt' funs' lindefs' linrefs'
mkCncCats (_ :cdefs) fid_cnt funs_cnt funs lindefs linrefs = mkCncCats (_ :cdefs) fid_cnt funs_cnt funs lindefs linrefs =
mkCncCats cdefs fid_cnt funs_cnt funs lindefs linrefs mkCncCats cdefs fid_cnt funs_cnt funs lindefs linrefs
mkCncFuns [] fid_cnt funs_cnt funs lindefs crc prods = mkCncFuns [] fid_cnt funs_cnt funs lindefs crc prods =
(fid_cnt,funs_cnt,funs,prods) (fid_cnt,funs_cnt,funs,prods)
mkCncFuns (((m,id),CncFun _ _ _ (Just (PMCFG prods0 funs0))):cdefs) fid_cnt funs_cnt funs lindefs crc prods = mkCncFuns (((m,id),CncFun _ _ _ (Just (PMCFG prods0 funs0))):cdefs) fid_cnt funs_cnt funs lindefs crc prods =
let ty_C = err error (\x -> x) $ fmap GM.typeForm (Look.lookupFunType gr am id) let ---Ok ty_C = fmap GM.typeForm (Look.lookupFunType gr am id)
ty_C = err error (\x -> x) $ fmap GM.typeForm (Look.lookupFunType gr am id)
!funs_cnt' = let (s_funid, e_funid) = bounds funs0 !funs_cnt' = let (s_funid, e_funid) = bounds funs0
in funs_cnt+(e_funid-s_funid+1) in funs_cnt+(e_funid-s_funid+1)
!(fid_cnt',crc',prods') !(fid_cnt',crc',prods')
@@ -251,23 +228,23 @@ genCncFuns gr am cm ex_seqs ciCmp seqs cdefs fid_cnt cnccat_ranges =
mkCncFuns (_ :cdefs) fid_cnt funs_cnt funs lindefs crc prods = mkCncFuns (_ :cdefs) fid_cnt funs_cnt funs lindefs crc prods =
mkCncFuns cdefs fid_cnt funs_cnt funs lindefs crc prods mkCncFuns cdefs fid_cnt funs_cnt funs lindefs crc prods
toProd lindefs (ctxt_C,res_C,_) offs st (A.Production fid0 funid0 args0) = toProd lindefs (ctxt_C,res_C,_) offs st (Production fid0 funid0 args0) =
let !((fid_cnt,crc,prods),args) = mapAccumL mkArg st (zip ctxt_C args0) let !((fid_cnt,crc,prods),args) = mapAccumL mkArg st (zip ctxt_C args0)
set0 = Set.fromList (map (PApply (offs+funid0)) (sequence args)) set0 = Set.fromList (map (C.PApply (offs+funid0)) (sequence args))
fid = mkFId res_C fid0 fid = mkFId res_C fid0
!prods' = case IntMap.lookup fid prods of !prods' = case IntMap.lookup fid prods of
Just set -> IntMap.insert fid (Set.union set0 set) prods Just set -> IntMap.insert fid (Set.union set0 set) prods
Nothing -> IntMap.insert fid set0 prods Nothing -> IntMap.insert fid set0 prods
in (fid_cnt,crc,prods') in (fid_cnt,crc,prods')
where where
mkArg st@(fid_cnt,crc,prods) ((_,_,ty),fid0s) = mkArg st@(fid_cnt,crc,prods) ((_,_,ty),fid0s ) =
case fid0s of case fid0s of
[fid0] -> (st,map (flip PArg (mkFId arg_C fid0)) ctxt) [fid0] -> (st,map (flip C.PArg (mkFId arg_C fid0)) ctxt)
fid0s -> case Map.lookup fids crc of fid0s -> case Map.lookup fids crc of
Just fid -> (st,map (flip PArg fid) ctxt) Just fid -> (st,map (flip C.PArg fid) ctxt)
Nothing -> let !crc' = Map.insert fids fid_cnt crc Nothing -> let !crc' = Map.insert fids fid_cnt crc
!prods' = IntMap.insert fid_cnt (Set.fromList (map PCoerce fids)) prods !prods' = IntMap.insert fid_cnt (Set.fromList (map C.PCoerce fids)) prods
in ((fid_cnt+1,crc',prods'),map (flip PArg fid_cnt) ctxt) in ((fid_cnt+1,crc',prods'),map (flip C.PArg fid_cnt) ctxt)
where where
(hargs_C,arg_C) = GM.catSkeleton ty (hargs_C,arg_C) = GM.catSkeleton ty
ctxt = mapM (mkCtxt lindefs) hargs_C ctxt = mapM (mkCtxt lindefs) hargs_C
@@ -275,14 +252,14 @@ genCncFuns gr am cm ex_seqs ciCmp seqs cdefs fid_cnt cnccat_ranges =
mkLinDefId id = prefixIdent "lindef " id mkLinDefId id = prefixIdent "lindef " id
toLinDef res offs lindefs (A.Production fid0 funid0 args) = toLinDef res offs lindefs (Production fid0 funid0 args) =
if args == [[fidVar]] if args == [[fidVar]]
then IntMap.insertWith (++) fid [offs+funid0] lindefs then IntMap.insertWith (++) fid [offs+funid0] lindefs
else lindefs else lindefs
where where
fid = mkFId res fid0 fid = mkFId res fid0
toLinRef res offs linrefs (A.Production fid0 funid0 [fargs]) = toLinRef res offs linrefs (Production fid0 funid0 [fargs]) =
if fid0 == fidVar if fid0 == fidVar
then foldr (\fid -> IntMap.insertWith (++) fid [offs+funid0]) linrefs fids then foldr (\fid -> IntMap.insertWith (++) fid [offs+funid0]) linrefs fids
else linrefs else linrefs
@@ -290,20 +267,20 @@ genCncFuns gr am cm ex_seqs ciCmp seqs cdefs fid_cnt cnccat_ranges =
fids = map (mkFId res) fargs fids = map (mkFId res) fargs
mkFId (_,cat) fid0 = mkFId (_,cat) fid0 =
case Map.lookup (i2i cat) cnccat_ranges of case Map.lookup (i2i cat) cnccats of
Just (s,e) -> s+fid0 Just (C.CncCat s e _) -> s+fid0
Nothing -> error ("GrammarToPGF.mkFId: missing category "++showIdent cat) Nothing -> error ("GrammarToPGF.mkFId: missing category "++showIdent cat)
mkCtxt lindefs (_,cat) = mkCtxt lindefs (_,cat) =
case Map.lookup (i2i cat) cnccat_ranges of case Map.lookup (i2i cat) cnccats of
Just (s,e) -> [(fid,fid) | fid <- [s..e], Just _ <- [IntMap.lookup fid lindefs]] Just (C.CncCat s e _) -> [(C.fidVar,fid) | fid <- [s..e], Just _ <- [IntMap.lookup fid lindefs]]
Nothing -> error "GrammarToPGF.mkCtxt failed" Nothing -> error "GrammarToPGF.mkCtxt failed"
toCncFun offs (m,id) funs (funid0,lins0) = toCncFun offs (m,id) funs (funid0,lins0) =
let mseqs = case lookupModule gr m of let mseqs = case lookupModule gr m of
Ok (ModInfo{mseqs=Just mseqs}) -> mseqs Ok (ModInfo{mseqs=Just mseqs}) -> mseqs
_ -> ex_seqs _ -> ex_seqs
in (i2i id, map (newIndex mseqs) (elems lins0)):funs in (offs+funid0,C.CncFun (i2i id) (amap (newIndex mseqs) lins0)):funs
where where
newIndex mseqs i = binSearch (mseqs ! i) seqs (bounds seqs) newIndex mseqs i = binSearch (mseqs ! i) seqs (bounds seqs)
@@ -316,9 +293,8 @@ genCncFuns gr am cm ex_seqs ciCmp seqs cdefs fid_cnt cnccat_ranges =
where where
k = (i+j) `div` 2 k = (i+j) `div` 2
genPrintNames cdefs = genPrintNames cdefs =
[(i2i id, name) | ((m,id),info) <- cdefs, name <- prn info] Map.fromAscList [(i2i id, name) | ((m,id),info) <- cdefs, name <- prn info]
where where
prn (CncFun _ _ (Just (L _ tr)) _) = [flatten tr] prn (CncFun _ _ (Just (L _ tr)) _) = [flatten tr]
prn (CncCat _ _ _ (Just (L _ tr)) _) = [flatten tr] prn (CncCat _ _ _ (Just (L _ tr)) _) = [flatten tr]
@@ -330,118 +306,3 @@ genPrintNames cdefs =
mkArray lst = listArray (0,length lst-1) lst mkArray lst = listArray (0,length lst-1) lst
mkMapArray map = array (0,Map.size map-1) [(v,k) | (k,v) <- Map.toList map] mkMapArray map = array (0,Map.size map-1) [(v,k) | (k,v) <- Map.toList map]
mkSetArray set = listArray (0,Set.size set-1) (Set.toList set)
-- The following is a version of Data.List.sortBy which together
-- with the sorting also eliminates duplicate values
sortNubBy cmp = mergeAll . sequences
where
sequences (a:b:xs) =
case cmp a b of
GT -> descending b [a] xs
EQ -> sequences (b:xs)
LT -> ascending b (a:) xs
sequences xs = [xs]
descending a as [] = [a:as]
descending a as (b:bs) =
case cmp a b of
GT -> descending b (a:as) bs
EQ -> descending a as bs
LT -> (a:as) : sequences (b:bs)
ascending a as [] = let !x = as [a]
in [x]
ascending a as (b:bs) =
case cmp a b of
GT -> let !x = as [a]
in x : sequences (b:bs)
EQ -> ascending a as bs
LT -> ascending b (\ys -> as (a:ys)) bs
mergeAll [x] = x
mergeAll xs = mergeAll (mergePairs xs)
mergePairs (a:b:xs) = let !x = merge a b
in x : mergePairs xs
mergePairs xs = xs
merge as@(a:as') bs@(b:bs') =
case cmp a b of
GT -> b:merge as bs'
EQ -> a:merge as' bs'
LT -> a:merge as' bs
merge [] bs = bs
merge as [] = as
-- The following function does case-insensitive comparison of sequences.
-- This is used to allow case-insensitive parsing, while
-- the linearizer still has access to the original cases.
compareCaseInsensitive [] [] = EQ
compareCaseInsensitive [] _ = LT
compareCaseInsensitive _ [] = GT
compareCaseInsensitive (x:xs) (y:ys) =
case compareSym x y of
EQ -> compareCaseInsensitive xs ys
x -> x
where
compareSym s1 s2 =
case s1 of
SymCat d1 r1
-> case s2 of
SymCat d2 r2
-> case compare d1 d2 of
EQ -> r1 `compare` r2
x -> x
_ -> LT
SymLit d1 r1
-> case s2 of
SymCat {} -> GT
SymLit d2 r2
-> case compare d1 d2 of
EQ -> r1 `compare` r2
x -> x
_ -> LT
SymVar d1 r1
-> if tagToEnum# (getTag s2 ># 2#)
then LT
else case s2 of
SymVar d2 r2
-> case compare d1 d2 of
EQ -> r1 `compare` r2
x -> x
_ -> GT
SymKS t1
-> if tagToEnum# (getTag s2 ># 3#)
then LT
else case s2 of
SymKS t2 -> t1 `compareToken` t2
_ -> GT
SymKP a1 b1
-> if tagToEnum# (getTag s2 ># 4#)
then LT
else case s2 of
SymKP a2 b2
-> case compare a1 a2 of
EQ -> b1 `compare` b2
x -> x
_ -> GT
_ -> let t1 = getTag s1
t2 = getTag s2
in if tagToEnum# (t1 <# t2)
then LT
else if tagToEnum# (t1 ==# t2)
then EQ
else GT
compareToken [] [] = EQ
compareToken [] _ = LT
compareToken _ [] = GT
compareToken (x:xs) (y:ys)
| x == y = compareToken xs ys
| otherwise = case compare (toLower x) (toLower y) of
EQ -> case compareToken xs ys of
EQ -> compare x y
x -> x
x -> x

View File

@@ -1,189 +0,0 @@
{-# LANGUAGE BangPatterns #-}
module GF.Compile.OptimizePGF(optimizePGF) where
import PGF2(Cat,Fun)
import PGF2.Internal
import Data.Array.ST
import Data.Array.Unboxed
import qualified Data.Map as Map
import qualified Data.Set as Set
import qualified Data.IntSet as IntSet
import qualified Data.IntMap as IntMap
import qualified Data.List as List
import Control.Monad.ST
type ConcrData = ([(FId,[FunId])], -- ^ Lindefs
[(FId,[FunId])], -- ^ Linrefs
[(FId,[Production])], -- ^ Productions
[(Fun,[SeqId])], -- ^ Concrete functions (must be sorted by Fun)
[[Symbol]], -- ^ Sequences (must be sorted)
[(Cat,FId,FId,[String])]) -- ^ Concrete categories
optimizePGF :: Cat -> ConcrData -> ConcrData
optimizePGF startCat = topDownFilter startCat . bottomUpFilter
catString = "String"
catInt = "Int"
catFloat = "Float"
catVar = "__gfVar"
topDownFilter :: Cat -> ConcrData -> ConcrData
topDownFilter startCat (lindefs,linrefs,prods,cncfuns,sequences,cnccats) =
let env0 = (Map.empty,Map.empty)
(env1,lindefs') = List.mapAccumL (\env (fid,funids) -> let (env',funids') = List.mapAccumL (optimizeFun fid [PArg [] fidVar]) env funids in (env',(fid,funids')))
env0
lindefs
(env2,linrefs') = List.mapAccumL (\env (fid,funids) -> let (env',funids') = List.mapAccumL (optimizeFun fidVar [PArg [] fid]) env funids in (env',(fid,funids')))
env1
linrefs
(env3,prods') = List.mapAccumL (\env (fid,set) -> let (env',set') = List.mapAccumL (optimizeProd fid) env set in (env',(fid,set')))
env2
prods
cnccats' = map filterCatLabels cnccats
(sequences',cncfuns') = env3
in (lindefs',linrefs',prods',mkSetArray cncfuns',mkSetArray sequences',cnccats')
where
cncfuns_array = listArray (0,length cncfuns-1) cncfuns :: Array FunId (Fun, [SeqId])
sequences_array = listArray (0,length sequences-1) sequences :: Array SeqId [Symbol]
prods_map = IntMap.fromList prods
fid2catMap = IntMap.fromList ((fidVar,catVar) : [(fid,cat) | (cat,start,end,lbls) <- cnccats,
fid <- [start..end]])
fid2cat fid =
case IntMap.lookup fid fid2catMap of
Just cat -> cat
Nothing -> case [fid | Just set <- [IntMap.lookup fid prods_map], PCoerce fid <- set] of
(fid:_) -> fid2cat fid
_ -> error "unknown forest id"
starts =
[(startCat,lbl) | (cat,_,_,lbls) <- cnccats, cat==startCat, lbl <- [0..length lbls-1]]
allRelations =
Map.unionsWith Set.union
[rel fid prod | (fid,set) <- prods, prod <- set]
where
rel fid (PApply funid args) = Map.fromList [((fid2cat fid,lbl),deps args seqid) | (lbl,seqid) <- zip [0..] lin]
where
(_,lin) = cncfuns_array ! funid
rel fid _ = Map.empty
deps args seqid = Set.fromList [let PArg _ fid = args !! r in (fid2cat fid,d) | SymCat r d <- seq]
where
seq = sequences_array ! seqid
-- here we create a mapping from a category to an array of indices.
-- An element of the array is equal to -1 if the corresponding index
-- is not going to be used in the optimized grammar, or the new index
-- if it will be used
closure :: Map.Map Cat [Int]
closure = runST $ do
set <- initSet
addLitCat catString set
addLitCat catInt set
addLitCat catFloat set
addLitCat catVar set
closureSet set starts
doneSet set
where
initSet :: ST s (Map.Map Cat (STUArray s Int Int))
initSet =
fmap Map.fromList $ sequence
[fmap ((,) cat) (newArray (0,length lbls-1) (-1))
| (cat,_,_,lbls) <- cnccats]
addLitCat cat set =
case Map.lookup cat set of
Just indices -> writeArray indices 0 0
Nothing -> return ()
closureSet set [] = return ()
closureSet set (x@(cat,index):xs) =
case Map.lookup cat set of
Just indices -> do v <- readArray indices index
writeArray indices index 0
if v < 0
then case Map.lookup x allRelations of
Just ys -> closureSet set (Set.toList ys++xs)
Nothing -> closureSet set xs
else closureSet set xs
Nothing -> error "unknown cat"
doneSet :: Map.Map Cat (STUArray s Int Int) -> ST s (Map.Map Cat [Int])
doneSet set =
fmap Map.fromAscList $ mapM done (Map.toAscList set)
where
done (cat,indices) = do
indices <- fmap (reindex 0) (getElems indices)
return (cat,indices)
reindex k [] = []
reindex k (v:vs)
| v < 0 = v : reindex k vs
| otherwise = k : reindex (k+1) vs
optimizeProd res env (PApply funid args) =
let (env',funid') = optimizeFun res args env funid
in (env', PApply funid' args)
optimizeProd res env prod = (env,prod)
optimizeFun res args (seqs,funs) funid =
let (seqs',lin') = List.mapAccumL addUnique seqs [map updateSymbol (sequences_array ! seqid) |
(idx,seqid) <- zip (indicesOf res) lin, idx >= 0]
(funs',funid') = addUnique funs (fun, lin')
in ((seqs',funs'), funid')
where
(fun,lin) = cncfuns_array ! funid
indicesOf fid
| fid < 0 = [0]
| otherwise =
case Map.lookup (fid2cat fid) closure of
Just indices -> indices
Nothing -> error "unknown category"
addUnique seqs seq =
case Map.lookup seq seqs of
Just seqid -> (seqs,seqid)
Nothing -> let seqid = Map.size seqs
in (Map.insert seq seqid seqs, seqid)
updateSymbol (SymCat r d) = let PArg _ fid = args !! r in SymCat r (indicesOf fid !! d)
updateSymbol s = s
filterCatLabels (cat,start,end,lbls) =
case Map.lookup cat closure of
Just indices -> let lbls' = [lbl | (idx,lbl) <- zip indices lbls, idx >= 0]
in (cat,start,end,lbls')
Nothing -> error ("unknown category")
mkSetArray map = sortSnd (Map.toList map)
where
sortSnd = List.map fst . List.sortBy (\(_,i) (_,j) -> compare i j)
bottomUpFilter :: ConcrData -> ConcrData
bottomUpFilter (lindefs,linrefs,prods,cncfuns,sequences,cnccats) =
(lindefs,linrefs,filterProductions IntMap.empty IntSet.empty prods,cncfuns,sequences,cnccats)
filterProductions prods0 hoc0 prods
| prods0 == prods1 = IntMap.toList prods0
| otherwise = filterProductions prods1 hoc1 prods
where
(prods1,hoc1) = foldl foldProdSet (IntMap.empty,IntSet.empty) prods
foldProdSet (!prods,!hoc) (fid,set)
| null set1 = (prods,hoc)
| otherwise = (IntMap.insert fid set1 prods,hoc1)
where
set1 = filter filterRule set
hoc1 = foldl accumHOC hoc set1
filterRule (PApply funid args) = all (\(PArg _ fid) -> isLive fid) args
filterRule (PCoerce fid) = isLive fid
filterRule _ = True
isLive fid = isPredefFId fid || IntMap.member fid prods0 || IntSet.member fid hoc0
accumHOC hoc (PApply funid args) = List.foldl' (\hoc (PArg hypos _) -> List.foldl' (\hoc fid -> IntSet.insert fid hoc) hoc (map snd hypos)) hoc args
accumHOC hoc _ = hoc

View File

@@ -16,17 +16,17 @@
module GF.Compile.PGFtoHaskell (grammar2haskell) where module GF.Compile.PGFtoHaskell (grammar2haskell) where
import PGF2 import PGF(showCId)
import PGF2.Internal import PGF.Internal
import GF.Data.Operations import GF.Data.Operations
import GF.Infra.Option import GF.Infra.Option
import Data.List import Data.List --(isPrefixOf, find, intersperse)
import Data.Maybe(mapMaybe)
import qualified Data.Map as Map import qualified Data.Map as Map
type Prefix = String -> String type Prefix = String -> String
type DerivingClause = String
-- | the main function -- | the main function
grammar2haskell :: Options grammar2haskell :: Options
@@ -34,29 +34,36 @@ 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 ++
[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
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 #-}"] -- 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 = []
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 gadt name derivingClause extraImports =
[ [
"module " ++ name ++ " where", "module " ++ name ++ " where",
"" ""
] ++ ] ++ extraImports ++ [
(if gadt then [
"import Control.Monad.Identity",
"import Data.Monoid"
] else []) ++
[
"import PGF hiding (Tree)", "import PGF hiding (Tree)",
"----------------------------------------------------", "----------------------------------------------------",
"-- automatic translation from GF to Haskell", "-- automatic translation from GF to Haskell",
@@ -66,11 +73,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",
@@ -78,10 +85,10 @@ haskPreamble gadt name =
"" ""
] ]
predefInst gadt gtyp typ destr consr = 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" ++++
@@ -95,24 +102,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 []
@@ -242,7 +249,7 @@ fInstance gId lexical m (cat,rules) =
then " " ++ gId cat ++ " (fgs t) where\n fgs t = case unApp t of" then " " ++ gId cat ++ " (fgs t) where\n fgs t = case unApp t of"
else " case unApp t of") ++++ else " case unApp t of") ++++
unlines [mkInst f xx | (f,xx) <- nonLexicalRules (lexical cat) rules] ++++ unlines [mkInst f xx | (f,xx) <- nonLexicalRules (lexical cat) rules] ++++
(if lexical cat then " Just (i,[]) -> " ++ lexicalConstructor cat +++ "i" else "") ++++ (if lexical cat then " Just (i,[]) -> " ++ lexicalConstructor cat +++ "(showCId i)" else "") ++++
" _ -> error (\"no" +++ cat ++ " \" ++ show t)" " _ -> error (\"no" +++ cat ++ " \" ++ show t)"
where where
isList = isListCat (cat,rules) isList = isListCat (cat,rules)
@@ -263,21 +270,18 @@ fInstance gId lexical m (cat,rules) =
--type HSkeleton = [(OIdent, [(OIdent, [OIdent])])] --type HSkeleton = [(OIdent, [(OIdent, [OIdent])])]
hSkeleton :: PGF -> (String,HSkeleton) hSkeleton :: PGF -> (String,HSkeleton)
hSkeleton gr = hSkeleton gr =
(abstractName gr, (showCId (absname gr),
let fs = let fs =
[(c, [(f, cs) | (f, cs,_) <- fs]) | [(showCId c, [(showCId f, map showCId cs) | (f, (cs,_)) <- fs]) |
fs@((_, _,c):_) <- fns] fs@((_, (_,c)):_) <- fns]
in fs ++ [(c, []) | c <- cts, notElem c (["Int", "Float", "String"] ++ map fst fs)] in fs ++ [(sc, []) | c <- cts, let sc = showCId c, notElem sc (["Int", "Float", "String"] ++ map fst fs)]
) )
where where
cts = categories gr cts = Map.keys (cats (abstract gr))
fns = groupBy valtypg (sortBy valtyps (mapMaybe jty (functions gr))) fns = groupBy valtypg (sortBy valtyps (map jty (Map.assocs (funs (abstract gr)))))
valtyps (_,_,x) (_,_,y) = compare x y valtyps (_, (_,x)) (_, (_,y)) = compare x y
valtypg (_,_,x) (_,_,y) = x == y valtypg (_, (_,x)) (_, (_,y)) = x == y
jty f = case functionType gr f of jty (f,(ty,_,_,_)) = (f,catSkeleton ty)
Just ty -> let (hypos,valcat,_) = unType ty
in Just (f,[argcat | (_,_,ty) <- hypos, let (_,argcat,_) = unType ty],valcat)
Nothing -> Nothing
{- {-
updateSkeleton :: OIdent -> HSkeleton -> (OIdent, [OIdent]) -> HSkeleton updateSkeleton :: OIdent -> HSkeleton -> (OIdent, [OIdent]) -> HSkeleton
updateSkeleton cat skel rule = updateSkeleton cat skel rule =

View File

@@ -0,0 +1,105 @@
module GF.Compile.PGFtoJS (pgf2js) where
import PGF(showCId)
import PGF.Internal as M
import qualified GF.JavaScript.AbsJS as JS
import qualified GF.JavaScript.PrintJS as JS
--import GF.Data.ErrM
--import GF.Infra.Option
--import Control.Monad (mplus)
--import Data.Array.Unboxed (UArray)
import qualified Data.Array.IArray as Array
--import Data.Maybe (fromMaybe)
import Data.Map (Map)
import qualified Data.Set as Set
import qualified Data.Map as Map
import qualified Data.IntMap as IntMap
pgf2js :: PGF -> String
pgf2js pgf =
JS.printTree $ JS.Program [JS.ElStmt $ JS.SDeclOrExpr $ JS.Decl [JS.DInit (JS.Ident n) grammar]]
where
n = showCId $ absname pgf
as = abstract pgf
cs = Map.assocs (concretes pgf)
start = showCId $ M.lookStartCat pgf
grammar = new "GFGrammar" [js_abstract, js_concrete]
js_abstract = abstract2js start as
js_concrete = JS.EObj $ map concrete2js cs
abstract2js :: String -> Abstr -> JS.Expr
abstract2js start ds = new "GFAbstract" [JS.EStr start, JS.EObj $ map absdef2js (Map.assocs (funs ds))]
absdef2js :: (CId,(Type,Int,Maybe ([Equation],[[M.Instr]]),Double)) -> JS.Property
absdef2js (f,(typ,_,_,_)) =
let (args,cat) = M.catSkeleton typ in
JS.Prop (JS.IdentPropName (JS.Ident (showCId f))) (new "Type" [JS.EArray [JS.EStr (showCId x) | x <- args], JS.EStr (showCId cat)])
lit2js (LStr s) = JS.EStr s
lit2js (LInt n) = JS.EInt n
lit2js (LFlt d) = JS.EDbl d
concrete2js :: (CId,Concr) -> JS.Property
concrete2js (c,cnc) =
JS.Prop l (new "GFConcrete" [mapToJSObj (lit2js) $ cflags cnc,
JS.EObj $ [JS.Prop (JS.IntPropName cat) (JS.EArray (map frule2js (Set.toList set))) | (cat,set) <- IntMap.toList (productions cnc)],
JS.EArray $ (map ffun2js (Array.elems (cncfuns cnc))),
JS.EArray $ (map seq2js (Array.elems (sequences cnc))),
JS.EObj $ map cats (Map.assocs (cnccats cnc)),
JS.EInt (totalCats cnc)])
where
l = JS.IdentPropName (JS.Ident (showCId c))
{-
litslins = [JS.Prop (JS.StringPropName "Int") (JS.EFun [children] [JS.SReturn $ new "Arr" [JS.EIndex (JS.EVar children) (JS.EInt 0)]]),
JS.Prop (JS.StringPropName "Float") (JS.EFun [children] [JS.SReturn $ new "Arr" [JS.EIndex (JS.EVar children) (JS.EInt 0)]]),
JS.Prop (JS.StringPropName "String") (JS.EFun [children] [JS.SReturn $ new "Arr" [JS.EIndex (JS.EVar children) (JS.EInt 0)]])]
-}
cats (c,CncCat start end _) = JS.Prop (JS.IdentPropName (JS.Ident (showCId c))) (JS.EObj [JS.Prop (JS.IdentPropName (JS.Ident "s")) (JS.EInt start)
,JS.Prop (JS.IdentPropName (JS.Ident "e")) (JS.EInt end)])
{-
mkStr :: String -> JS.Expr
mkStr s = new "Str" [JS.EStr s]
mkSeq :: [JS.Expr] -> JS.Expr
mkSeq [x] = x
mkSeq xs = new "Seq" xs
argIdent :: Integer -> JS.Ident
argIdent n = JS.Ident ("x" ++ show n)
-}
children :: JS.Ident
children = JS.Ident "cs"
frule2js :: Production -> JS.Expr
frule2js (PApply funid args) = new "Apply" [JS.EInt funid, JS.EArray (map farg2js args)]
frule2js (PCoerce arg) = new "Coerce" [JS.EInt arg]
farg2js (PArg hypos fid) = new "PArg" (map (JS.EInt . snd) hypos ++ [JS.EInt fid])
ffun2js (CncFun f lins) = new "CncFun" [JS.EStr (showCId f), JS.EArray (map JS.EInt (Array.elems lins))]
seq2js :: Array.Array DotPos Symbol -> JS.Expr
seq2js seq = JS.EArray [sym2js s | s <- Array.elems seq]
sym2js :: Symbol -> JS.Expr
sym2js (SymCat n l) = new "SymCat" [JS.EInt n, JS.EInt l]
sym2js (SymLit n l) = new "SymLit" [JS.EInt n, JS.EInt l]
sym2js (SymVar n l) = new "SymVar" [JS.EInt n, JS.EInt l]
sym2js (SymKS t) = new "SymKS" [JS.EStr t]
sym2js (SymKP ts alts) = new "SymKP" [JS.EArray (map sym2js ts), JS.EArray (map alt2js alts)]
sym2js SymBIND = new "SymKS" [JS.EStr "&+"]
sym2js SymSOFT_BIND = new "SymKS" [JS.EStr "&+"]
sym2js SymSOFT_SPACE = new "SymKS" [JS.EStr "&+"]
sym2js SymCAPIT = new "SymKS" [JS.EStr "&|"]
sym2js SymALL_CAPIT = new "SymKS" [JS.EStr "&|"]
sym2js SymNE = new "SymNE" []
alt2js (ps,ts) = new "Alt" [JS.EArray (map sym2js ps), JS.EArray (map JS.EStr ts)]
new :: String -> [JS.Expr] -> JS.Expr
new f xs = JS.ENew (JS.Ident f) xs
mapToJSObj :: (a -> JS.Expr) -> Map CId a -> JS.Expr
mapToJSObj f m = JS.EObj [ JS.Prop (JS.IdentPropName (JS.Ident (showCId k))) (f v) | (k,v) <- Map.toList m ]

View File

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

View File

@@ -1,6 +1,6 @@
module GF.Compile.PGFtoJava (grammar2java) where module GF.Compile.PGFtoJava (grammar2java) where
import PGF2 import PGF
import Data.Maybe(maybe) import Data.Maybe(maybe)
import Data.List(intercalate) import Data.List(intercalate)
import GF.Infra.Option import GF.Infra.Option
@@ -24,8 +24,9 @@ javaPreamble name =
] ]
javaMethod gr fun = javaMethod gr fun =
" public static Expr "++fun++"("++arg_decls++") { return new Expr("++show fun++args++"); }" " public static Expr "++name++"("++arg_decls++") { return new Expr("++show name++args++"); }"
where where
name = showCId fun
arity = maybe 0 getArrity (functionType gr fun) arity = maybe 0 getArrity (functionType gr fun)
vars = ['e':show i | i <- [1..arity]] vars = ['e':show i | i <- [1..arity]]

View File

@@ -0,0 +1,262 @@
----------------------------------------------------------------------
-- |
-- Module : PGFtoProlog
-- Maintainer : Peter Ljunglöf
--
-- exports a GF grammar into a Prolog module
-----------------------------------------------------------------------------
module GF.Compile.PGFtoProlog (grammar2prolog) where
import PGF(mkCId,wildCId,showCId)
import PGF.Internal
--import PGF.Macros
import GF.Data.Operations
import qualified Data.Array.IArray as Array
import qualified Data.Set as Set
import qualified Data.Map as Map
import qualified Data.IntMap as IntMap
import Data.Char (isAlphaNum, isAscii, isAsciiLower, isAsciiUpper, ord)
import Data.List (isPrefixOf, mapAccumL)
grammar2prolog :: PGF -> String
grammar2prolog pgf
= ("%% This file was automatically generated by GF" +++++
":- style_check(-singleton)." +++++
plFacts wildCId "abstract" 1 "(?AbstractName)"
[[plp name]] ++++
plFacts wildCId "concrete" 2 "(?AbstractName, ?ConcreteName)"
[[plp name, plp cncname] |
cncname <- Map.keys (concretes pgf)] ++++
plFacts wildCId "flag" 2 "(?Flag, ?Value): global flags"
[[plp f, plp v] |
(f, v) <- Map.assocs (gflags pgf)] ++++
plAbstract name (abstract pgf) ++++
unlines (map plConcrete (Map.assocs (concretes pgf)))
)
where name = absname pgf
----------------------------------------------------------------------
-- abstract syntax
plAbstract :: CId -> Abstr -> String
plAbstract name abs
= (plHeader "Abstract syntax" ++++
plFacts name "flag" 2 "(?Flag, ?Value): flags for abstract syntax"
[[plp f, plp v] |
(f, v) <- Map.assocs (aflags abs)] ++++
plFacts name "cat" 2 "(?Type, ?[X:Type,...])"
[[plType cat args, plHypos hypos'] |
(cat, (hypos,_,_)) <- Map.assocs (cats abs),
let ((_, subst), hypos') = mapAccumL alphaConvertHypo emptyEnv hypos,
let args = reverse [EFun x | (_,x) <- subst]] ++++
plFacts name "fun" 3 "(?Fun, ?Type, ?[X:Type,...])"
[[plp fun, plType cat args, plHypos hypos] |
(fun, (typ, _, _, _)) <- Map.assocs (funs abs),
let (_, DTyp hypos cat args) = alphaConvert emptyEnv typ] ++++
plFacts name "def" 2 "(?Fun, ?Expr)"
[[plp fun, plp expr] |
(fun, (_, _, Just (eqs,_), _)) <- Map.assocs (funs abs),
let (_, expr) = alphaConvert emptyEnv eqs]
)
where plType cat args = plTerm (plp cat) (map plp args)
plHypos hypos = plList [plOper ":" (plp x) (plp ty) | (_, x, ty) <- hypos]
----------------------------------------------------------------------
-- concrete syntax
plConcrete :: (CId, Concr) -> String
plConcrete (name, cnc)
= (plHeader ("Concrete syntax: " ++ plp name) ++++
plFacts name "flag" 2 "(?Flag, ?Value): flags for concrete syntax"
[[plp f, plp v] |
(f, v) <- Map.assocs (cflags cnc)] ++++
plFacts name "printname" 2 "(?AbsFun/AbsCat, ?Atom)"
[[plp f, plp n] |
(f, n) <- Map.assocs (printnames cnc)] ++++
plFacts name "lindef" 2 "(?CncCat, ?CncFun)"
[[plCat cat, plFun fun] |
(cat, funs) <- IntMap.assocs (lindefs cnc),
fun <- funs] ++++
plFacts name "prod" 3 "(?CncCat, ?CncFun, ?[CncCat])"
[[plCat cat, fun, plTerm "c" (map plCat args)] |
(cat, set) <- IntMap.toList (productions cnc),
(fun, args) <- map plProduction (Set.toList set)] ++++
plFacts name "cncfun" 3 "(?CncFun, ?[Seq,...], ?AbsFun)"
[[plFun fun, plTerm "s" (map plSeq (Array.elems lins)), plp absfun] |
(fun, CncFun absfun lins) <- Array.assocs (cncfuns cnc)] ++++
plFacts name "seq" 2 "(?Seq, ?[Term])"
[[plSeq seq, plp (Array.elems symbols)] |
(seq, symbols) <- Array.assocs (sequences cnc)] ++++
plFacts name "cnccat" 2 "(?AbsCat, ?[CnCCat])"
[[plp cat, plList (map plCat [start..end])] |
(cat, CncCat start end _) <- Map.assocs (cnccats cnc)]
)
where plProduction (PCoerce arg) = ("-", [arg])
plProduction (PApply funid args) = (plFun funid, [fid | PArg hypos fid <- args])
----------------------------------------------------------------------
-- prolog-printing pgf datatypes
instance PLPrint Type where
plp (DTyp hypos cat args)
| null hypos = result
| otherwise = plOper " -> " plHypos result
where result = plTerm (plp cat) (map plp args)
plHypos = plList [plOper ":" (plp x) (plp ty) | (_,x,ty) <- hypos]
instance PLPrint Expr where
plp (EFun x) = plp x
plp (EAbs _ x e)= plOper "^" (plp x) (plp e)
plp (EApp e e') = plOper " * " (plp e) (plp e')
plp (ELit lit) = plp lit
plp (EMeta n) = "Meta_" ++ show n
instance PLPrint Patt where
plp (PVar x) = plp x
plp (PApp f ps) = plOper " * " (plp f) (plp ps)
plp (PLit lit) = plp lit
instance PLPrint Equation where
plp (Equ patterns result) = plOper ":" (plp patterns) (plp result)
instance PLPrint CId where
plp cid | isLogicalVariable str || cid == wildCId = plVar str
| otherwise = plAtom str
where str = showCId cid
instance PLPrint Literal where
plp (LStr s) = plp s
plp (LInt n) = plp (show n)
plp (LFlt f) = plp (show f)
instance PLPrint Symbol where
plp (SymCat n l) = plOper ":" (show n) (show l)
plp (SymLit n l) = plTerm "lit" [show n, show l]
plp (SymVar n l) = plTerm "var" [show n, show l]
plp (SymKS t) = plAtom t
plp (SymKP ts alts) = plTerm "pre" [plList (map plp ts), plList (map plAlt alts)]
where plAlt (ps,ts) = plOper "/" (plList (map plp ps)) (plList (map plAtom ts))
class PLPrint a where
plp :: a -> String
plps :: [a] -> String
plps = plList . map plp
instance PLPrint Char where
plp c = plAtom [c]
plps s = plAtom s
instance PLPrint a => PLPrint [a] where
plp = plps
----------------------------------------------------------------------
-- other prolog-printing functions
plCat :: Int -> String
plCat n = plAtom ('c' : show n)
plFun :: Int -> String
plFun n = plAtom ('f' : show n)
plSeq :: Int -> String
plSeq n = plAtom ('s' : show n)
plHeader :: String -> String
plHeader hdr = "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n%% " ++ hdr ++ "\n"
plFacts :: CId -> String -> Int -> String -> [[String]] -> String
plFacts mod pred arity comment facts = "%% " ++ pred ++ comment ++++ clauses
where clauses = (if facts == [] then ":- dynamic " ++ pred ++ "/" ++ show arity ++ ".\n"
else unlines [mod' ++ plTerm pred args ++ "." | args <- facts])
mod' = if mod == wildCId then "" else plp mod ++ ": "
plTerm :: String -> [String] -> String
plTerm fun args = plAtom fun ++ prParenth (prTList ", " args)
plList :: [String] -> String
plList xs = prBracket (prTList "," xs)
plOper :: String -> String -> String -> String
plOper op a b = prParenth (a ++ op ++ b)
plVar :: String -> String
plVar = varPrefix . concatMap changeNonAlphaNum
where varPrefix var@(c:_) | isAsciiUpper c || c=='_' = var
| otherwise = "_" ++ var
changeNonAlphaNum c | isAlphaNumUnderscore c = [c]
| otherwise = "_" ++ show (ord c) ++ "_"
plAtom :: String -> String
plAtom "" = "''"
plAtom atom@(c:cs) | isAsciiLower c && all isAlphaNumUnderscore cs
|| c == '\'' && cs /= "" && last cs == '\'' = atom
| otherwise = "'" ++ changeQuote atom ++ "'"
where changeQuote ('\'':cs) = '\\' : '\'' : changeQuote cs
changeQuote ('\\':cs) = '\\' : '\\' : changeQuote cs
changeQuote (c:cs) = c : changeQuote cs
changeQuote "" = ""
isAlphaNumUnderscore :: Char -> Bool
isAlphaNumUnderscore c = (isAscii c && isAlphaNum c) || c == '_'
----------------------------------------------------------------------
-- prolog variables
createLogicalVariable :: Int -> CId
createLogicalVariable n = mkCId (logicalVariablePrefix ++ show n)
isLogicalVariable :: String -> Bool
isLogicalVariable = isPrefixOf logicalVariablePrefix
logicalVariablePrefix :: String
logicalVariablePrefix = "X"
----------------------------------------------------------------------
-- alpha convert variables to (unique) logical variables
-- * this is needed if we want to translate variables to Prolog variables
-- * used for abstract syntax, not concrete
-- * not (yet?) used for variables bound in pattern equations
type ConvertEnv = (Int, [(CId,CId)])
emptyEnv :: ConvertEnv
emptyEnv = (0, [])
class AlphaConvert a where
alphaConvert :: ConvertEnv -> a -> (ConvertEnv, a)
instance AlphaConvert a => AlphaConvert [a] where
alphaConvert env [] = (env, [])
alphaConvert env (a:as) = (env'', a':as')
where (env', a') = alphaConvert env a
(env'', as') = alphaConvert env' as
instance AlphaConvert Type where
alphaConvert env@(_,subst) (DTyp hypos cat args)
= ((ctr,subst), DTyp hypos' cat args')
where (env', hypos') = mapAccumL alphaConvertHypo env hypos
((ctr,_), args') = alphaConvert env' args
alphaConvertHypo env (b,x,typ) = ((ctr+1,(x,x'):subst), (b,x',typ'))
where ((ctr,subst), typ') = alphaConvert env typ
x' = createLogicalVariable ctr
instance AlphaConvert Expr where
alphaConvert (ctr,subst) (EAbs b x e) = ((ctr',subst), EAbs b x' e')
where ((ctr',_), e') = alphaConvert (ctr+1,(x,x'):subst) e
x' = createLogicalVariable ctr
alphaConvert env (EApp e1 e2) = (env'', EApp e1' e2')
where (env', e1') = alphaConvert env e1
(env'', e2') = alphaConvert env' e2
alphaConvert env expr@(EFun i) = (env, maybe expr EFun (lookup i (snd env)))
alphaConvert env expr = (env, expr)
-- pattern variables are not alpha converted
-- (but they probably should be...)
instance AlphaConvert Equation where
alphaConvert env@(_,subst) (Equ patterns result)
= ((ctr,subst), Equ patterns result')
where ((ctr,_), result') = alphaConvert env result

View File

@@ -0,0 +1,122 @@
----------------------------------------------------------------------
-- |
-- Module : PGFtoPython
-- Maintainer : Peter Ljunglöf
--
-- exports a GF grammar into a Python module
-----------------------------------------------------------------------------
{-# LANGUAGE FlexibleContexts #-}
module GF.Compile.PGFtoPython (pgf2python) where
import PGF(showCId)
import PGF.Internal as M
import GF.Data.Operations
import qualified Data.Array.IArray as Array
import qualified Data.Set as Set
import qualified Data.Map as Map
import qualified Data.IntMap as IntMap
--import Data.List (intersperse)
pgf2python :: PGF -> String
pgf2python pgf = ("# -*- coding: utf-8 -*-" ++++
"# This file was automatically generated by GF" +++++
showCId name +++ "=" +++
pyDict 1 pyStr id [
("flags", pyDict 2 pyCId pyLiteral (Map.assocs (gflags pgf))),
("abstract", pyDict 2 pyStr id [
("name", pyCId name),
("start", pyCId start),
("flags", pyDict 3 pyCId pyLiteral (Map.assocs (aflags abs))),
("funs", pyDict 3 pyCId pyAbsdef (Map.assocs (funs abs)))
]),
("concretes", pyDict 2 pyCId pyConcrete (Map.assocs cncs))
] ++ "\n")
where
name = absname pgf
start = M.lookStartCat pgf
abs = abstract pgf
cncs = concretes pgf
pyAbsdef :: (Type, Int, Maybe ([Equation], [[M.Instr]]), Double) -> String
pyAbsdef (typ, _, _, _) = pyTuple 0 id [pyCId cat, pyList 0 pyCId args]
where (args, cat) = M.catSkeleton typ
pyLiteral :: Literal -> String
pyLiteral (LStr s) = pyStr s
pyLiteral (LInt n) = show n
pyLiteral (LFlt d) = show d
pyConcrete :: Concr -> String
pyConcrete cnc = pyDict 3 pyStr id [
("flags", pyDict 0 pyCId pyLiteral (Map.assocs (cflags cnc))),
("printnames", pyDict 4 pyCId pyStr (Map.assocs (printnames cnc))),
("lindefs", pyDict 4 pyCat (pyList 0 pyFun) (IntMap.assocs (lindefs cnc))),
("productions", pyDict 4 pyCat pyProds (IntMap.assocs (productions cnc))),
("cncfuns", pyDict 4 pyFun pyCncFun (Array.assocs (cncfuns cnc))),
("sequences", pyDict 4 pySeq pySymbols (Array.assocs (sequences cnc))),
("cnccats", pyDict 4 pyCId pyCncCat (Map.assocs (cnccats cnc))),
("size", show (totalCats cnc))
]
where pyProds prods = pyList 5 pyProduction (Set.toList prods)
pyCncCat (CncCat start end _) = pyList 0 pyCat [start..end]
pyCncFun (CncFun f lins) = pyTuple 0 id [pyList 0 pySeq (Array.elems lins), pyCId f]
pySymbols syms = pyList 0 pySymbol (Array.elems syms)
pyProduction :: Production -> String
pyProduction (PCoerce arg) = pyTuple 0 id [pyStr "", pyList 0 pyCat [arg]]
pyProduction (PApply funid args) = pyTuple 0 id [pyFun funid, pyList 0 pyPArg args]
where pyPArg (PArg [] fid) = pyCat fid
pyPArg (PArg hypos fid) = pyTuple 0 pyCat (fid : map snd hypos)
pySymbol :: Symbol -> String
pySymbol (SymCat n l) = pyTuple 0 show [n, l]
pySymbol (SymLit n l) = pyDict 0 pyStr id [("lit", pyTuple 0 show [n, l])]
pySymbol (SymVar n l) = pyDict 0 pyStr id [("var", pyTuple 0 show [n, l])]
pySymbol (SymKS t) = pyStr t
pySymbol (SymKP ts alts) = pyDict 0 pyStr id [("pre", pyList 0 pySymbol ts), ("alts", pyList 0 alt2py alts)]
where alt2py (ps,ts) = pyTuple 0 (pyList 0 pyStr) [map pySymbol ps, ts]
pySymbol SymBIND = pyStr "&+"
pySymbol SymSOFT_BIND = pyStr "&+"
pySymbol SymSOFT_SPACE = pyStr "&+"
pySymbol SymCAPIT = pyStr "&|"
pySymbol SymALL_CAPIT = pyStr "&|"
pySymbol SymNE = pyDict 0 pyStr id [("nonExist", pyTuple 0 id [])]
----------------------------------------------------------------------
-- python helpers
pyDict :: Int -> (k -> String) -> (v -> String) -> [(k, v)] -> String
pyDict n pk pv [] = "{}"
pyDict n pk pv kvlist = prCurly (pyIndent n ++ prTList ("," ++ pyIndent n) (map pyKV kvlist) ++ pyIndent n)
where pyKV (k, v) = pk k ++ ":" ++ pv v
pyList :: Int -> (v -> String) -> [v] -> String
pyList n pv [] = "[]"
pyList n pv xs = prBracket (pyIndent n ++ prTList ("," ++ pyIndent n) (map pv xs) ++ pyIndent n)
pyTuple :: Int -> (v -> String) -> [v] -> String
pyTuple n pv [] = "()"
pyTuple n pv [x] = prParenth (pyIndent n ++ pv x ++ "," ++ pyIndent n)
pyTuple n pv xs = prParenth (pyIndent n ++ prTList ("," ++ pyIndent n) (map pv xs) ++ pyIndent n)
pyCat :: Int -> String
pyCat n = pyStr ('C' : show n)
pyFun :: Int -> String
pyFun n = pyStr ('F' : show n)
pySeq :: Int -> String
pySeq n = pyStr ('S' : show n)
pyStr :: String -> String
pyStr s = 'u' : prQuotedString s
pyCId :: CId -> String
pyCId = pyStr . showCId
pyIndent :: Int -> String
pyIndent n | n > 0 = "\n" ++ replicate n ' '
| otherwise = ""

View File

@@ -110,7 +110,7 @@ renameIdentTerm' env@(act,imps) t0 =
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
AbsFun _ _ Nothing _ -> maybe Con (curry QC) mq AbsFun _ _ Nothing _ -> maybe Con (curry QC) mq
ResValue _ _ -> maybe Con (curry QC) mq ResValue _ -> maybe Con (curry QC) mq
ResParam _ _ -> maybe Con (curry QC) mq ResParam _ _ -> maybe Con (curry QC) mq
AnyInd True m -> maybe Con (const (curry QC m)) mq AnyInd True m -> maybe Con (const (curry QC m)) mq
AnyInd False m -> maybe Cn (const (curry Q m)) mq AnyInd False m -> maybe Cn (const (curry Q m)) mq
@@ -148,9 +148,9 @@ renameInfo cwd status (m,mi) i info =
ResParam (Just pp) m -> do ResParam (Just pp) m -> do
pp' <- renLoc (mapM (renParam status)) pp pp' <- renLoc (mapM (renParam status)) pp
return (ResParam (Just pp') m) return (ResParam (Just pp') m)
ResValue ty offset -> do ResValue t -> do
t <- renLoc (renameTerm status []) ty t <- renLoc (renameTerm status []) t
return (ResValue ty offset) return (ResValue t)
CncCat mcat mdef mref mpr mpmcfg -> liftM5 CncCat (renTerm mcat) (renTerm mdef) (renTerm mref) (renTerm mpr) (return mpmcfg) CncCat mcat mdef mref mpr mpmcfg -> liftM5 CncCat (renTerm mcat) (renTerm mdef) (renTerm mref) (renTerm mpr) (return mpmcfg)
CncFun mty mtr mpr mpmcfg -> liftM3 (CncFun mty) (renTerm mtr) (renTerm mpr) (return mpmcfg) CncFun mty mtr mpr mpmcfg -> liftM3 (CncFun mty) (renTerm mtr) (renTerm mpr) (return mpmcfg)
_ -> return info _ -> return info
@@ -178,9 +178,9 @@ renameInfo cwd status (m,mi) i info =
return (ps',t') return (ps',t')
renParam :: Status -> Param -> Check Param renParam :: Status -> Param -> Check Param
renParam env (c,co,i) = do renParam env (c,co) = do
co' <- renameContext env co co' <- renameContext env co
return (c,co',i) return (c,co')
renameTerm :: Status -> [Ident] -> Term -> Check Term renameTerm :: Status -> [Ident] -> Term -> Check Term
renameTerm env vars = ren vars where renameTerm env vars = ren vars where
@@ -236,7 +236,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

View File

@@ -31,7 +31,7 @@ getLocalTags x (m,mi) =
getLocations (AbsFun mb_type _ mb_eqs _) = maybe (ltype "fun") mb_type ++ getLocations (AbsFun mb_type _ mb_eqs _) = maybe (ltype "fun") mb_type ++
maybe (list (loc "def")) mb_eqs maybe (list (loc "def")) mb_eqs
getLocations (ResParam mb_params _) = maybe (loc "param") mb_params getLocations (ResParam mb_params _) = maybe (loc "param") mb_params
getLocations (ResValue mb_type _) = ltype "param-value" mb_type getLocations (ResValue mb_type) = ltype "param-value" mb_type
getLocations (ResOper mb_type mb_def) = maybe (ltype "oper-type") mb_type ++ getLocations (ResOper mb_type mb_def) = maybe (ltype "oper-type") mb_type ++
maybe (loc "oper-def") mb_def maybe (loc "oper-def") mb_def
getLocations (ResOverload _ defs) = list (\(x,y) -> ltype "overload-type" x ++ getLocations (ResOverload _ defs) = list (\(x,y) -> ltype "overload-type" x ++

View File

@@ -2,7 +2,8 @@ module GF.Compile.ToAPI
(stringToAPI,exprToAPI) (stringToAPI,exprToAPI)
where where
import PGF2 import PGF.Internal
import PGF(showCId)
import Data.Maybe import Data.Maybe
--import System.IO --import System.IO
--import Control.Monad --import Control.Monad
@@ -46,12 +47,12 @@ exprToFunc :: Expr -> APIfunc
exprToFunc expr = exprToFunc expr =
case unApp expr of case unApp expr of
Just (cid,l) -> Just (cid,l) ->
case Map.lookup cid syntaxFuncs of case Map.lookup (showCId cid) syntaxFuncs of
Just sig -> mkAPI True (fst sig,expr) Just sig -> mkAPI True (fst sig,expr)
_ -> case l of _ -> case l of
[] -> BasicFunc cid [] -> BasicFunc (showCId cid)
_ -> let es = map exprToFunc l _ -> let es = map exprToFunc l
in AppFunc cid es in AppFunc (showCId cid) es
_ -> BasicFunc (showExpr [] expr) _ -> BasicFunc (showExpr [] expr)
@@ -68,8 +69,8 @@ mkAPI opt (ty,expr) =
where where
rephraseSentence ty expr = rephraseSentence ty expr =
case unApp expr of case unApp expr of
Just (cid,es) -> if isPrefixOf "Use" cid then Just (cid,es) -> if isPrefixOf "Use" (showCId cid) then
let newCat = drop 3 cid let newCat = drop 3 (showCId cid)
afClause = mkAPI True (newCat, es !! 2) afClause = mkAPI True (newCat, es !! 2)
afPol = mkAPI True ("Pol",es !! 1) afPol = mkAPI True ("Pol",es !! 1)
lTense = mkAPI True ("Temp", head es) lTense = mkAPI True ("Temp", head es)
@@ -97,9 +98,9 @@ mkAPI opt (ty,expr) =
computeAPI :: (String,Expr) -> APIfunc computeAPI :: (String,Expr) -> APIfunc
computeAPI (ty,expr) = computeAPI (ty,expr) =
case (unApp expr) of case (unApp expr) of
Just (cid,[]) -> getSimpCat cid ty Just (cid,[]) -> getSimpCat (showCId cid) ty
Just (cid,es) -> Just (cid,es) ->
let p = specFunction cid es let p = specFunction (showCId cid) es
in if isJust p then fromJust p in if isJust p then fromJust p
else case Map.lookup (show cid) syntaxFuncs of else case Map.lookup (show cid) syntaxFuncs of
Nothing -> exprToFunc expr Nothing -> exprToFunc expr
@@ -146,23 +147,23 @@ optimize expr = optimizeNP expr
optimizeNP expr = optimizeNP expr =
case unApp expr of case unApp expr of
Just (cid,es) -> Just (cid,es) ->
if cid == "MassNP" then let afs = nounAsCN (head es) if showCId cid == "MassNP" then let afs = nounAsCN (head es)
in AppFunc "mkNP" [afs] in AppFunc "mkNP" [afs]
else if cid == "DetCN" then let quants = quantAsDet (head es) else if showCId cid == "DetCN" then let quants = quantAsDet (head es)
ns = nounAsCN (head $ tail es) ns = nounAsCN (head $ tail es)
in AppFunc "mkNP" (quants ++ [ns]) in AppFunc "mkNP" (quants ++ [ns])
else mkAPI False ("NP",expr) else mkAPI False ("NP",expr)
_ -> error $ "incorrect expression " ++ (showExpr [] expr) _ -> error $ "incorrect expression " ++ (showExpr [] expr)
where where
nounAsCN expr = nounAsCN expr =
case unApp expr of case unApp expr of
Just (cid,es) -> if cid == "UseN" then (mkAPI False) ("N",head es) Just (cid,es) -> if showCId cid == "UseN" then (mkAPI False) ("N",head es)
else (mkAPI False) ("CN",expr) else (mkAPI False) ("CN",expr)
_ -> error $ "incorrect expression "++ (showExpr [] expr) _ -> error $ "incorrect expression "++ (showExpr [] expr)
quantAsDet expr = quantAsDet expr =
case unApp expr of case unApp expr of
Just (cid,es) -> if cid == "DetQuant" then map (mkAPI False) [("Quant", head es),("Num",head $ tail es)] Just (cid,es) -> if showCId cid == "DetQuant" then map (mkAPI False) [("Quant", head es),("Num",head $ tail es)]
else [mkAPI False ("Det",expr)] else [mkAPI False ("Det",expr)]
_ -> error $ "incorrect expression "++ (showExpr [] expr) _ -> error $ "incorrect expression "++ (showExpr [] expr)

View File

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

View File

@@ -8,7 +8,7 @@ typPredefined :: Ident -> Maybe Type
typPredefined f = case Map.lookup f primitives of typPredefined f = case Map.lookup f primitives of
Just (ResOper (Just (L _ ty)) _) -> Just ty Just (ResOper (Just (L _ ty)) _) -> Just ty
Just (ResParam _ _) -> Just typePType Just (ResParam _ _) -> Just typePType
Just (ResValue (L _ ty) _) -> Just ty Just (ResValue (L _ ty)) -> Just ty
_ -> Nothing _ -> Nothing
primitives = Map.fromList primitives = Map.fromList
@@ -16,9 +16,9 @@ primitives = Map.fromList
, (cInt , ResOper (Just (noLoc typePType)) Nothing) , (cInt , ResOper (Just (noLoc typePType)) Nothing)
, (cFloat , ResOper (Just (noLoc typePType)) Nothing) , (cFloat , ResOper (Just (noLoc typePType)) Nothing)
, (cInts , fun [typeInt] typePType) , (cInts , fun [typeInt] typePType)
, (cPBool , ResParam (Just (noLoc [(cPTrue,[],0),(cPFalse,[],1)])) (Just [QC (cPredef,cPTrue), QC (cPredef,cPFalse)])) , (cPBool , ResParam (Just (noLoc [(cPTrue,[]),(cPFalse,[])])) (Just [QC (cPredef,cPTrue), QC (cPredef,cPFalse)]))
, (cPTrue , ResValue (noLoc typePBool) 0) , (cPTrue , ResValue (noLoc typePBool))
, (cPFalse , ResValue (noLoc typePBool) 1) , (cPFalse , ResValue (noLoc typePBool))
, (cError , fun [typeStr] typeError) -- non-can. of empty set , (cError , fun [typeStr] typeError) -- non-can. of empty set
, (cLength , fun [typeTok] typeInt) , (cLength , fun [typeTok] typeInt)
, (cDrop , fun [typeInt,typeTok] typeTok) , (cDrop , fun [typeInt,typeTok] typeTok)

View File

@@ -1,5 +1,6 @@
{-# LANGUAGE PatternGuards #-} {-# LANGUAGE PatternGuards #-}
module GF.Compile.TypeCheck.RConcrete( checkLType, inferLType, computeLType, ppType ) where 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.Infra.CheckM
import GF.Data.Operations import GF.Data.Operations
@@ -127,7 +128,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 ("A function type is expected for" <+> ppTerm Unqualified 0 f <+> "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
@@ -219,8 +224,14 @@ 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
@@ -394,7 +405,7 @@ getOverload gr g mt ot = case appForm ot of
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
@@ -427,7 +438,9 @@ checkLType gr g trm typ0 = do
else do b' <- checkIn (pp "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' z a b') return $ (Abs bt x c', Prod bt' z a b')
_ -> checkError $ "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
@@ -505,8 +518,13 @@ checkLType gr g trm typ0 = do
RecType ss -> return $ map fst ss RecType ss -> return $ map fst ss
_ -> checkError ("cannot get labels from" $$ nest 2 (ppTerm Unqualified 0 typ2)) _ -> checkError ("cannot get labels from" $$ nest 2 (ppTerm Unqualified 0 typ2))
let ll1 = [l | (l,_) <- rr, notElem l ll2] 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]) --- 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]) let rec = R ([(l,(Nothing,P r' l)) | l <- ll1] ++ [(l,(Nothing,P s' l)) | l <- ll2])
return (rec, typ) return (rec, typ)
@@ -637,9 +655,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 $ s <+> "type of" <+> ppTerm Unqualified 0 trm $$ False ->
"expected:" <+> ppTerm Qualified 0 t $$ -- ppqType t u $$ let inferredType = ppTerm Qualified 0 u
"inferred:" <+> ppTerm Qualified 0 u -- ppqType u t 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

View File

@@ -27,9 +27,10 @@ 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
@@ -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
@@ -166,7 +168,7 @@ extendMod gr isCompl ((name,mi),cond) base new = foldM try new $ Map.toList (jme
indirInfo :: ModuleName -> Info -> Info indirInfo :: ModuleName -> Info -> Info
indirInfo n info = AnyInd b n' where indirInfo n info = AnyInd b n' where
(b,n') = case info of (b,n') = case info of
ResValue _ _ -> (True,n) ResValue _ -> (True,n)
ResParam _ _ -> (True,n) ResParam _ _ -> (True,n)
AbsFun _ _ Nothing _ -> (True,n) AbsFun _ _ Nothing _ -> (True,n)
AnyInd b k -> (b,k) AnyInd b k -> (b,k)
@@ -177,7 +179,7 @@ globalizeLoc fpath i =
AbsCat mc -> AbsCat (fmap gl mc) AbsCat mc -> AbsCat (fmap gl mc)
AbsFun mt ma md moper -> AbsFun (fmap gl mt) ma (fmap (fmap gl) md) moper AbsFun mt ma md moper -> AbsFun (fmap gl mt) ma (fmap (fmap gl) md) moper
ResParam mt mv -> ResParam (fmap gl mt) mv ResParam mt mv -> ResParam (fmap gl mt) mv
ResValue t offset -> ResValue (gl t) offset ResValue t -> ResValue (gl t)
ResOper mt m -> ResOper (fmap gl mt) (fmap gl m) ResOper mt m -> ResOper (fmap gl mt) (fmap gl m)
ResOverload ms os -> ResOverload ms (map (\(x,y) -> (gl x,gl y)) os) ResOverload ms os -> ResOverload ms (map (\(x,y) -> (gl x,gl y)) os)
CncCat mc md mr mp mpmcfg-> CncCat (fmap gl mc) (fmap gl md) (fmap gl mr) (fmap gl mp) mpmcfg CncCat mc md mr mp mpmcfg-> CncCat (fmap gl mc) (fmap gl md) (fmap gl mr) (fmap gl mp) mpmcfg
@@ -199,9 +201,9 @@ unifyAnyInfo m i j = case (i,j) of
(ResParam mt1 mv1, ResParam mt2 mv2) -> (ResParam mt1 mv1, ResParam mt2 mv2) ->
liftM2 ResParam (unifyMaybeL mt1 mt2) (unifyMaybe mv1 mv2) liftM2 ResParam (unifyMaybeL mt1 mt2) (unifyMaybe mv1 mv2)
(ResValue (L l1 t1) i1, ResValue (L l2 t2) i2) (ResValue (L l1 t1), ResValue (L l2 t2))
| t1==t2 && i1 == i2 -> return (ResValue (L l1 t1) i1) | t1==t2 -> return (ResValue (L l1 t1))
| otherwise -> fail "" | otherwise -> fail ""
(_, ResOverload ms t) | elem m ms -> (_, ResOverload ms t) | elem m ms ->
return $ ResOverload ms t return $ ResOverload ms t
(ResOper mt1 m1, ResOper mt2 m2) -> (ResOper mt1 m1, ResOper mt2 m2) ->

View File

@@ -1,6 +1,6 @@
-- | Parallel grammar compilation -- | Parallel grammar compilation
module GF.CompileInParallel(parallelBatchCompile) where module GF.CompileInParallel(parallelBatchCompile) where
import Prelude hiding (catch) import Prelude hiding (catch,(<>)) -- GHC 8.4.1 clash with Text.PrettyPrint
import Control.Monad(join,ap,when,unless) import Control.Monad(join,ap,when,unless)
import Control.Applicative import Control.Applicative
import GF.Infra.Concurrency import GF.Infra.Concurrency
@@ -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.
@@ -34,8 +36,11 @@ import qualified Data.ByteString.Lazy as BS
parallelBatchCompile jobs opts rootfiles0 = parallelBatchCompile jobs opts rootfiles0 =
do setJobs jobs do setJobs jobs
rootfiles <- mapM canonical rootfiles0 rootfiles <- mapM canonical rootfiles0
lib_dir <- canonical =<< getLibraryDirectory opts lib_dirs1 <- getLibraryDirectory opts
filepaths <- mapM (getPathFromFile lib_dir opts) rootfiles lib_dirs2 <- mapM canonical lib_dirs1
let lib_dir = head lib_dirs2
when (length lib_dirs2 >1) $ ePutStrLn ("GF_LIB_PATH defines more than one directory; using the first, " ++ show lib_dir)
filepaths <- mapM (getPathFromFile [lib_dir] opts) rootfiles
let groups = groupFiles lib_dir filepaths let groups = groupFiles lib_dir filepaths
n = length groups n = length groups
when (n>1) $ ePutStrLn "Grammar mixes present and alltenses, dividing modules into two groups" when (n>1) $ ePutStrLn "Grammar mixes present and alltenses, dividing modules into two groups"
@@ -80,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)
@@ -238,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,()))
@@ -253,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)

View File

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

View File

@@ -1,8 +1,11 @@
module GF.Compiler (mainGFC, linkGrammars, writeGrammar, writeOutputs) where module GF.Compiler (mainGFC, linkGrammars, writePGF, writeLPGF, writeOutputs) where
import PGF2 import PGF
import PGF2.Internal(unionPGF,writePGF,writeConcr) import PGF.Internal(concretes,optimizePGF,unionPGF)
import GF.Compile as S(batchCompile,link,srcAbsName) import PGF.Internal(putSplitAbs,encodeFile,runPut)
import LPGF(LPGF)
import qualified LPGF
import GF.Compile as S(batchCompile,link,linkl,srcAbsName)
import GF.CompileInParallel as P(parallelBatchCompile) import GF.CompileInParallel as P(parallelBatchCompile)
import GF.Compile.Export import GF.Compile.Export
import GF.Compile.ConcreteToHaskell(concretes2haskell) import GF.Compile.ConcreteToHaskell(concretes2haskell)
@@ -10,7 +13,8 @@ import GF.Compile.GrammarToCanonical--(concretes2canonical)
import GF.Compile.CFGtoPGF import GF.Compile.CFGtoPGF
import GF.Compile.GetGrammar import GF.Compile.GetGrammar
import GF.Grammar.BNFC import GF.Grammar.BNFC
import GF.Grammar.CFG import GF.Grammar.CFG hiding (Grammar)
import GF.Grammar.Grammar (Grammar, ModuleName)
--import GF.Infra.Ident(showIdent) --import GF.Infra.Ident(showIdent)
import GF.Infra.UseIO import GF.Infra.UseIO
@@ -22,10 +26,11 @@ import GF.Text.Pretty(render,render80)
import Data.Maybe import Data.Maybe
import qualified Data.Map as Map import qualified Data.Map as Map
import qualified Data.Set as Set import qualified Data.Set as Set
import Data.Time(UTCTime)
import qualified Data.ByteString.Lazy as BSL import qualified Data.ByteString.Lazy as BSL
import GF.Grammar.CanonicalJSON (encodeJSON) import GF.Grammar.CanonicalJSON (encodeJSON)
import System.FilePath import System.FilePath
import Control.Monad(when,unless,forM_) import Control.Monad(when,unless,forM,void)
-- | Compile the given GF grammar files. The result is a number of @.gfo@ files -- | Compile the given GF grammar files. The result is a number of @.gfo@ files
-- and, depending on the options, a @.pgf@ file. (@gf -batch@, @gf -make@) -- and, depending on the options, a @.pgf@ file. (@gf -batch@, @gf -make@)
@@ -91,7 +96,11 @@ compileSourceFiles opts fs =
-- in the 'Options') from the output of 'parallelBatchCompile'. -- in the 'Options') from the output of 'parallelBatchCompile'.
-- If a @.pgf@ file by the same name already exists and it is newer than the -- If a @.pgf@ file by the same name already exists and it is newer than the
-- source grammar files (as indicated by the 'UTCTime' argument), it is not -- source grammar files (as indicated by the 'UTCTime' argument), it is not
-- recreated. Calls 'writeGrammar' and 'writeOutputs'. -- recreated. Calls 'writePGF' and 'writeOutputs'.
linkGrammars :: Options -> (UTCTime,[(ModuleName, Grammar)]) -> IOE ()
linkGrammars opts (_,cnc_grs) | FmtLPGF `elem` flag optOutputFormats opts = do
lpgf <- linkl opts (head cnc_grs)
void $ writeLPGF opts lpgf
linkGrammars opts (t_src,~cnc_grs@(~(cnc,gr):_)) = linkGrammars opts (t_src,~cnc_grs@(~(cnc,gr):_)) =
do let abs = render (srcAbsName gr cnc) do let abs = render (srcAbsName gr cnc)
pgfFile = outputPath opts (grammarName' opts abs<.>"pgf") pgfFile = outputPath opts (grammarName' opts abs<.>"pgf")
@@ -101,8 +110,10 @@ linkGrammars opts (t_src,~cnc_grs@(~(cnc,gr):_)) =
if t_pgf >= Just t_src if t_pgf >= Just t_src
then putIfVerb opts $ pgfFile ++ " is up-to-date." then putIfVerb opts $ pgfFile ++ " is up-to-date."
else do pgfs <- mapM (link opts) cnc_grs else do pgfs <- mapM (link opts) cnc_grs
let pgf = foldl1 (\one two -> fromMaybe two (unionPGF one two)) pgfs let pgf0 = foldl1 unionPGF pgfs
writeGrammar opts pgf probs <- maybe (return . defaultProbabilities) readProbabilitiesFromFile (flag optProbsFile opts) pgf0
let pgf = setProbabilities probs pgf0
writePGF opts pgf
writeOutputs opts pgf writeOutputs opts pgf
compileCFFiles :: Options -> [FilePath] -> IOE () compileCFFiles :: Options -> [FilePath] -> IOE ()
@@ -112,11 +123,12 @@ compileCFFiles opts fs = do
startCat <- case rules of startCat <- case rules of
(Rule cat _ _ : _) -> return cat (Rule cat _ _ : _) -> return cat
_ -> fail "empty CFG" _ -> fail "empty CFG"
probs <- liftIO (maybe (return Map.empty) readProbabilitiesFromFile (flag optProbsFile opts)) let pgf = cf2pgf (last fs) (mkCFG startCat Set.empty rules)
let pgf = cf2pgf opts (last fs) (mkCFG startCat Set.empty rules) probs
unless (flag optStopAfterPhase opts == Compile) $ unless (flag optStopAfterPhase opts == Compile) $
do writeGrammar opts pgf do probs <- liftIO (maybe (return . defaultProbabilities) readProbabilitiesFromFile (flag optProbsFile opts) pgf)
writeOutputs opts pgf let pgf' = setProbabilities probs $ if flag optOptimizePGF opts then optimizePGF pgf else pgf
writePGF opts pgf'
writeOutputs opts pgf'
unionPGFFiles :: Options -> [FilePath] -> IOE () unionPGFFiles :: Options -> [FilePath] -> IOE ()
unionPGFFiles opts fs = unionPGFFiles opts fs =
@@ -134,11 +146,14 @@ unionPGFFiles opts fs =
doIt = doIt =
do pgfs <- mapM readPGFVerbose fs do pgfs <- mapM readPGFVerbose fs
let pgf = foldl1 (\one two -> fromMaybe two (unionPGF one two)) pgfs let pgf0 = foldl1 unionPGF pgfs
let pgfFile = outputPath opts (grammarName opts pgf <.> "pgf") pgf1 = if flag optOptimizePGF opts then optimizePGF pgf0 else pgf0
probs <- liftIO (maybe (return . defaultProbabilities) readProbabilitiesFromFile (flag optProbsFile opts) pgf1)
let pgf = setProbabilities probs pgf1
pgfFile = outputPath opts (grammarName opts pgf <.> "pgf")
if pgfFile `elem` fs if pgfFile `elem` fs
then putStrLnE $ "Refusing to overwrite " ++ pgfFile then putStrLnE $ "Refusing to overwrite " ++ pgfFile
else writeGrammar opts pgf else void $ writePGF opts pgf
writeOutputs opts pgf writeOutputs opts pgf
readPGFVerbose f = readPGFVerbose f =
@@ -155,30 +170,44 @@ writeOutputs opts pgf = do
-- | Write the result of compiling a grammar (e.g. with 'compileToPGF' or -- | Write the result of compiling a grammar (e.g. with 'compileToPGF' or
-- 'link') to a @.pgf@ file. -- 'link') to a @.pgf@ file.
-- A split PGF file is output if the @-split-pgf@ option is used. -- A split PGF file is output if the @-split-pgf@ option is used.
writeGrammar :: Options -> PGF -> IOE () writePGF :: Options -> PGF -> IOE [FilePath]
writeGrammar opts pgf = writePGF opts pgf =
if flag optSplitPGF opts then writeSplitPGF else writeNormalPGF if flag optSplitPGF opts then writeSplitPGF else writeNormalPGF
where where
writeNormalPGF = writeNormalPGF =
do let outfile = outputPath opts (grammarName opts pgf <.> "pgf") do let outfile = outputPath opts (grammarName opts pgf <.> "pgf")
writing opts outfile (writePGF outfile pgf) writing opts outfile $ encodeFile outfile pgf
return [outfile]
writeSplitPGF = writeSplitPGF =
do let outfile = outputPath opts (grammarName opts pgf <.> "pgf") do let outfile = outputPath opts (grammarName opts pgf <.> "pgf")
writing opts outfile $ writePGF outfile pgf writing opts outfile $ BSL.writeFile outfile (runPut (putSplitAbs pgf))
forM_ (Map.toList (languages pgf)) $ \(concrname,concr) -> do --encodeFile_ outfile (putSplitAbs pgf)
let outfile = outputPath opts (concrname <.> "pgf_c") outfiles <- forM (Map.toList (concretes pgf)) $ \cnc -> do
writing opts outfile (writeConcr outfile concr) let outfile = outputPath opts (showCId (fst cnc) <.> "pgf_c")
writing opts outfile $ encodeFile outfile cnc
return outfile
return (outfile:outfiles)
writeOutput :: Options -> FilePath-> String -> IOE () writeLPGF :: Options -> LPGF -> IOE FilePath
writeOutput opts file str = writing opts path $ writeUTF8File path str writeLPGF opts lpgf = do
where path = outputPath opts file let
grammarName = fromMaybe (showCId (LPGF.abstractName lpgf)) (flag optName opts)
outfile = outputPath opts (grammarName <.> "lpgf")
writing opts outfile $ liftIO $ LPGF.encodeFile outfile lpgf
return outfile
writeOutput :: Options -> FilePath-> String -> IOE FilePath
writeOutput opts file str = do
let outfile = outputPath opts file
writing opts outfile $ writeUTF8File outfile str
return outfile
-- * Useful helper functions -- * Useful helper functions
grammarName :: Options -> PGF -> String grammarName :: Options -> PGF -> String
grammarName opts pgf = grammarName' opts (abstractName pgf) grammarName opts pgf = grammarName' opts (showCId (abstractName pgf))
grammarName' opts abs = fromMaybe abs (flag optName opts) grammarName' opts abs = fromMaybe abs (flag optName opts)
outputJustPGF opts = null (flag optOutputFormats opts) && not (flag optSplitPGF opts) outputJustPGF opts = null (flag optOutputFormats opts) && not (flag optSplitPGF opts)

View File

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

View File

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

View File

@@ -0,0 +1,57 @@
-- | In order to build an IntMap in one pass, we need a map data structure with
-- fast lookup in both keys and values.
-- This is achieved by keeping a separate reversed map of values to keys during building.
module GF.Data.IntMapBuilder where
import Data.IntMap (IntMap)
import qualified Data.IntMap as IntMap
import Data.Hashable (Hashable)
import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as HashMap
import Data.Tuple (swap)
import Prelude hiding (lookup)
data IMB a = IMB {
intMap :: IntMap a,
valMap :: HashMap a Int
}
-- | An empty IMB
empty :: (Eq a, Hashable a) => IMB a
empty = IMB {
intMap = IntMap.empty,
valMap = HashMap.empty
}
-- | Lookup a value
lookup :: (Eq a, Hashable a) => a -> IMB a -> Maybe Int
lookup a IMB { valMap = vm } = HashMap.lookup a vm
-- | Insert without any lookup
insert :: (Eq a, Hashable a) => a -> IMB a -> (Int, IMB a)
insert a IMB { intMap = im, valMap = vm } =
let
ix = IntMap.size im
im' = IntMap.insert ix a im
vm' = HashMap.insert a ix vm
imb' = IMB { intMap = im', valMap = vm' }
in
(ix, imb')
-- | Insert only when lookup fails
insert' :: (Eq a, Hashable a) => a -> IMB a -> (Int, IMB a)
insert' a imb =
case lookup a imb of
Just ix -> (ix, imb)
Nothing -> insert a imb
-- | Build IMB from existing IntMap
fromIntMap :: (Eq a, Hashable a) => IntMap a -> IMB a
fromIntMap im = IMB {
intMap = im,
valMap = HashMap.fromList (map swap (IntMap.toList im))
}
-- | Get IntMap from IMB
toIntMap :: (Eq a, Hashable a) => IMB a -> IntMap a
toIntMap = intMap

View File

@@ -26,8 +26,8 @@ module GF.Data.Operations (
-- ** Checking -- ** Checking
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

View File

@@ -29,7 +29,7 @@ stripInfo i = case i of
AbsCat _ -> i AbsCat _ -> i
AbsFun mt mi me mb -> AbsFun mt mi Nothing mb AbsFun mt mi me mb -> AbsFun mt mi Nothing mb
ResParam mp mt -> ResParam mp Nothing ResParam mp mt -> ResParam mp Nothing
ResValue _ lt -> i ---- ResValue lt -> i ----
ResOper mt md -> ResOper mt Nothing ResOper mt md -> ResOper mt Nothing
ResOverload is fs -> ResOverload is [(lty, L loc (EInt 0)) | (lty,L loc _) <- fs] ResOverload is fs -> ResOverload is [(lty, L loc (EInt 0)) | (lty,L loc _) <- fs]
CncCat mty mte _ mtf mpmcfg -> CncCat mty Nothing Nothing Nothing Nothing CncCat mty mte _ mtf mpmcfg -> CncCat mty Nothing Nothing Nothing Nothing
@@ -107,8 +107,8 @@ sizeInfo i = case i of
AbsFun mt mi me mb -> 1 + msize mt + AbsFun mt mi me mb -> 1 + msize mt +
sum [sum (map (sizeTerm . patt2term) ps) + sizeTerm t | Just es <- [me], L _ (ps,t) <- es] sum [sum (map (sizeTerm . patt2term) ps) + sizeTerm t | Just es <- [me], L _ (ps,t) <- es]
ResParam mp mt -> ResParam mp mt ->
1 + sum [1 + sum [1 + sizeTerm ty | (_,_,ty) <- co] | Just (L _ ps) <- [mp], (_,co,_) <- ps] 1 + sum [1 + sum [1 + sizeTerm ty | (_,_,ty) <- co] | Just (L _ ps) <- [mp], (_,co) <- ps]
ResValue _ lt -> 0 ResValue lt -> 0
ResOper mt md -> 1 + msize mt + msize md ResOper mt md -> 1 + msize mt + msize md
ResOverload is fs -> 1 + sum [sizeTerm ty + sizeTerm tr | (L _ ty, L _ tr) <- fs] ResOverload is fs -> 1 + sum [sizeTerm ty + sizeTerm tr | (L _ ty, L _ tr) <- fs]
CncCat mty _ _ _ _ -> 1 + msize mty -- ignoring lindef, linref and printname CncCat mty _ _ _ _ -> 1 + msize mty -- ignoring lindef, linref and printname

View File

@@ -15,6 +15,7 @@
module GF.Grammar.BNFC(BNFCRule(..), BNFCSymbol, Symbol(..), CFTerm(..), bnfc2cf) where module GF.Grammar.BNFC(BNFCRule(..), BNFCSymbol, Symbol(..), CFTerm(..), bnfc2cf) where
import GF.Grammar.CFG import GF.Grammar.CFG
import PGF (Token, mkCId)
import Data.List (partition) import Data.List (partition)
type IsList = Bool type IsList = Bool
@@ -63,12 +64,12 @@ transformRules sepMap (BNFCCoercions c num) = rules ++ [lastRule]
lastRule = Rule (c',[0]) ss rn lastRule = Rule (c',[0]) ss rn
where c' = c ++ show num where c' = c ++ show num
ss = [Terminal "(", NonTerminal (c,[0]), Terminal ")"] ss = [Terminal "(", NonTerminal (c,[0]), Terminal ")"]
rn = CFObj ("coercion_" ++ c) [] rn = CFObj (mkCId $ "coercion_" ++ c) []
fRules c n = Rule (c',[0]) ss rn fRules c n = Rule (c',[0]) ss rn
where c' = if n == 0 then c else c ++ show n where c' = if n == 0 then c else c ++ show n
ss = [NonTerminal (c ++ show (n+1),[0])] ss = [NonTerminal (c ++ show (n+1),[0])]
rn = CFObj ("coercion_" ++ c') [] rn = CFObj (mkCId $ "coercion_" ++ c') []
transformSymb :: SepMap -> BNFCSymbol -> (String, ParamCFSymbol) transformSymb :: SepMap -> BNFCSymbol -> (String, ParamCFSymbol)
transformSymb sepMap s = case s of transformSymb sepMap s = case s of
@@ -93,7 +94,7 @@ createListRules' ne isSep symb c = ruleBase : ruleCons
then [NonTerminal (c,[0]) | ne] then [NonTerminal (c,[0]) | ne]
else [NonTerminal (c,[0]) | ne] ++ else [NonTerminal (c,[0]) | ne] ++
[Terminal symb | symb /= "" && ne] [Terminal symb | symb /= "" && ne]
rn = CFObj ("Base" ++ c) [] rn = CFObj (mkCId $ "Base" ++ c) []
ruleCons ruleCons
| isSep && symb /= "" && not ne = [Rule ("List" ++ c,[1]) smbs0 rn | isSep && symb /= "" && not ne = [Rule ("List" ++ c,[1]) smbs0 rn
,Rule ("List" ++ c,[1]) smbs1 rn] ,Rule ("List" ++ c,[1]) smbs1 rn]
@@ -106,4 +107,4 @@ createListRules' ne isSep symb c = ruleBase : ruleCons
smbs = [NonTerminal (c,[0])] ++ smbs = [NonTerminal (c,[0])] ++
[Terminal symb | symb /= ""] ++ [Terminal symb | symb /= ""] ++
[NonTerminal ("List" ++ c,[0])] [NonTerminal ("List" ++ c,[0])]
rn = CFObj ("Cons" ++ c) [] rn = CFObj (mkCId $ "Cons" ++ c) []

View File

@@ -10,9 +10,9 @@
module GF.Grammar.Binary(VersionTagged(..),decodeModuleHeader,decodeModule,encodeModule) where module GF.Grammar.Binary(VersionTagged(..),decodeModuleHeader,decodeModule,encodeModule) where
import Prelude hiding (catch) import Prelude hiding (catch)
import Control.Monad
import Control.Exception(catch,ErrorCall(..),throwIO) import Control.Exception(catch,ErrorCall(..),throwIO)
import Data.Binary
import PGF.Internal(Binary(..),Word8,putWord8,getWord8,encodeFile,decodeFile)
import qualified Data.Map as Map(empty) import qualified Data.Map as Map(empty)
import qualified Data.ByteString.Char8 as BS import qualified Data.ByteString.Char8 as BS
@@ -22,10 +22,11 @@ import GF.Infra.Option
import GF.Infra.UseIO(MonadIO(..)) import GF.Infra.UseIO(MonadIO(..))
import GF.Grammar.Grammar import GF.Grammar.Grammar
import PGF2.Internal(Literal(..),Symbol(..)) import PGF() -- Binary instances
import PGF.Internal(Literal(..))
-- Please change this every time when the GFO format is changed -- Please change this every time when the GFO format is changed
gfoVersion = "GF05" gfoVersion = "GF04"
instance Binary Ident where instance Binary Ident where
put id = put (ident2utf8 id) put id = put (ident2utf8 id)
@@ -119,7 +120,7 @@ instance Binary Info where
put (AbsCat x) = putWord8 0 >> put x put (AbsCat x) = putWord8 0 >> put x
put (AbsFun w x y z) = putWord8 1 >> put (w,x,y,z) put (AbsFun w x y z) = putWord8 1 >> put (w,x,y,z)
put (ResParam x y) = putWord8 2 >> put (x,y) put (ResParam x y) = putWord8 2 >> put (x,y)
put (ResValue x y) = putWord8 3 >> put (x,y) put (ResValue x) = putWord8 3 >> put x
put (ResOper x y) = putWord8 4 >> put (x,y) put (ResOper x y) = putWord8 4 >> put (x,y)
put (ResOverload x y)= putWord8 5 >> put (x,y) put (ResOverload x y)= putWord8 5 >> put (x,y)
put (CncCat v w x y z)=putWord8 6 >> put (v,w,x,y,z) put (CncCat v w x y z)=putWord8 6 >> put (v,w,x,y,z)
@@ -130,7 +131,7 @@ instance Binary Info where
0 -> get >>= \x -> return (AbsCat x) 0 -> get >>= \x -> return (AbsCat x)
1 -> get >>= \(w,x,y,z) -> return (AbsFun w x y z) 1 -> get >>= \(w,x,y,z) -> return (AbsFun w x y z)
2 -> get >>= \(x,y) -> return (ResParam x y) 2 -> get >>= \(x,y) -> return (ResParam x y)
3 -> get >>= \(x,y) -> return (ResValue x y) 3 -> get >>= \x -> return (ResValue x)
4 -> get >>= \(x,y) -> return (ResOper x y) 4 -> get >>= \(x,y) -> return (ResOper x y)
5 -> get >>= \(x,y) -> return (ResOverload x y) 5 -> get >>= \(x,y) -> return (ResOverload x y)
6 -> get >>= \(v,w,x,y,z)->return (CncCat v w x y z) 6 -> get >>= \(v,w,x,y,z)->return (CncCat v w x y z)
@@ -297,53 +298,6 @@ instance Binary Label where
1 -> fmap LVar get 1 -> fmap LVar get
_ -> decodingError _ -> decodingError
instance Binary BindType where
put Explicit = putWord8 0
put Implicit = putWord8 1
get = do tag <- getWord8
case tag of
0 -> return Explicit
1 -> return Implicit
_ -> decodingError
instance Binary Literal where
put (LStr s) = putWord8 0 >> put s
put (LInt i) = putWord8 1 >> put i
put (LFlt d) = putWord8 2 >> put d
get = do tag <- getWord8
case tag of
0 -> liftM LStr get
1 -> liftM LInt get
2 -> liftM LFlt get
_ -> decodingError
instance Binary Symbol where
put (SymCat n l) = putWord8 0 >> put (n,l)
put (SymLit n l) = putWord8 1 >> put (n,l)
put (SymVar n l) = putWord8 2 >> put (n,l)
put (SymKS ts) = putWord8 3 >> put ts
put (SymKP d vs) = putWord8 4 >> put (d,vs)
put SymBIND = putWord8 5
put SymSOFT_BIND = putWord8 6
put SymNE = putWord8 7
put SymSOFT_SPACE = putWord8 8
put SymCAPIT = putWord8 9
put SymALL_CAPIT = putWord8 10
get = do tag <- getWord8
case tag of
0 -> liftM2 SymCat get get
1 -> liftM2 SymLit get get
2 -> liftM2 SymVar get get
3 -> liftM SymKS get
4 -> liftM2 (\d vs -> SymKP d vs) get get
5 -> return SymBIND
6 -> return SymSOFT_BIND
7 -> return SymNE
8 -> return SymSOFT_SPACE
9 -> return SymCAPIT
10-> return SymALL_CAPIT
_ -> decodingError
--putGFOVersion = mapM_ (putWord8 . fromIntegral . ord) gfoVersion --putGFOVersion = mapM_ (putWord8 . fromIntegral . ord) gfoVersion
--getGFOVersion = replicateM (length gfoVersion) (fmap (chr . fromIntegral) getWord8) --getGFOVersion = replicateM (length gfoVersion) (fmap (chr . fromIntegral) getWord8)
--putGFOVersion = put gfoVersion --putGFOVersion = put gfoVersion

View File

@@ -4,11 +4,10 @@
-- --
-- Context-free grammar representation and manipulation. -- Context-free grammar representation and manipulation.
---------------------------------------------------------------------- ----------------------------------------------------------------------
module GF.Grammar.CFG(Cat,Token, module GF.Grammar.CFG) where module GF.Grammar.CFG where
import GF.Data.Utilities import GF.Data.Utilities
import PGF2(Fun,Cat) import PGF
import PGF2.Internal(Token)
import GF.Data.Relation import GF.Data.Relation
import Data.Map (Map) import Data.Map (Map)
@@ -21,6 +20,8 @@ import qualified Data.Set as Set
-- * Types -- * Types
-- --
type Cat = String
data Symbol c t = NonTerminal c | Terminal t data Symbol c t = NonTerminal c | Terminal t
deriving (Eq, Ord, Show) deriving (Eq, Ord, Show)
@@ -38,12 +39,12 @@ data Grammar c t = Grammar {
deriving (Eq, Ord, Show) deriving (Eq, Ord, Show)
data CFTerm data CFTerm
= CFObj Fun [CFTerm] -- ^ an abstract syntax function with arguments = CFObj CId [CFTerm] -- ^ an abstract syntax function with arguments
| CFAbs Int CFTerm -- ^ A lambda abstraction. The Int is the variable id. | CFAbs Int CFTerm -- ^ A lambda abstraction. The Int is the variable id.
| CFApp CFTerm CFTerm -- ^ Application | CFApp CFTerm CFTerm -- ^ Application
| CFRes Int -- ^ The result of the n:th (0-based) non-terminal | CFRes Int -- ^ The result of the n:th (0-based) non-terminal
| CFVar Int -- ^ A lambda-bound variable | CFVar Int -- ^ A lambda-bound variable
| CFMeta Fun -- ^ A metavariable | CFMeta CId -- ^ A metavariable
deriving (Eq, Ord, Show) deriving (Eq, Ord, Show)
type CFSymbol = Symbol Cat Token type CFSymbol = Symbol Cat Token
@@ -231,7 +232,7 @@ uniqueFuns = snd . mapAccumL uniqueFun Set.empty
uniqueFun funs (Rule cat items (CFObj fun args)) = (Set.insert fun' funs,Rule cat items (CFObj fun' args)) uniqueFun funs (Rule cat items (CFObj fun args)) = (Set.insert fun' funs,Rule cat items (CFObj fun' args))
where where
fun' = head [fun'|suffix<-"":map show ([2..]::[Int]), fun' = head [fun'|suffix<-"":map show ([2..]::[Int]),
let fun'=fun++suffix, let fun'=mkCId (showCId fun++suffix),
not (fun' `Set.member` funs)] not (fun' `Set.member` funs)]
-- | Gets all rules in a CFG. -- | Gets all rules in a CFG.
@@ -309,12 +310,12 @@ prProductions prods =
prCFTerm :: CFTerm -> String prCFTerm :: CFTerm -> String
prCFTerm = pr 0 prCFTerm = pr 0
where where
pr p (CFObj f args) = paren p (f ++ " (" ++ concat (intersperse "," (map (pr 0) args)) ++ ")") pr p (CFObj f args) = paren p (showCId f ++ " (" ++ concat (intersperse "," (map (pr 0) args)) ++ ")")
pr p (CFAbs i t) = paren p ("\\x" ++ show i ++ ". " ++ pr 0 t) pr p (CFAbs i t) = paren p ("\\x" ++ show i ++ ". " ++ pr 0 t)
pr p (CFApp t1 t2) = paren p (pr 1 t1 ++ "(" ++ pr 0 t2 ++ ")") pr p (CFApp t1 t2) = paren p (pr 1 t1 ++ "(" ++ pr 0 t2 ++ ")")
pr _ (CFRes i) = "$" ++ show i pr _ (CFRes i) = "$" ++ show i
pr _ (CFVar i) = "x" ++ show i pr _ (CFVar i) = "x" ++ show i
pr _ (CFMeta c) = "?" ++ c pr _ (CFMeta c) = "?" ++ showCId c
paren 0 x = x paren 0 x = x
paren 1 x = "(" ++ x ++ ")" paren 1 x = "(" ++ x ++ ")"
@@ -322,12 +323,12 @@ prCFTerm = pr 0
-- * CFRule Utilities -- * CFRule Utilities
-- --
ruleFun :: Rule c t -> Fun ruleFun :: Rule c t -> CId
ruleFun (Rule _ _ t) = f t ruleFun (Rule _ _ t) = f t
where f (CFObj n _) = n where f (CFObj n _) = n
f (CFApp _ x) = f x f (CFApp _ x) = f x
f (CFAbs _ x) = f x f (CFAbs _ x) = f x
f _ = "" f _ = mkCId ""
-- | Check if any of the categories used on the right-hand side -- | Check if any of the categories used on the right-hand side
-- are in the given list of categories. -- are in the given list of categories.
@@ -335,7 +336,7 @@ anyUsedBy :: Eq c => [c] -> Rule c t -> Bool
anyUsedBy cs (Rule _ ss _) = any (`elem` cs) (filterCats ss) anyUsedBy cs (Rule _ ss _) = any (`elem` cs) (filterCats ss)
mkCFTerm :: String -> CFTerm mkCFTerm :: String -> CFTerm
mkCFTerm n = CFObj n [] mkCFTerm n = CFObj (mkCId n) []
ruleIsNonRecursive :: Ord c => Set c -> Rule c t -> Bool ruleIsNonRecursive :: Ord c => Set c -> Rule c t -> Bool
ruleIsNonRecursive cs = noCatsInSet cs . ruleRhs ruleIsNonRecursive cs = noCatsInSet cs . ruleRhs

View File

@@ -30,7 +30,7 @@ data TypeApp = TypeApp CatId [Type] deriving Show
data TypeBinding = TypeBinding VarId Type deriving Show data TypeBinding = TypeBinding VarId Type deriving Show
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
-- ** Concreate syntax -- ** Concrete syntax
-- | Concrete Syntax -- | Concrete Syntax
data Concrete = Concrete ModId ModId Flags [ParamDef] [LincatDef] [LinDef] data Concrete = Concrete ModId ModId Flags [ParamDef] [LincatDef] [LinDef]
@@ -102,9 +102,9 @@ data TableRow rhs = TableRow LinPattern rhs
-- *** Identifiers in Concrete Syntax -- *** Identifiers in Concrete Syntax
newtype PredefId = PredefId Id deriving (Eq,Ord,Show) newtype PredefId = PredefId Id deriving (Eq,Ord,Show)
newtype LabelId = LabelId Id deriving (Eq,Ord,Show) newtype LabelId = LabelId Id deriving (Eq,Ord,Show)
data VarValueId = VarValueId QualId deriving (Eq,Ord,Show) newtype VarValueId = VarValueId QualId deriving (Eq,Ord,Show)
-- | Name of param type or param value -- | Name of param type or param value
newtype ParamId = ParamId QualId deriving (Eq,Ord,Show) newtype ParamId = ParamId QualId deriving (Eq,Ord,Show)
@@ -115,9 +115,9 @@ newtype ParamId = ParamId QualId deriving (Eq,Ord,Show)
newtype ModId = ModId Id deriving (Eq,Ord,Show) newtype ModId = ModId Id deriving (Eq,Ord,Show)
newtype CatId = CatId Id deriving (Eq,Ord,Show) newtype CatId = CatId Id deriving (Eq,Ord,Show)
newtype FunId = FunId Id deriving (Eq,Show) newtype FunId = FunId Id deriving (Eq,Ord,Show)
data VarId = Anonymous | VarId Id deriving Show data VarId = Anonymous | VarId Id deriving (Eq,Show)
newtype Flags = Flags [(FlagName,FlagValue)] deriving Show newtype Flags = Flags [(FlagName,FlagValue)] deriving Show
type FlagName = Id type FlagName = Id

View File

@@ -6,6 +6,7 @@ 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)
encodeJSON :: FilePath -> Grammar -> IO () encodeJSON :: FilePath -> Grammar -> IO ()
@@ -126,10 +127,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 +187,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
@@ -237,7 +238,7 @@ 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
@@ -268,6 +269,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

View File

@@ -16,6 +16,7 @@ module GF.Grammar.EBNF (EBNF, ERule, ERHS(..), ebnf2cf) where
import GF.Data.Operations import GF.Data.Operations
import GF.Grammar.CFG import GF.Grammar.CFG
import PGF (mkCId)
type EBNF = [ERule] type EBNF = [ERule]
type ERule = (ECat, ERHS) type ERule = (ECat, ERHS)
@@ -39,7 +40,7 @@ ebnf2cf :: EBNF -> [ParamCFRule]
ebnf2cf ebnf = ebnf2cf ebnf =
[Rule cat items (mkCFF i cat) | (i,(cat,items)) <- zip [0..] (normEBNF ebnf)] [Rule cat items (mkCFF i cat) | (i,(cat,items)) <- zip [0..] (normEBNF ebnf)]
where where
mkCFF i (c,_) = CFObj ("Mk" ++ c ++ "_" ++ show i) [] mkCFF i (c,_) = CFObj (mkCId ("Mk" ++ c ++ "_" ++ show i)) []
normEBNF :: EBNF -> [CFJustRule] normEBNF :: EBNF -> [CFJustRule]
normEBNF erules = let normEBNF erules = let

View File

@@ -64,7 +64,7 @@ module GF.Grammar.Grammar (
Location(..), L(..), unLoc, noLoc, ppLocation, ppL, Location(..), L(..), unLoc, noLoc, ppLocation, ppL,
-- ** PMCFG -- ** PMCFG
PMCFG(..), Production(..), FId, FunId, SeqId, LIndex PMCFG(..), Production(..), FId, FunId, SeqId, LIndex, Sequence
) where ) where
import GF.Infra.Ident import GF.Infra.Ident
@@ -73,8 +73,7 @@ import GF.Infra.Location
import GF.Data.Operations import GF.Data.Operations
import PGF2(LIndex, BindType(..)) import PGF.Internal (FId, FunId, SeqId, LIndex, Sequence, BindType(..))
import PGF2.Internal(FId, FunId, SeqId, Symbol)
import Data.Array.IArray(Array) import Data.Array.IArray(Array)
import Data.Array.Unboxed(UArray) import Data.Array.Unboxed(UArray)
@@ -100,7 +99,7 @@ data ModuleInfo = ModInfo {
mopens :: [OpenSpec], mopens :: [OpenSpec],
mexdeps :: [ModuleName], mexdeps :: [ModuleName],
msrc :: FilePath, msrc :: FilePath,
mseqs :: Maybe (Array SeqId [Symbol]), mseqs :: Maybe (Array SeqId Sequence),
jments :: Map.Map Ident Info jments :: Map.Map Ident Info
} }
@@ -330,7 +329,7 @@ data Info =
-- judgements in resource -- judgements in resource
| ResParam (Maybe (L [Param])) (Maybe [Term]) -- ^ (/RES/) the second parameter is list of all possible values | ResParam (Maybe (L [Param])) (Maybe [Term]) -- ^ (/RES/) the second parameter is list of all possible values
| ResValue (L Type) Int -- ^ (/RES/) to mark parameter constructors for lookup | ResValue (L Type) -- ^ (/RES/) to mark parameter constructors for lookup
| ResOper (Maybe (L Type)) (Maybe (L Term)) -- ^ (/RES/) | ResOper (Maybe (L Type)) (Maybe (L Term)) -- ^ (/RES/)
| ResOverload [ModuleName] [(L Type,L Term)] -- ^ (/RES/) idents: modules inherited | ResOverload [ModuleName] [(L Type,L Term)] -- ^ (/RES/) idents: modules inherited
@@ -459,7 +458,7 @@ type Case = (Patt, Term)
--type Cases = ([Patt], Term) --type Cases = ([Patt], Term)
type LocalDef = (Ident, (Maybe Type, Term)) type LocalDef = (Ident, (Maybe Type, Term))
type Param = (Ident, Context, Int) type Param = (Ident, Context)
type Altern = (Term, [(Term, Term)]) type Altern = (Term, [(Term, Term)])
type Substitution = [(Ident, Term)] type Substitution = [(Ident, Term)]

View File

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

View File

@@ -25,7 +25,6 @@ module GF.Grammar.Lookup (
lookupOverloadTypes, lookupOverloadTypes,
lookupParamValues, lookupParamValues,
allParamValues, allParamValues,
lookupParamValueIndex,
lookupAbsDef, lookupAbsDef,
lookupLincat, lookupLincat,
lookupFunType, lookupFunType,
@@ -84,7 +83,7 @@ lookupResDefLoc gr (m,c)
AnyInd _ n -> look n c AnyInd _ n -> look n c
ResParam _ _ -> return (noLoc (QC (m,c))) ResParam _ _ -> return (noLoc (QC (m,c)))
ResValue _ _ -> return (noLoc (QC (m,c))) ResValue _ -> return (noLoc (QC (m,c)))
_ -> raise $ render (c <+> "is not defined in resource" <+> m) _ -> raise $ render (c <+> "is not defined in resource" <+> m)
lookupResType :: ErrorMonad m => Grammar -> QIdent -> m Type lookupResType :: ErrorMonad m => Grammar -> QIdent -> m Type
@@ -100,7 +99,7 @@ lookupResType gr (m,c) = do
return $ mkProd cont val' [] return $ mkProd cont val' []
AnyInd _ n -> lookupResType gr (n,c) AnyInd _ n -> lookupResType gr (n,c)
ResParam _ _ -> return typePType ResParam _ _ -> return typePType
ResValue (L _ t) _-> return t ResValue (L _ t) -> return t
_ -> raise $ render (c <+> "has no type defined in resource" <+> m) _ -> raise $ render (c <+> "has no type defined in resource" <+> m)
lookupOverloadTypes :: ErrorMonad m => Grammar -> QIdent -> m [(Term,Type)] lookupOverloadTypes :: ErrorMonad m => Grammar -> QIdent -> m [(Term,Type)]
@@ -114,8 +113,8 @@ lookupOverloadTypes gr id@(m,c) = do
CncFun (Just (cat,cont,val)) _ _ _ -> do CncFun (Just (cat,cont,val)) _ _ _ -> do
val' <- lock cat val val' <- lock cat val
ret $ mkProd cont val' [] ret $ mkProd cont val' []
ResParam _ _ -> ret typePType ResParam _ _ -> ret typePType
ResValue (L _ t) _ -> ret t ResValue (L _ t) -> ret t
ResOverload os tysts -> do ResOverload os tysts -> do
tss <- mapM (\x -> lookupOverloadTypes gr (x,c)) os tss <- mapM (\x -> lookupOverloadTypes gr (x,c)) os
return $ [(tr,ty) | (L _ ty,L _ tr) <- tysts] ++ return $ [(tr,ty) | (L _ ty,L _ tr) <- tysts] ++
@@ -167,23 +166,16 @@ 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
sortByFst = sortBy (\ x y -> compare (fst x) (fst y)) sortByFst = sortBy (\ x y -> compare (fst x) (fst y))
lookupParamValueIndex :: ErrorMonad m => Grammar -> QIdent -> m Int
lookupParamValueIndex gr c = do
(_,info) <- lookupOrigInfo gr c
case info of
ResValue _ i -> return i
_ -> raise $ render (ppQIdent Qualified c <+> "has no parameter index defined")
lookupAbsDef :: ErrorMonad m => Grammar -> ModuleName -> Ident -> m (Maybe Int,Maybe [Equation]) lookupAbsDef :: ErrorMonad m => Grammar -> ModuleName -> Ident -> m (Maybe Int,Maybe [Equation])
lookupAbsDef gr m c = errIn (render ("looking up absdef of" <+> c)) $ do lookupAbsDef gr m c = errIn (render ("looking up absdef of" <+> c)) $ do
info <- lookupQIdentInfo gr (m,c) info <- lookupQIdentInfo gr (m,c)
@@ -234,7 +226,7 @@ allOpers gr =
typesIn info = case info of typesIn info = case info of
AbsFun (Just ltyp) _ _ _ -> [ltyp] AbsFun (Just ltyp) _ _ _ -> [ltyp]
ResOper (Just ltyp) _ -> [ltyp] ResOper (Just ltyp) _ -> [ltyp]
ResValue ltyp _ -> [ltyp] ResValue ltyp -> [ltyp]
ResOverload _ tytrs -> [ltyp | (ltyp,_) <- tytrs] ResOverload _ tytrs -> [ltyp | (ltyp,_) <- tytrs]
CncFun (Just (i,ctx,typ)) _ _ _ -> CncFun (Just (i,ctx,typ)) _ _ _ ->
[L NoLoc (mkProdSimple ctx (lock' i typ))] [L NoLoc (mkProdSimple ctx (lock' i typ))]

View File

@@ -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.
@@ -47,7 +48,7 @@ typeForm t =
Q c -> ([],c,[]) Q c -> ([],c,[])
QC c -> ([],c,[]) QC c -> ([],c,[])
Sort c -> ([],(MN identW, c),[]) Sort c -> ([],(MN identW, c),[])
_ -> error (render ("no normal form of type" <+> show t)) _ -> error (render ("no normal form of type" <+> ppTerm Unqualified 0 t))
typeFormCnc :: Type -> (Context, Type) typeFormCnc :: Type -> (Context, Type)
typeFormCnc t = typeFormCnc t =
@@ -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
@@ -614,15 +611,13 @@ allDependencies ism b =
opersIn t = case t of opersIn t = case t of
Q (n,c) | ism n -> [c] Q (n,c) | ism n -> [c]
QC (n,c) | ism n -> [c] QC (n,c) | ism n -> [c]
Cn c -> [c]
_ -> collectOp opersIn t _ -> collectOp opersIn t
opty (Just (L _ ty)) = opersIn ty opty (Just (L _ ty)) = opersIn ty
opty _ = [] opty _ = []
pts i = case i of pts i = case i of
ResOper pty pt -> [pty,pt] ResOper pty pt -> [pty,pt]
ResOverload _ tyts -> concat [[Just ty, Just tr] | (ty,tr) <- tyts] ResOverload _ tyts -> concat [[Just ty, Just tr] | (ty,tr) <- tyts]
ResParam (Just (L loc ps)) _ -> [Just (L loc t) | (_,cont,_) <- ps, (_,_,t) <- cont] ResParam (Just (L loc ps)) _ -> [Just (L loc t) | (_,cont) <- ps, (_,_,t) <- cont]
ResValue pty _ -> [Just pty]
CncCat pty _ _ _ _ -> [pty] CncCat pty _ _ _ _ -> [pty]
CncFun _ pt _ _ -> [pt] ---- (Maybe (Ident,(Context,Type)) CncFun _ pt _ _ -> [pt] ---- (Maybe (Ident,(Context,Type))
AbsFun pty _ ptr _ -> [pty] --- ptr is def, which can be mutual AbsFun pty _ ptr _ -> [pty] --- ptr is def, which can be mutual

View File

@@ -25,6 +25,7 @@ import GF.Compile.Update (buildAnyTree)
import Data.List(intersperse) import Data.List(intersperse)
import Data.Char(isAlphaNum) import Data.Char(isAlphaNum)
import qualified Data.Map as Map import qualified Data.Map as Map
import PGF(mkCId)
} }
@@ -267,7 +268,7 @@ DataDef
ParamDef :: { [(Ident,Info)] } ParamDef :: { [(Ident,Info)] }
ParamDef ParamDef
: Posn LhsIdent '=' ListParConstr Posn { ($2, ResParam (Just (mkL $1 $5 [param | L loc param <- $4])) Nothing) : : Posn LhsIdent '=' ListParConstr Posn { ($2, ResParam (Just (mkL $1 $5 [param | L loc param <- $4])) Nothing) :
[(f, ResValue (L loc (mkProdSimple co (Cn $2))) i) | L loc (f,co,i) <- $4] } [(f, ResValue (L loc (mkProdSimple co (Cn $2)))) | L loc (f,co) <- $4] }
| Posn LhsIdent Posn { [($2, ResParam Nothing Nothing)] } | Posn LhsIdent Posn { [($2, ResParam Nothing Nothing)] }
OperDef :: { [(Ident,Info)] } OperDef :: { [(Ident,Info)] }
@@ -302,7 +303,7 @@ ListDataConstr
ParConstr :: { L Param } ParConstr :: { L Param }
ParConstr ParConstr
: Posn Ident ListDDecl Posn { mkL $1 $4 ($2,$3,0) } : Posn Ident ListDDecl Posn { mkL $1 $4 ($2,$3) }
ListLinDef :: { [(Ident,Info)] } ListLinDef :: { [(Ident,Info)] }
ListLinDef ListLinDef
@@ -624,7 +625,7 @@ ListCFRule
CFRule :: { [BNFCRule] } CFRule :: { [BNFCRule] }
CFRule CFRule
: Ident '.' Ident '::=' ListCFSymbol ';' { [BNFCRule (showIdent $3) $5 (CFObj (showIdent $1) [])] : Ident '.' Ident '::=' ListCFSymbol ';' { [BNFCRule (showIdent $3) $5 (CFObj (mkCId (showIdent $1)) [])]
} }
| Ident '::=' ListCFRHS ';' { let { cat = showIdent $1; | Ident '::=' ListCFRHS ';' { let { cat = showIdent $1;
mkFun cat its = mkFun cat its =
@@ -637,7 +638,7 @@ CFRule
Terminal c -> filter isAlphaNum c; Terminal c -> filter isAlphaNum c;
NonTerminal (t,_) -> t NonTerminal (t,_) -> t
} }
} in map (\rhs -> BNFCRule cat rhs (CFObj (mkFun cat rhs) [])) $3 } in map (\rhs -> BNFCRule cat rhs (CFObj (mkCId (mkFun cat rhs)) [])) $3
} }
| 'coercions' Ident Integer ';' { [BNFCCoercions (showIdent $2) $3]} | 'coercions' Ident Integer ';' { [BNFCCoercions (showIdent $2) $3]}
| 'terminator' NonEmpty Ident String ';' { [BNFCTerminator $2 (showIdent $3) $4] } | 'terminator' NonEmpty Ident String ';' { [BNFCTerminator $2 (showIdent $3) $4] }
@@ -774,7 +775,7 @@ checkInfoType mt jment@(id,info) =
CncCat pty pd pr ppn _->ifConcrete mt (locPerh pty ++ locPerh pd ++ locPerh pr ++ locPerh ppn) CncCat pty pd pr ppn _->ifConcrete mt (locPerh pty ++ locPerh pd ++ locPerh pr ++ locPerh ppn)
CncFun _ pd ppn _ -> ifConcrete mt (locPerh pd ++ locPerh ppn) CncFun _ pd ppn _ -> ifConcrete mt (locPerh pd ++ locPerh ppn)
ResParam pparam _ -> ifResource mt (locPerh pparam) ResParam pparam _ -> ifResource mt (locPerh pparam)
ResValue ty _ -> ifResource mt (locL ty) ResValue ty -> ifResource mt (locL ty)
ResOper pty pt -> ifOper mt pty pt ResOper pty pt -> ifOper mt pty pt
ResOverload _ xs -> ifResource mt (concat [[loc1,loc2] | (L loc1 _,L loc2 _) <- xs]) ResOverload _ xs -> ifResource mt (concat [[loc1,loc2] | (L loc1 _,L loc2 _) <- xs])
where where

View File

@@ -73,14 +73,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 +107,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 +135,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

View File

@@ -22,17 +22,21 @@ module GF.Grammar.Printer
, ppMeta , ppMeta
, getAbs , getAbs
) where ) where
import Prelude hiding ((<>)) -- GHC 8.4.1 clash with Text.PrettyPrint
import PGF2 as PGF2
import PGF2.Internal as PGF2
import GF.Infra.Ident import GF.Infra.Ident
import GF.Infra.Option import GF.Infra.Option
import GF.Grammar.Values import GF.Grammar.Values
import GF.Grammar.Grammar import GF.Grammar.Grammar
import PGF.Internal (ppMeta, ppLit, ppFId, ppFunId, ppSeqId, ppSeq)
import GF.Text.Pretty import GF.Text.Pretty
import Data.Maybe (isNothing) import Data.Maybe (isNothing)
import Data.List (intersperse) import Data.List (intersperse)
import qualified Data.Map as Map import qualified Data.Map as Map
--import qualified Data.IntMap as IntMap
--import qualified Data.Set as Set
import qualified Data.Array.IArray as Array import qualified Data.Array.IArray as Array
data TermPrintQual data TermPrintQual
@@ -106,8 +110,8 @@ ppJudgement q (id, ResParam pparams _) =
(case pparams of (case pparams of
Just (L _ ps) -> '=' <+> ppParams q ps Just (L _ ps) -> '=' <+> ppParams q ps
_ -> empty) <+> ';' _ -> empty) <+> ';'
ppJudgement q (id, ResValue pvalue i) = ppJudgement q (id, ResValue pvalue) =
"-- param constructor" <+> "[index" <+> i <> "]" <+> id <+> ':' <+> "-- param constructor" <+> id <+> ':' <+>
(case pvalue of (case pvalue of
(L _ ty) -> ppTerm q 0 ty) <+> ';' (L _ ty) -> ppTerm q 0 ty) <+> ';'
ppJudgement q (id, ResOper ptype pexp) = ppJudgement q (id, ResOper ptype pexp) =
@@ -322,7 +326,7 @@ ppBind (Implicit,v) = braces v
ppAltern q (x,y) = ppTerm q 0 x <+> '/' <+> ppTerm q 0 y ppAltern q (x,y) = ppTerm q 0 x <+> '/' <+> ppTerm q 0 y
ppParams q ps = fsep (intersperse (pp '|') (map (ppParam q) ps)) ppParams q ps = fsep (intersperse (pp '|') (map (ppParam q) ps))
ppParam q (id,cxt,_) = id <+> hsep (map (ppDDecl q) cxt) ppParam q (id,cxt) = id <+> hsep (map (ppDDecl q) cxt)
ppProduction (Production fid funid args) = ppProduction (Production fid funid args) =
ppFId fid <+> "->" <+> ppFunId funid <> ppFId fid <+> "->" <+> ppFunId funid <>
@@ -359,39 +363,3 @@ getLet (Let l e) = let (ls,e') = getLet e
in (l:ls,e') in (l:ls,e')
getLet e = ([],e) getLet e = ([],e)
ppFunId funid = pp 'F' <> pp funid
ppSeqId seqid = pp 'S' <> pp seqid
ppFId fid
| fid == PGF2.fidString = pp "CString"
| fid == PGF2.fidInt = pp "CInt"
| fid == PGF2.fidFloat = pp "CFloat"
| fid == PGF2.fidVar = pp "CVar"
| fid == PGF2.fidStart = pp "CStart"
| otherwise = pp 'C' <> pp fid
ppMeta :: Int -> Doc
ppMeta n
| n == 0 = pp '?'
| otherwise = pp '?' <> pp n
ppLit (PGF2.LStr s) = pp (show s)
ppLit (PGF2.LInt n) = pp n
ppLit (PGF2.LFlt d) = pp d
ppSeq (seqid,seq) =
ppSeqId seqid <+> pp ":=" <+> hsep (map ppSymbol seq)
ppSymbol (PGF2.SymCat d r) = pp '<' <> pp d <> pp ',' <> pp r <> pp '>'
ppSymbol (PGF2.SymLit d r) = pp '{' <> pp d <> pp ',' <> pp r <> pp '}'
ppSymbol (PGF2.SymVar d r) = pp '<' <> pp d <> pp ',' <> pp '$' <> pp r <> pp '>'
ppSymbol (PGF2.SymKS t) = doubleQuotes (pp t)
ppSymbol PGF2.SymNE = pp "nonExist"
ppSymbol PGF2.SymBIND = pp "BIND"
ppSymbol PGF2.SymSOFT_BIND = pp "SOFT_BIND"
ppSymbol PGF2.SymSOFT_SPACE= pp "SOFT_SPACE"
ppSymbol PGF2.SymCAPIT = pp "CAPIT"
ppSymbol PGF2.SymALL_CAPIT = pp "ALL_CAPIT"
ppSymbol (PGF2.SymKP syms alts) = pp "pre" <+> braces (hsep (punctuate (pp ';') (hsep (map ppSymbol syms) : map ppAlt alts)))
ppAlt (syms,ps) = hsep (map ppSymbol syms) <+> pp '/' <+> hsep (map (doubleQuotes . pp) ps)

View File

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

View File

@@ -18,6 +18,7 @@ module GF.Infra.CheckM
checkIn, checkInModule, checkMap, checkMapRecover, checkIn, checkInModule, checkMap, checkMapRecover,
parallelCheck, accumulateError, commitCheck, parallelCheck, accumulateError, commitCheck,
) where ) where
import Prelude hiding ((<>)) -- GHC 8.4.1 clash with Text.PrettyPrint
import GF.Data.Operations import GF.Data.Operations
--import GF.Infra.Ident --import GF.Infra.Ident
@@ -31,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
@@ -52,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

View File

@@ -13,17 +13,17 @@
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
module GF.Infra.Ident (-- ** Identifiers module GF.Infra.Ident (-- ** Identifiers
ModuleName(..), moduleNameS, ModuleName(..), moduleNameS,
Ident, ident2utf8, showIdent, prefixIdent, Ident, ident2utf8, showIdent, prefixIdent,
-- *** Normal identifiers (returned by the parser) -- *** Normal identifiers (returned by the parser)
identS, identC, identW, identS, identC, identW,
-- *** Special identifiers for internal use -- *** Special identifiers for internal use
identV, identA, identAV, identV, identA, identAV,
argIdent, isArgIdent, getArgIndex, argIdent, isArgIdent, getArgIndex,
varStr, varX, isWildIdent, varIndex, varStr, varX, isWildIdent, varIndex,
-- *** Raw identifiers -- *** Raw identifiers
RawIdent, rawIdentS, rawIdentC, ident2raw, prefixRawIdent, RawIdent, rawIdentS, rawIdentC, ident2raw, prefixRawIdent,
isPrefixOf, showRawIdent isPrefixOf, showRawIdent
) where ) where
import qualified Data.ByteString.UTF8 as UTF8 import qualified Data.ByteString.UTF8 as UTF8
@@ -31,7 +31,7 @@ import qualified Data.ByteString.Char8 as BS(append,isPrefixOf)
-- Limit use of BS functions to the ones that work correctly on -- Limit use of BS functions to the ones that work correctly on
-- UTF-8-encoded bytestrings! -- UTF-8-encoded bytestrings!
import Data.Char(isDigit) import Data.Char(isDigit)
import Data.Binary(Binary(..)) import PGF.Internal(Binary(..))
import GF.Text.Pretty import GF.Text.Pretty

View File

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

View File

@@ -34,14 +34,18 @@ import Data.Maybe
import GF.Infra.Ident import GF.Infra.Ident
import GF.Infra.GetOpt import GF.Infra.GetOpt
import GF.Grammar.Predef import GF.Grammar.Predef
--import System.Console.GetOpt
import System.FilePath import System.FilePath
import PGF2.Internal(Literal(..)) --import System.IO
import GF.Data.Operations(Err,ErrorMonad(..),liftErr) import GF.Data.Operations(Err,ErrorMonad(..),liftErr)
import Data.Set (Set) import Data.Set (Set)
import qualified Data.Set as Set import qualified Data.Set as Set
import PGF.Internal(Literal(..))
import qualified Control.Monad.Fail as Fail
usageHeader :: String usageHeader :: String
usageHeader = unlines usageHeader = unlines
["Usage: gf [OPTIONS] [FILE [...]]", ["Usage: gf [OPTIONS] [FILE [...]]",
@@ -72,6 +76,7 @@ errors = raise . unlines
data Mode = ModeVersion | ModeHelp data Mode = ModeVersion | ModeHelp
| ModeInteractive | ModeRun | ModeInteractive | ModeRun
| ModeInteractive2 | ModeRun2
| ModeCompiler | ModeCompiler
| ModeServer {-port::-}Int | ModeServer {-port::-}Int
deriving (Show,Eq,Ord) deriving (Show,Eq,Ord)
@@ -82,12 +87,16 @@ data Verbosity = Quiet | Normal | Verbose | Debug
data Phase = Preproc | Convert | Compile | Link data Phase = Preproc | Convert | Compile | Link
deriving (Show,Eq,Ord) deriving (Show,Eq,Ord)
data OutputFormat = FmtPGFPretty data OutputFormat = FmtLPGF
| FmtPGFPretty
| FmtCanonicalGF | FmtCanonicalGF
| FmtCanonicalJson | FmtCanonicalJson
| FmtJavaScript
| FmtJSON | FmtJSON
| FmtPython
| FmtHaskell | FmtHaskell
| FmtJava | FmtJava
| FmtProlog
| FmtBNF | FmtBNF
| FmtEBNF | FmtEBNF
| FmtRegular | FmtRegular
@@ -124,7 +133,7 @@ data CFGTransform = CFGNoLR
deriving (Show,Eq,Ord) deriving (Show,Eq,Ord)
data HaskellOption = HaskellNoPrefix | HaskellGADT | HaskellLexical data HaskellOption = HaskellNoPrefix | HaskellGADT | HaskellLexical
| HaskellConcrete | HaskellVariants | HaskellConcrete | HaskellVariants | HaskellData
deriving (Show,Eq,Ord) deriving (Show,Eq,Ord)
data Warning = WarnMissingLincat data Warning = WarnMissingLincat
@@ -149,7 +158,7 @@ data Flags = Flags {
optLiteralCats :: Set Ident, optLiteralCats :: Set Ident,
optGFODir :: Maybe FilePath, optGFODir :: Maybe FilePath,
optOutputDir :: Maybe FilePath, optOutputDir :: Maybe FilePath,
optGFLibPath :: Maybe FilePath, optGFLibPath :: Maybe [FilePath],
optDocumentRoot :: Maybe FilePath, -- For --server mode optDocumentRoot :: Maybe FilePath, -- For --server mode
optRecomp :: Recomp, optRecomp :: Recomp,
optProbsFile :: Maybe FilePath, optProbsFile :: Maybe FilePath,
@@ -204,9 +213,10 @@ parseModuleOptions args = do
then return opts then return opts
else errors $ map ("Non-option among module options: " ++) nonopts else errors $ map ("Non-option among module options: " ++) nonopts
fixRelativeLibPaths curr_dir lib_dir (Options o) = Options (fixPathFlags . o) fixRelativeLibPaths curr_dir lib_dirs (Options o) = Options (fixPathFlags . o)
where where
fixPathFlags f@(Flags{optLibraryPath=path}) = f{optLibraryPath=concatMap (\dir -> [curr_dir </> dir, lib_dir </> dir]) path} fixPathFlags f@(Flags{optLibraryPath=path}) = f{optLibraryPath=concatMap (\dir -> [parent </> dir
| parent <- curr_dir : lib_dirs]) path}
-- Showing options -- Showing options
@@ -302,6 +312,8 @@ optDescr =
Option ['j'] ["jobs"] (OptArg jobs "N") "Compile N modules in parallel with -batch (default 1).", Option ['j'] ["jobs"] (OptArg jobs "N") "Compile N modules in parallel with -batch (default 1).",
Option [] ["interactive"] (NoArg (mode ModeInteractive)) "Run in interactive mode (default).", Option [] ["interactive"] (NoArg (mode ModeInteractive)) "Run in interactive mode (default).",
Option [] ["run"] (NoArg (mode ModeRun)) "Run in interactive mode, showing output only (no other messages).", Option [] ["run"] (NoArg (mode ModeRun)) "Run in interactive mode, showing output only (no other messages).",
Option [] ["cshell"] (NoArg (mode ModeInteractive2)) "Start the C run-time shell.",
Option [] ["crun"] (NoArg (mode ModeRun2)) "Start the C run-time shell, showing output only (no other messages).",
Option [] ["server"] (OptArg modeServer "port") $ Option [] ["server"] (OptArg modeServer "port") $
"Run in HTTP server mode on given port (default "++show defaultPort++").", "Run in HTTP server mode on given port (default "++show defaultPort++").",
Option [] ["document-root"] (ReqArg gfDocuRoot "DIR") Option [] ["document-root"] (ReqArg gfDocuRoot "DIR")
@@ -319,7 +331,7 @@ optDescr =
Option ['f'] ["output-format"] (ReqArg outFmt "FMT") Option ['f'] ["output-format"] (ReqArg outFmt "FMT")
(unlines ["Output format. FMT can be one of:", (unlines ["Output format. FMT can be one of:",
"Canonical GF grammar: canonical_gf, canonical_json, (and haskell with option --haskell=concrete)", "Canonical GF grammar: canonical_gf, canonical_json, (and haskell with option --haskell=concrete)",
"Multiple concrete: pgf (default), json, js, pgf_pretty, prolog, python, ...", -- gar, "Multiple concrete: pgf (default), lpgf, json, js, pgf_pretty, prolog, python, ...", -- gar,
"Single concrete only: bnf, ebnf, fa, gsl, jsgf, regexp, slf, srgs_xml, srgs_abnf, vxml, ....", -- cf, lbnf, "Single concrete only: bnf, ebnf, fa, gsl, jsgf, regexp, slf, srgs_xml, srgs_abnf, vxml, ....", -- cf, lbnf,
"Abstract only: haskell, ..."]), -- prolog_abs, "Abstract only: haskell, ..."]), -- prolog_abs,
Option [] ["sisr"] (ReqArg sisrFmt "FMT") Option [] ["sisr"] (ReqArg sisrFmt "FMT")
@@ -338,7 +350,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.",
@@ -416,7 +428,7 @@ optDescr =
literalCat x = set $ \o -> o { optLiteralCats = foldr Set.insert (optLiteralCats o) ((map identS . splitBy (==',')) x) } literalCat x = set $ \o -> o { optLiteralCats = foldr Set.insert (optLiteralCats o) ((map identS . splitBy (==',')) x) }
lexicalCat x = set $ \o -> o { optLexicalCats = foldr Set.insert (optLexicalCats o) (splitBy (==',') x) } lexicalCat x = set $ \o -> o { optLexicalCats = foldr Set.insert (optLexicalCats o) (splitBy (==',') x) }
outDir x = set $ \o -> o { optOutputDir = Just x } outDir x = set $ \o -> o { optOutputDir = Just x }
gfLibPath x = set $ \o -> o { optGFLibPath = Just x } gfLibPath x = set $ \o -> o { optGFLibPath = Just $ splitInModuleSearchPath x }
gfDocuRoot x = set $ \o -> o { optDocumentRoot = Just x } gfDocuRoot x = set $ \o -> o { optDocumentRoot = Just x }
recomp x = set $ \o -> o { optRecomp = x } recomp x = set $ \o -> o { optRecomp = x }
probsFile x = set $ \o -> o { optProbsFile = Just x } probsFile x = set $ \o -> o { optProbsFile = Just x }
@@ -461,12 +473,16 @@ outputFormats = map fst outputFormatsExpl
outputFormatsExpl :: [((String,OutputFormat),String)] outputFormatsExpl :: [((String,OutputFormat),String)]
outputFormatsExpl = outputFormatsExpl =
[(("pgf_pretty", FmtPGFPretty),"human-readable pgf"), [(("lpgf", FmtLPGF),"Linearisation-only PGF"),
(("pgf_pretty", FmtPGFPretty),"Human-readable PGF"),
(("canonical_gf", FmtCanonicalGF),"Canonical GF source files"), (("canonical_gf", FmtCanonicalGF),"Canonical GF source files"),
(("canonical_json", FmtCanonicalJson),"Canonical JSON source files"), (("canonical_json", FmtCanonicalJson),"Canonical JSON source files"),
(("js", FmtJavaScript),"JavaScript (whole grammar)"),
(("json", FmtJSON),"JSON (whole grammar)"), (("json", FmtJSON),"JSON (whole grammar)"),
(("python", FmtPython),"Python (whole grammar)"),
(("haskell", FmtHaskell),"Haskell (abstract syntax)"), (("haskell", FmtHaskell),"Haskell (abstract syntax)"),
(("java", FmtJava),"Java (abstract syntax)"), (("java", FmtJava),"Java (abstract syntax)"),
(("prolog", FmtProlog),"Prolog (whole grammar)"),
(("bnf", FmtBNF),"BNF (context-free grammar)"), (("bnf", FmtBNF),"BNF (context-free grammar)"),
(("ebnf", FmtEBNF),"Extended BNF"), (("ebnf", FmtEBNF),"Extended BNF"),
(("regular", FmtRegular),"* regular grammar"), (("regular", FmtRegular),"* regular grammar"),
@@ -517,7 +533,8 @@ haskellOptionNames =
("gadt", HaskellGADT), ("gadt", HaskellGADT),
("lexical", HaskellLexical), ("lexical", HaskellLexical),
("concrete", HaskellConcrete), ("concrete", HaskellConcrete),
("variants", HaskellVariants)] ("variants", HaskellVariants),
("data", HaskellData)]
-- | 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
@@ -534,7 +551,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
@@ -542,7 +559,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

View File

@@ -12,6 +12,9 @@ module GF.Infra.SIO(
newStdGen,print,putStr,putStrLn, newStdGen,print,putStr,putStrLn,
-- ** Specific to GF -- ** Specific to GF
importGrammar,importSource, importGrammar,importSource,
#ifdef C_RUNTIME
readPGF2,
#endif
putStrLnFlush,runInterruptibly,lazySIO, putStrLnFlush,runInterruptibly,lazySIO,
-- * Restricted accesss to arbitrary (potentially unsafe) IO operations -- * Restricted accesss to arbitrary (potentially unsafe) IO operations
-- | If the environment variable GF_RESTRICTED is defined, these -- | If the environment variable GF_RESTRICTED is defined, these
@@ -36,6 +39,10 @@ import qualified System.Random as IO(newStdGen)
import qualified GF.Infra.UseIO as IO(getLibraryDirectory) import qualified GF.Infra.UseIO as IO(getLibraryDirectory)
import qualified GF.System.Signal as IO(runInterruptibly) import qualified GF.System.Signal as IO(runInterruptibly)
import qualified GF.Command.Importing as GF(importGrammar, importSource) import qualified GF.Command.Importing as GF(importGrammar, importSource)
#ifdef C_RUNTIME
import qualified PGF2
#endif
import qualified Control.Monad.Fail as Fail
-- * The SIO monad -- * The SIO monad
@@ -52,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
@@ -117,3 +127,7 @@ lazySIO = lift1 lazyIO
importGrammar pgf opts files = lift0 $ GF.importGrammar pgf opts files importGrammar pgf opts files = lift0 $ GF.importGrammar pgf opts files
importSource opts files = lift0 $ GF.importSource opts files importSource opts files = lift0 $ GF.importSource opts files
#ifdef C_RUNTIME
readPGF2 = lift0 . PGF2.readPGF
#endif

View File

@@ -38,6 +38,7 @@ import Control.Monad(when,liftM,foldM)
import Control.Monad.Trans(MonadIO(..)) import Control.Monad.Trans(MonadIO(..))
import Control.Monad.State(StateT,lift) import Control.Monad.State(StateT,lift)
import Control.Exception(evaluate) import Control.Exception(evaluate)
import Data.List (nub)
--putIfVerb :: MonadIO io => Options -> String -> io () --putIfVerb :: MonadIO io => Options -> String -> io ()
putIfVerb opts msg = when (verbAtLeast opts Verbose) $ putStrLnE msg putIfVerb opts msg = when (verbAtLeast opts Verbose) $ putStrLnE msg
@@ -51,28 +52,32 @@ type FullPath = String
gfLibraryPath = "GF_LIB_PATH" gfLibraryPath = "GF_LIB_PATH"
gfGrammarPathVar = "GF_GRAMMAR_PATH" gfGrammarPathVar = "GF_GRAMMAR_PATH"
getLibraryDirectory :: MonadIO io => Options -> io FilePath getLibraryDirectory :: MonadIO io => Options -> io [FilePath]
getLibraryDirectory opts = getLibraryDirectory opts =
case flag optGFLibPath opts of case flag optGFLibPath opts of
Just path -> return path Just path -> return path
Nothing -> liftIO $ catch (getEnv gfLibraryPath) Nothing -> liftM splitSearchPath $ liftIO (catch (getEnv gfLibraryPath)
(\ex -> fmap (</> "lib") getDataDir) (\ex -> fmap (</> "lib") getDataDir))
getGrammarPath :: MonadIO io => FilePath -> io [FilePath] getGrammarPath :: MonadIO io => [FilePath] -> io [FilePath]
getGrammarPath lib_dir = liftIO $ do getGrammarPath lib_dirs = liftIO $ do
catch (fmap splitSearchPath $ getEnv gfGrammarPathVar) catch (fmap splitSearchPath $ getEnv gfGrammarPathVar)
(\_ -> return [lib_dir </> "alltenses",lib_dir </> "prelude"]) -- e.g. GF_GRAMMAR_PATH (\_ -> return $ concat [[lib_dir </> "alltenses", lib_dir </> "prelude"]
| lib_dir <- lib_dirs ]) -- e.g. GF_GRAMMAR_PATH
-- | extends the search path with the -- | extends the search path with the
-- 'gfLibraryPath' and 'gfGrammarPathVar' -- 'gfLibraryPath' and 'gfGrammarPathVar'
-- environment variables. Returns only existing paths. -- environment variables. Returns only existing paths.
extendPathEnv :: MonadIO io => Options -> io [FilePath] extendPathEnv :: MonadIO io => Options -> io [FilePath]
extendPathEnv opts = liftIO $ do extendPathEnv opts = liftIO $ do
let opt_path = flag optLibraryPath opts -- e.g. paths given as options let opt_path = nub $ flag optLibraryPath opts -- e.g. paths given as options
lib_dir <- getLibraryDirectory opts -- e.g. GF_LIB_PATH lib_dirs <- getLibraryDirectory opts -- e.g. GF_LIB_PATH
grm_path <- getGrammarPath lib_dir -- e.g. GF_GRAMMAR_PATH grm_path <- getGrammarPath lib_dirs -- e.g. GF_GRAMMAR_PATH
let paths = opt_path ++ [lib_dir] ++ grm_path let paths = opt_path ++ lib_dirs ++ grm_path
ps <- liftM concat $ mapM allSubdirs paths when (verbAtLeast opts Verbose) $ putStrLn ("extendPathEnv: opt_path is "++ show opt_path)
when (verbAtLeast opts Verbose) $ putStrLn ("extendPathEnv: lib_dirs is "++ show lib_dirs)
when (verbAtLeast opts Verbose) $ putStrLn ("extendPathEnv: grm_path is "++ show grm_path)
ps <- liftM (nub . concat) $ mapM allSubdirs (nub paths)
mapM canonicalizePath ps mapM canonicalizePath ps
where where
allSubdirs :: FilePath -> IO [FilePath] allSubdirs :: FilePath -> IO [FilePath]
@@ -80,11 +85,15 @@ extendPathEnv opts = liftIO $ do
allSubdirs p = case last p of allSubdirs p = case last p of
'*' -> do let path = init p '*' -> do let path = init p
fs <- getSubdirs path fs <- getSubdirs path
return [path </> f | f <- fs] let starpaths = [path </> f | f <- fs]
when (verbAtLeast opts Verbose) $ putStrLn ("extendPathEnv: allSubdirs: * found "++show starpaths)
return starpaths
_ -> do exists <- doesDirectoryExist p _ -> do exists <- doesDirectoryExist p
if exists if exists
then return [p] then do
else do when (verbAtLeast opts Verbose) $ putStrLn ("ignore path "++p) when (verbAtLeast opts Verbose) $ putStrLn ("extendPathEnv: allSubdirs: found path "++show p)
return [p]
else do when (verbAtLeast opts Verbose) $ putStrLn ("extendPathEnv: allSubdirs: ignore path "++ show p)
return [] return []
getSubdirs :: FilePath -> IO [FilePath] getSubdirs :: FilePath -> IO [FilePath]
@@ -150,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
@@ -161,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

View File

@@ -5,14 +5,14 @@ module GF.Interactive (mainGFI,mainRunGFI,mainServerGFI) where
import Prelude hiding (putStrLn,print) import Prelude hiding (putStrLn,print)
import qualified Prelude as P(putStrLn) import qualified Prelude as P(putStrLn)
import GF.Command.Interpreter(CommandEnv(..),mkCommandEnv,interpretCommandLine) import GF.Command.Interpreter(CommandEnv(..),mkCommandEnv,interpretCommandLine)
import GF.Command.Commands(HasPGF(..),pgfCommands) import GF.Command.Commands(PGFEnv,HasPGFEnv(..),pgf,pgfEnv,pgfCommands)
import GF.Command.CommonCommands(commonCommands,extend) import GF.Command.CommonCommands(commonCommands,extend)
import GF.Command.SourceCommands import GF.Command.SourceCommands
import GF.Command.CommandInfo import GF.Command.CommandInfo
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)
@@ -20,12 +20,15 @@ import GF.Infra.SIO
import GF.Infra.Option import GF.Infra.Option
import qualified System.Console.Haskeline as Haskeline import qualified System.Console.Haskeline as Haskeline
import PGF2 import PGF
import PGF.Internal(abstract,funs,lookStartCat,emptyPGF)
import Data.Char import Data.Char
import Data.List(isPrefixOf) import Data.List(isPrefixOf)
import qualified Data.Map as Map import qualified Data.Map as Map
import qualified Text.ParserCombinators.ReadP as RP import qualified Text.ParserCombinators.ReadP as RP
--import System.IO(utf8)
--import System.CPUTime(getCPUTime)
import System.Directory({-getCurrentDirectory,-}getAppUserDataDirectory) import System.Directory({-getCurrentDirectory,-}getAppUserDataDirectory)
import Control.Exception(SomeException,fromException,evaluate,try) import Control.Exception(SomeException,fromException,evaluate,try)
import Control.Monad.State hiding (void) import Control.Monad.State hiding (void)
@@ -35,6 +38,9 @@ import GF.Server(server)
#endif #endif
import GF.Command.Messages(welcome) import GF.Command.Messages(welcome)
import GF.Infra.UseIO (Output)
-- Provides an orphan instance of MonadFail for StateT in ghc versions < 8
import Control.Monad.Trans.Instances ()
-- | Run the GF Shell in quiet mode (@gf -run@). -- | Run the GF Shell in quiet mode (@gf -run@).
mainRunGFI :: Options -> [FilePath] -> IO () mainRunGFI :: Options -> [FilePath] -> IO ()
@@ -159,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 _ =
@@ -274,19 +280,18 @@ importInEnv opts files =
if flag optRetainResource opts if flag optRetainResource opts
then do src <- lift $ importSource opts files then do src <- lift $ importSource opts files
pgf <- lift . lazySIO $ importPGF pgf0 -- duplicates some work, better to link src pgf <- lift . lazySIO $ importPGF pgf0 -- duplicates some work, better to link src
modify $ \ gfenv -> gfenv {retain=True, pgfenv = (src,pgf)} modify $ \ gfenv -> gfenv {retain=True, pgfenv = (src,pgfEnv pgf)}
else do pgf1 <- lift $ importPGF pgf0 else do pgf1 <- lift $ importPGF pgf0
modify $ \ gfenv->gfenv { retain=False, modify $ \ gfenv->gfenv { retain=False,
pgfenv = (emptyGrammar,pgf1) } pgfenv = (emptyGrammar,pgfEnv pgf1) }
where where
importPGF pgf0 = importPGF pgf0 =
do let opts' = addOptions (setOptimization OptCSE False) opts do let opts' = addOptions (setOptimization OptCSE False) opts
pgf1 <- importGrammar pgf0 opts' files pgf1 <- importGrammar pgf0 opts' files
if (verbAtLeast opts Normal) if (verbAtLeast opts Normal)
then case pgf1 of then putStrLnFlush $
Just pgf -> putStrLnFlush $ unwords $ "\nLanguages:" : Map.keys (languages pgf) unwords $ "\nLanguages:" : map showCId (languages pgf1)
Nothing -> done else return ()
else done
return pgf1 return pgf1
tryGetLine = do tryGetLine = do
@@ -296,12 +301,12 @@ tryGetLine = do
Right l -> return l Right l -> return l
prompt env prompt env
| retain env = "> " | retain env || abs == wildCId = "> "
| otherwise = case multigrammar env of | otherwise = showCId abs ++ "> "
Just pgf -> abstractName pgf ++ "> " where
Nothing -> "> " abs = abstractName (multigrammar env)
type CmdEnv = (Grammar,Maybe PGF) type CmdEnv = (Grammar,PGFEnv)
data GFEnv = GFEnv { data GFEnv = GFEnv {
startOpts :: Options, startOpts :: Options,
@@ -313,10 +318,10 @@ data GFEnv = GFEnv {
emptyGFEnv opts = GFEnv opts False emptyCmdEnv emptyCommandEnv [] emptyGFEnv opts = GFEnv opts False emptyCmdEnv emptyCommandEnv []
emptyCmdEnv = (emptyGrammar,Nothing) emptyCmdEnv = (emptyGrammar,pgfEnv emptyPGF)
emptyCommandEnv = mkCommandEnv allCommands emptyCommandEnv = mkCommandEnv allCommands
multigrammar = snd . pgfenv multigrammar = pgf . snd . pgfenv
allCommands = allCommands =
extend pgfCommands (helpCommand allCommands:moreCommands) extend pgfCommands (helpCommand allCommands:moreCommands)
@@ -324,35 +329,24 @@ allCommands =
`Map.union` commonCommands `Map.union` commonCommands
instance HasGrammar ShellM where getGrammar = gets (fst . pgfenv) instance HasGrammar ShellM where getGrammar = gets (fst . pgfenv)
instance HasPGF ShellM where getPGF = gets (snd . pgfenv) instance HasPGFEnv ShellM where getPGFEnv = gets (snd . pgfenv)
wordCompletion gfenv (left,right) = do wordCompletion gfenv (left,right) = do
case wc_type (reverse left) of case wc_type (reverse left) of
CmplCmd pref CmplCmd pref
-> ret (length pref) [Haskeline.simpleCompletion name | name <- Map.keys (commands cmdEnv), isPrefixOf pref name] -> ret (length pref) [Haskeline.simpleCompletion name | name <- Map.keys (commands cmdEnv), isPrefixOf pref name]
CmplStr (Just (Command _ opts _)) s0 CmplStr (Just (Command _ opts _)) s0
-> case multigrammar gfenv of -> do mb_state0 <- try (evaluate (initState pgf (optLang opts) (optType opts)))
Just pgf -> let langs = languages pgf case mb_state0 of
optLang opts = case valStrOpts "lang" "" opts of Right state0 -> let (rprefix,rs) = break isSpace (reverse s0)
"" -> case Map.minView langs of s = reverse rs
Nothing -> Nothing prefix = reverse rprefix
Just (concr,_) -> Just concr ws = words s
lang -> mplus (Map.lookup lang langs) in case loop state0 ws of
(Map.lookup (abstractName pgf ++ lang) langs) Nothing -> ret 0 []
optType opts = let readOpt str = case readType str of Just state -> let compls = getCompletions state prefix
Just ty -> case checkType pgf ty of in ret (length prefix) (map (\x -> Haskeline.simpleCompletion x) (Map.keys compls))
Left _ -> Nothing Left (_ :: SomeException) -> ret 0 []
Right ty -> Just ty
Nothing -> Nothing
in maybeStrOpts "cat" (Just (startCat pgf)) readOpt opts
(rprefix,rs) = break isSpace (reverse s0)
s = reverse rs
prefix = reverse rprefix
in case (optLang opts, optType opts) of
(Just lang,Just cat) -> let compls = [t | (t,_,_,_) <- complete lang cat s prefix]
in ret (length prefix) (map Haskeline.simpleCompletion compls)
_ -> ret 0 []
Nothing -> ret 0 []
CmplOpt (Just (Command n _ _)) pref CmplOpt (Just (Command n _ _)) pref
-> case Map.lookup n (commands cmdEnv) of -> case Map.lookup n (commands cmdEnv) of
Just inf -> do let flg_compls = [Haskeline.Completion ('-':flg++"=") ('-':flg) False | (flg,_) <- flags inf, isPrefixOf pref flg] Just inf -> do let flg_compls = [Haskeline.Completion ('-':flg++"=") ('-':flg) False | (flg,_) <- flags inf, isPrefixOf pref flg]
@@ -363,15 +357,23 @@ wordCompletion gfenv (left,right) = do
CmplIdent (Just (Command "i" _ _)) _ -- HACK: file name completion for command i CmplIdent (Just (Command "i" _ _)) _ -- HACK: file name completion for command i
-> Haskeline.completeFilename (left,right) -> Haskeline.completeFilename (left,right)
CmplIdent _ pref CmplIdent _ pref
-> case multigrammar gfenv of -> do mb_abs <- try (evaluate (abstract pgf))
Just pgf -> ret (length pref) [Haskeline.simpleCompletion name | name <- functions pgf, isPrefixOf pref name] case mb_abs of
Nothing -> ret (length pref) [] Right abs -> ret (length pref) [Haskeline.simpleCompletion name | cid <- Map.keys (funs abs), let name = showCId cid, isPrefixOf pref name]
Left (_ :: SomeException) -> ret (length pref) []
_ -> ret 0 [] _ -> ret 0 []
where where
pgf = multigrammar gfenv
cmdEnv = commandenv gfenv cmdEnv = commandenv gfenv
optLang opts = valCIdOpts "lang" (head (languages pgf)) opts
optType opts =
let str = valStrOpts "cat" (showCId $ lookStartCat pgf) opts
in case readType str of
Just ty -> ty
Nothing -> error ("Can't parse '"++str++"' as type")
loop ps [] = Just ps loop ps [] = Just ps
loop ps (t:ts) = case error "nextState ps (simpleParseInput t)" of loop ps (t:ts) = case nextState ps (simpleParseInput t) of
Left es -> Nothing Left es -> Nothing
Right ps -> loop ps ts Right ps -> loop ps ts

View File

@@ -0,0 +1,442 @@
{-# LANGUAGE CPP, ScopedTypeVariables, TypeSynonymInstances, FlexibleInstances, FlexibleContexts #-}
-- | GF interactive mode (with the C run-time system)
module GF.Interactive2 (mainGFI,mainRunGFI{-,mainServerGFI-}) where
import Prelude hiding (putStrLn,print)
import qualified Prelude as P(putStrLn)
import GF.Command.Interpreter(CommandEnv(..),commands,mkCommandEnv,interpretCommandLine)
import GF.Command.Commands2(PGFEnv,HasPGFEnv(..),pgf,concs,pgfEnv,emptyPGFEnv,pgfCommands)
import GF.Command.CommonCommands
import GF.Command.CommandInfo
import GF.Command.Help(helpCommand)
import GF.Command.Abstract
import GF.Command.Parse(readCommandLine,pCommand)
import GF.Data.Operations (Err(..))
import GF.Data.Utilities(whenM,repeatM)
import GF.Infra.UseIO(ioErrorText,putStrLnE)
import GF.Infra.SIO
import GF.Infra.Option
import qualified System.Console.Haskeline as Haskeline
import qualified PGF2 as C
import qualified PGF as H
import Data.Char
import Data.List(isPrefixOf)
import qualified Data.Map as Map
import qualified Text.ParserCombinators.ReadP as RP
--import System.IO(utf8)
--import System.CPUTime(getCPUTime)
import System.Directory({-getCurrentDirectory,-}getAppUserDataDirectory)
import System.FilePath(takeExtensions)
import Control.Exception(SomeException,fromException,try)
--import Control.Monad
import Control.Monad.State hiding (void)
import qualified GF.System.Signal as IO(runInterruptibly)
{-
#ifdef SERVER_MODE
import GF.Server(server)
#endif
-}
import GF.Command.Messages(welcome)
-- | Run the GF Shell in quiet mode (@gf -run@).
mainRunGFI :: Options -> [FilePath] -> IO ()
mainRunGFI opts files = shell (beQuiet opts) files
beQuiet = addOptions (modifyFlags (\f -> f{optVerbosity=Quiet}))
-- | Run the interactive GF Shell
mainGFI :: Options -> [FilePath] -> IO ()
mainGFI opts files = do
P.putStrLn welcome
P.putStrLn "This shell uses the C run-time system. See help for available commands."
shell opts files
shell opts files = flip evalStateT (emptyGFEnv opts) $
do mapStateT runSIO $ importInEnv opts files
loop
{-
#ifdef SERVER_MODE
-- | Run the GF Server (@gf -server@).
-- The 'Int' argument is the port number for the HTTP service.
mainServerGFI opts0 port files =
server jobs port root (execute1 opts)
=<< runSIO (importInEnv (emptyGFEnv opts) opts files)
where
root = flag optDocumentRoot opts
opts = beQuiet opts0
jobs = join (flag optJobs opts)
#else
mainServerGFI opts port files =
error "GF has not been compiled with server mode support"
#endif
-}
-- | Read end execute commands until it is time to quit
loop :: StateT GFEnv IO ()
loop = repeatM readAndExecute1
-- | Read and execute one command, returning 'True' to continue execution,
-- | 'False' when it is time to quit
readAndExecute1 :: StateT GFEnv IO Bool
readAndExecute1 = mapStateT runSIO . execute1 =<< readCommand
-- | Read a command
readCommand :: StateT GFEnv IO String
readCommand =
do opts <- gets startOpts
case flag optMode opts of
ModeRun -> lift tryGetLine
_ -> lift . fetchCommand =<< get
timeIt act =
do t1 <- liftSIO $ getCPUTime
a <- act
t2 <- liftSIO $ getCPUTime
return (t2-t1,a)
-- | Optionally show how much CPU time was used to run an IO action
optionallyShowCPUTime :: (Monad m,MonadSIO m) => Options -> m a -> m a
optionallyShowCPUTime opts act
| not (verbAtLeast opts Normal) = act
| otherwise = do (dt,r) <- timeIt act
liftSIO $ putStrLnFlush $ show (dt `div` 1000000000) ++ " msec"
return r
type ShellM = StateT GFEnv SIO
-- | Execute a given command line, returning 'True' to continue execution,
-- | 'False' when it is time to quit
execute1 :: String -> ShellM Bool
execute1 s0 =
do modify $ \ gfenv0 -> gfenv0 {history = s0 : history gfenv0}
execute1' s0
-- | Execute a given command line, without adding it to the history
execute1' s0 =
do opts <- gets startOpts
interruptible $ optionallyShowCPUTime opts $
case pwords s0 of
-- cc, sd, so, ss and dg are now in GF.Commands.SourceCommands
-- special commands
"q" :_ -> quit
"!" :ws -> system_command ws
"eh":ws -> execute_history ws
"i" :ws -> do import_ ws; continue
-- other special commands, working on GFEnv
"dc":ws -> define_command ws
"dt":ws -> define_tree ws
-- ordinary commands
_ -> do env <- gets commandenv
interpretCommandLine env s0
continue
where
continue,stop :: ShellM Bool
continue = return True
stop = return False
interruptible :: ShellM Bool -> ShellM Bool
interruptible act =
do gfenv <- get
mapStateT (
either (\e -> printException e >> return (True,gfenv)) return
<=< runInterruptibly) act
-- Special commands:
quit = do opts <- gets startOpts
when (verbAtLeast opts Normal) $ putStrLnE "See you."
stop
system_command ws = do lift $ restrictedSystem $ unwords ws ; continue
{-"eh":w:_ -> do
cs <- readFile w >>= return . map words . lines
gfenv' <- foldM (flip (process False benv)) gfenv cs
loopNewCPU gfenv' -}
execute_history [w] =
do execute . lines =<< lift (restricted (readFile w))
continue
where
execute :: [String] -> ShellM ()
execute [] = return ()
execute (line:lines) = whenM (execute1' line) (execute lines)
execute_history _ =
do putStrLnE "eh command not parsed"
continue
define_command (f:ws) =
case readCommandLine (unwords ws) of
Just comm ->
do modify $
\ gfenv ->
let env = commandenv gfenv
in gfenv {
commandenv = env {
commandmacros = Map.insert f comm (commandmacros env)
}
}
continue
_ -> dc_not_parsed
define_command _ = dc_not_parsed
dc_not_parsed = putStrLnE "command definition not parsed" >> continue
define_tree (f:ws) =
case H.readExpr (unwords ws) of
Just exp ->
do modify $
\ gfenv ->
let env = commandenv gfenv
in gfenv { commandenv = env {
expmacros = Map.insert f exp (expmacros env) } }
continue
_ -> dt_not_parsed
define_tree _ = dt_not_parsed
dt_not_parsed = putStrLnE "value definition not parsed" >> continue
pwords s = case words s of
w:ws -> getCommandOp w :ws
ws -> ws
import_ args =
do case parseOptions args of
Ok (opts',files) -> do
opts <- gets startOpts
curr_dir <- lift getCurrentDirectory
lib_dir <- lift $ getLibraryDirectory (addOptions opts opts')
importInEnv (addOptions opts (fixRelativeLibPaths curr_dir lib_dir opts')) files
Bad err ->
do putStrLnE $ "Command parse error: " ++ err
-- | Commands that work on 'GFEnv'
moreCommands = [
("e", emptyCommandInfo {
longname = "empty",
synopsis = "empty the environment (except the command history)",
exec = \ _ _ ->
do modify $ \ gfenv -> (emptyGFEnv (startOpts gfenv))
{ history=history gfenv }
return void
}),
("ph", emptyCommandInfo {
longname = "print_history",
synopsis = "print command history",
explanation = unlines [
"Prints the commands issued during the GF session.",
"The result is readable by the eh command.",
"The result can be used as a script when starting GF."
],
examples = [
mkEx "ph | wf -file=foo.gfs -- save the history into a file"
],
exec = \ _ _ ->
fmap (fromString . unlines . reverse . drop 1 . history) get
}),
("r", emptyCommandInfo {
longname = "reload",
synopsis = "repeat the latest import command",
exec = \ _ _ ->
do gfenv0 <- get
let imports = [(s,ws) | s <- history gfenv0, ("i":ws) <- [pwords s]]
case imports of
(s,ws):_ -> do
putStrLnE $ "repeating latest import: " ++ s
import_ ws
_ -> do
putStrLnE $ "no import in history"
return void
})
]
printException e = maybe (print e) (putStrLn . ioErrorText) (fromException e)
fetchCommand :: GFEnv -> IO String
fetchCommand gfenv = do
path <- getAppUserDataDirectory "gf_history"
let settings =
Haskeline.Settings {
Haskeline.complete = wordCompletion gfenv,
Haskeline.historyFile = Just path,
Haskeline.autoAddHistory = True
}
res <- IO.runInterruptibly $ Haskeline.runInputT settings (Haskeline.getInputLine (prompt gfenv))
case res of
Left _ -> return ""
Right Nothing -> return "q"
Right (Just s) -> return s
importInEnv :: Options -> [FilePath] -> ShellM ()
importInEnv opts files =
case files of
_ | flag optRetainResource opts ->
putStrLnE "Flag -retain is not supported in this shell"
[file] | takeExtensions file == ".pgf" -> importPGF file
[] -> return ()
_ -> do putStrLnE "Can only import one .pgf file"
where
importPGF file =
do gfenv <- get
case multigrammar gfenv of
Just _ -> putStrLnE "Discarding previous grammar"
_ -> return ()
pgf1 <- lift $ readPGF2 file
let gfenv' = gfenv { pgfenv = pgfEnv pgf1 }
when (verbAtLeast opts Normal) $
let langs = Map.keys . concretes $ gfenv'
in putStrLnE . unwords $ "\nLanguages:":langs
put gfenv'
tryGetLine = do
res <- try getLine
case res of
Left (e :: SomeException) -> return "q"
Right l -> return l
prompt env = abs ++ "> "
where
abs = maybe "" C.abstractName (multigrammar env)
data GFEnv = GFEnv {
startOpts :: Options,
--grammar :: (), -- gfo grammar -retain
--retain :: (), -- grammar was imported with -retain flag
pgfenv :: PGFEnv,
commandenv :: CommandEnv ShellM,
history :: [String]
}
emptyGFEnv opts = GFEnv opts {-() ()-} emptyPGFEnv emptyCommandEnv []
emptyCommandEnv = mkCommandEnv allCommands
multigrammar = pgf . pgfenv
concretes = concs . pgfenv
allCommands =
extend pgfCommands (helpCommand allCommands:moreCommands)
`Map.union` commonCommands
instance HasPGFEnv ShellM where getPGFEnv = gets pgfenv
-- ** Completion
wordCompletion gfenv (left,right) = do
case wc_type (reverse left) of
CmplCmd pref
-> ret (length pref) [Haskeline.simpleCompletion name | name <- Map.keys (commands cmdEnv), isPrefixOf pref name]
{-
CmplStr (Just (Command _ opts _)) s0
-> do mb_state0 <- try (evaluate (H.initState pgf (optLang opts) (optType opts)))
case mb_state0 of
Right state0 -> let (rprefix,rs) = break isSpace (reverse s0)
s = reverse rs
prefix = reverse rprefix
ws = words s
in case loop state0 ws of
Nothing -> ret 0 []
Just state -> let compls = H.getCompletions state prefix
in ret (length prefix) (map (\x -> Haskeline.simpleCompletion x) (Map.keys compls))
Left (_ :: SomeException) -> ret 0 []
-}
CmplOpt (Just (Command n _ _)) pref
-> case Map.lookup n (commands cmdEnv) of
Just inf -> do let flg_compls = [Haskeline.Completion ('-':flg++"=") ('-':flg) False | (flg,_) <- flags inf, isPrefixOf pref flg]
opt_compls = [Haskeline.Completion ('-':opt) ('-':opt) True | (opt,_) <- options inf, isPrefixOf pref opt]
ret (length pref+1)
(flg_compls++opt_compls)
Nothing -> ret (length pref) []
CmplIdent (Just (Command "i" _ _)) _ -- HACK: file name completion for command i
-> Haskeline.completeFilename (left,right)
CmplIdent _ pref
-> case mb_pgf of
Just pgf -> ret (length pref)
[Haskeline.simpleCompletion name
| name <- C.functions pgf,
isPrefixOf pref name]
_ -> ret (length pref) []
_ -> ret 0 []
where
mb_pgf = multigrammar gfenv
cmdEnv = commandenv gfenv
{-
optLang opts = valStrOpts "lang" (head $ Map.keys (concretes cmdEnv)) opts
optType opts =
let str = valStrOpts "cat" (H.showCId $ H.lookStartCat pgf) opts
in case H.readType str of
Just ty -> ty
Nothing -> error ("Can't parse '"++str++"' as type")
loop ps [] = Just ps
loop ps (t:ts) = case H.nextState ps (H.simpleParseInput t) of
Left es -> Nothing
Right ps -> loop ps ts
-}
ret len xs = return (drop len left,xs)
data CompletionType
= CmplCmd Ident
| CmplStr (Maybe Command) String
| CmplOpt (Maybe Command) Ident
| CmplIdent (Maybe Command) Ident
deriving Show
wc_type :: String -> CompletionType
wc_type = cmd_name
where
cmd_name cs =
let cs1 = dropWhile isSpace cs
in go cs1 cs1
where
go x [] = CmplCmd x
go x (c:cs)
| isIdent c = go x cs
| otherwise = cmd x cs
cmd x [] = ret CmplIdent x "" 0
cmd _ ('|':cs) = cmd_name cs
cmd _ (';':cs) = cmd_name cs
cmd x ('"':cs) = str x cs cs
cmd x ('-':cs) = option x cs cs
cmd x (c :cs)
| isIdent c = ident x (c:cs) cs
| otherwise = cmd x cs
option x y [] = ret CmplOpt x y 1
option x y ('=':cs) = optValue x y cs
option x y (c :cs)
| isIdent c = option x y cs
| otherwise = cmd x cs
optValue x y ('"':cs) = str x y cs
optValue x y cs = cmd x cs
ident x y [] = ret CmplIdent x y 0
ident x y (c:cs)
| isIdent c = ident x y cs
| otherwise = cmd x cs
str x y [] = ret CmplStr x y 1
str x y ('\"':cs) = cmd x cs
str x y ('\\':c:cs) = str x y cs
str x y (c:cs) = str x y cs
ret f x y d = f cmd y
where
x1 = take (length x - length y - d) x
x2 = takeWhile (\c -> isIdent c || isSpace c || c == '-' || c == '=' || c == '"') x1
cmd = case [x | (x,cs) <- RP.readP_to_S pCommand x2, all isSpace cs] of
[x] -> Just x
_ -> Nothing
isIdent c = c == '_' || c == '\'' || isAlphaNum c

View File

@@ -2,7 +2,10 @@
{-# LANGUAGE CPP #-} {-# LANGUAGE CPP #-}
module GF.Main where module GF.Main where
import GF.Compiler import GF.Compiler
import GF.Interactive import qualified GF.Interactive as GFI1
#ifdef C_RUNTIME
import qualified GF.Interactive2 as GFI2
#endif
import GF.Data.ErrM import GF.Data.ErrM
import GF.Infra.Option import GF.Infra.Option
import GF.Infra.UseIO import GF.Infra.UseIO
@@ -44,7 +47,17 @@ mainOpts opts files =
case flag optMode opts of case flag optMode opts of
ModeVersion -> putStrLn $ "Grammatical Framework (GF) version " ++ showVersion version ++ "\n" ++ buildInfo ModeVersion -> putStrLn $ "Grammatical Framework (GF) version " ++ showVersion version ++ "\n" ++ buildInfo
ModeHelp -> putStrLn helpMessage ModeHelp -> putStrLn helpMessage
ModeServer port -> mainServerGFI opts port files ModeServer port -> GFI1.mainServerGFI opts port files
ModeCompiler -> mainGFC opts files ModeCompiler -> mainGFC opts files
ModeInteractive -> mainGFI opts files ModeInteractive -> GFI1.mainGFI opts files
ModeRun -> mainRunGFI opts files ModeRun -> GFI1.mainRunGFI opts files
#ifdef C_RUNTIME
ModeInteractive2 -> GFI2.mainGFI opts files
ModeRun2 -> GFI2.mainRunGFI opts files
#else
ModeInteractive2 -> noCruntime
ModeRun2 -> noCruntime
where
noCruntime = do ePutStrLn "GF configured without C run-time support"
exitFailure
#endif

View File

@@ -18,8 +18,13 @@ module GF.Quiz (
morphologyList morphologyList
) where ) where
import PGF2 import PGF
--import PGF.Linearize
import GF.Data.Operations import GF.Data.Operations
--import GF.Infra.UseIO
--import GF.Infra.Option
--import PGF.Probabilistic
import System.Random import System.Random
import Data.List (nub) import Data.List (nub)
@@ -33,7 +38,7 @@ mkQuiz msg tts = do
teachDialogue qas msg teachDialogue qas msg
translationList :: translationList ::
Maybe Expr -> PGF -> Concr -> Concr -> Type -> Int -> IO [(String,[String])] Maybe Expr -> PGF -> Language -> Language -> Type -> Int -> IO [(String,[String])]
translationList mex pgf ig og typ number = do translationList mex pgf ig og typ number = do
gen <- newStdGen gen <- newStdGen
let ts = take number $ case mex of let ts = take number $ case mex of
@@ -41,22 +46,19 @@ translationList mex pgf ig og typ number = do
Nothing -> generateRandom gen pgf typ Nothing -> generateRandom gen pgf typ
return $ map mkOne $ ts return $ map mkOne $ ts
where where
mkOne t = (norml (linearize ig t), mkOne t = (norml (linearize pgf ig t),
map norml (concatMap lins (homonyms t))) map norml (concatMap lins (homonyms t)))
homonyms t = homonyms = parse pgf ig typ . linearize pgf ig
case (parse ig typ . linearize ig) t of lins = nub . concatMap (map snd) . tabularLinearizes pgf og
ParseOk res -> map fst res
_ -> []
lins = nub . concatMap (map snd) . tabularLinearizeAll og
morphologyList :: morphologyList ::
Maybe Expr -> PGF -> Concr -> Type -> Int -> IO [(String,[String])] Maybe Expr -> PGF -> Language -> Type -> Int -> IO [(String,[String])]
morphologyList mex pgf ig typ number = do morphologyList mex pgf ig typ number = do
gen <- newStdGen gen <- newStdGen
let ts = take (max 1 number) $ case mex of let ts = take (max 1 number) $ case mex of
Just ex -> generateRandomFrom gen pgf ex Just ex -> generateRandomFrom gen pgf ex
Nothing -> generateRandom gen pgf typ Nothing -> generateRandom gen pgf typ
let ss = map (tabularLinearizeAll ig) ts let ss = map (tabularLinearizes pgf ig) ts
let size = length (head (head ss)) let size = length (head (head ss))
let forms = take number $ randomRs (0,size-1) gen let forms = take number $ randomRs (0,size-1) gen
return [(snd (head pws0) +++ fst (pws0 !! i), ws) | return [(snd (head pws0) +++ fst (pws0 !! i), ws) |

View File

@@ -3,6 +3,7 @@
module GF.Server(server) where module GF.Server(server) where
import Data.List(partition,stripPrefix,isInfixOf) import Data.List(partition,stripPrefix,isInfixOf)
import qualified Data.Map as M import qualified Data.Map as M
import Control.Applicative -- for GHC<7.10
import Control.Monad(when) import Control.Monad(when)
import Control.Monad.State(StateT(..),get,gets,put) import Control.Monad.State(StateT(..),get,gets,put)
import Control.Monad.Error(ErrorT(..),Error(..)) import Control.Monad.Error(ErrorT(..),Error(..))
@@ -33,7 +34,7 @@ import Network.Shed.Httpd(initServer,Request(..),Response(..),noCache)
--import qualified Network.FastCGI as FCGI -- from hackage direct-fastcgi --import qualified Network.FastCGI as FCGI -- from hackage direct-fastcgi
import Network.CGI(handleErrors,liftIO) import Network.CGI(handleErrors,liftIO)
import CGIUtils(handleCGIErrors)--,outputJSONP,stderrToFile import CGIUtils(handleCGIErrors)--,outputJSONP,stderrToFile
import Text.JSON(encode,showJSON,makeObj) import Text.JSON(JSValue(..),Result(..),valFromObj,encode,decode,showJSON,makeObj)
--import System.IO.Silently(hCapture) --import System.IO.Silently(hCapture)
import System.Process(readProcessWithExitCode) import System.Process(readProcessWithExitCode)
import System.Exit(ExitCode(..)) import System.Exit(ExitCode(..))
@@ -42,6 +43,7 @@ import GF.Infra.UseIO(readBinaryFile,writeBinaryFile,ePutStrLn)
import GF.Infra.SIO(captureSIO) import GF.Infra.SIO(captureSIO)
import GF.Data.Utilities(apSnd,mapSnd) import GF.Data.Utilities(apSnd,mapSnd)
import qualified PGFService as PS import qualified PGFService as PS
import qualified ExampleService as ES
import Data.Version(showVersion) import Data.Version(showVersion)
import Paths_gf(getDataDir,version) import Paths_gf(getDataDir,version)
import GF.Infra.BuildInfo (buildInfo) import GF.Infra.BuildInfo (buildInfo)
@@ -169,6 +171,7 @@ handle logLn documentroot state0 cache execute1 stateVar
(_ ,_ ,".pgf") -> do --debug $ "PGF service: "++path (_ ,_ ,".pgf") -> do --debug $ "PGF service: "++path
wrapCGI $ PS.cgiMain' cache path wrapCGI $ PS.cgiMain' cache path
(dir,"grammars.cgi",_ ) -> grammarList dir (decoded qs) (dir,"grammars.cgi",_ ) -> grammarList dir (decoded qs)
(dir ,"exb.fcgi" ,_ ) -> wrapCGI $ ES.cgiMain' root dir (PS.pgfCache cache)
_ -> serveStaticFile rpath path _ -> serveStaticFile rpath path
where path = translatePath rpath where path = translatePath rpath
_ -> return $ resp400 upath _ -> return $ resp400 upath
@@ -177,7 +180,7 @@ handle logLn documentroot state0 cache execute1 stateVar
translatePath rpath = root</>rpath -- hmm, check for ".." translatePath rpath = root</>rpath -- hmm, check for ".."
versionInfo c = versionInfo (c1,c2) =
html200 . unlines $ html200 . unlines $
"<!DOCTYPE html>": "<!DOCTYPE html>":
"<meta name = \"viewport\" content = \"width = device-width\">": "<meta name = \"viewport\" content = \"width = device-width\">":
@@ -185,7 +188,8 @@ handle logLn documentroot state0 cache execute1 stateVar
"": "":
("<h2>"++hdr++"</h2>"): ("<h2>"++hdr++"</h2>"):
(zipWith (++) ("<p>":repeat "<br>") buildinfo)++ (zipWith (++) ("<p>":repeat "<br>") buildinfo)++
sh "Run-time system" c sh "Haskell run-time system" c1++
sh "C run-time system" c2
where where
hdr:buildinfo = lines gf_version hdr:buildinfo = lines gf_version
rel = makeRelative documentroot rel = makeRelative documentroot
@@ -280,13 +284,17 @@ handle logLn documentroot state0 cache execute1 stateVar
skip_empty = filter (not.null.snd) skip_empty = filter (not.null.snd)
jsonList = jsonList' return jsonList = jsonList' return
jsonListLong = jsonList' (mapM addTime) jsonListLong ext = jsonList' (mapM (addTime ext)) ext
jsonList' details ext = fmap (json200) (details =<< ls_ext "." ext) jsonList' details ext = fmap (json200) (details =<< ls_ext "." ext)
addTime path = addTime ext path =
do t <- getModificationTime path do t <- getModificationTime path
return $ makeObj ["path".=path,"time".=format t] if ext==".json"
then addComment (time t) <$> liftIO (try $ getComment path)
else return . makeObj $ time t
where where
addComment t = makeObj . either (const t) (\c->t++["comment".=c])
time t = ["path".=path,"time".=format t]
format = formatTime defaultTimeLocale rfc822DateFormat format = formatTime defaultTimeLocale rfc822DateFormat
rm path | takeExtension path `elem` ok_to_delete = rm path | takeExtension path `elem` ok_to_delete =
@@ -328,6 +336,11 @@ handle logLn documentroot state0 cache execute1 stateVar
do paths <- getDirectoryContents dir do paths <- getDirectoryContents dir
return [path | path<-paths, takeExtension path==ext] return [path | path<-paths, takeExtension path==ext]
getComment path =
do Ok (JSObject obj) <- decode <$> readFile path
Ok cmnt <- return (valFromObj "comment" obj)
return (cmnt::String)
-- * Dynamic content -- * Dynamic content
jsonresult cwd dir cmd (ecode,stdout,stderr) files = jsonresult cwd dir cmd (ecode,stdout,stderr) files =

View File

@@ -14,6 +14,7 @@ import qualified Data.Map as Map
import Data.Set (Set) import Data.Set (Set)
import qualified Data.Set as Set import qualified Data.Set as Set
import PGF.Internal
import GF.Data.Utilities import GF.Data.Utilities
import GF.Grammar.CFG import GF.Grammar.CFG
--import GF.Speech.PGFToCFG --import GF.Speech.PGFToCFG

View File

@@ -7,12 +7,15 @@
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
module GF.Speech.GSL (gslPrinter) where module GF.Speech.GSL (gslPrinter) where
import Prelude hiding ((<>)) -- GHC 8.4.1 clash with Text.PrettyPrint
--import GF.Data.Utilities
import GF.Grammar.CFG import GF.Grammar.CFG
import GF.Speech.SRG import GF.Speech.SRG
import GF.Speech.RegExp import GF.Speech.RegExp
import GF.Infra.Option import GF.Infra.Option
import PGF2 --import GF.Infra.Ident
import PGF
import Data.Char (toUpper,toLower) import Data.Char (toUpper,toLower)
import Data.List (partition) import Data.List (partition)
@@ -21,7 +24,7 @@ import GF.Text.Pretty
width :: Int width :: Int
width = 75 width = 75
gslPrinter :: Options -> PGF -> Concr -> String gslPrinter :: Options -> PGF -> CId -> String
gslPrinter opts pgf cnc = renderStyle st $ prGSL $ makeNonLeftRecursiveSRG opts pgf cnc gslPrinter opts pgf cnc = renderStyle st $ prGSL $ makeNonLeftRecursiveSRG opts pgf cnc
where st = style { lineLength = width } where st = style { lineLength = width }

View File

@@ -11,6 +11,7 @@
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
module GF.Speech.JSGF (jsgfPrinter) where module GF.Speech.JSGF (jsgfPrinter) where
import Prelude hiding ((<>)) -- GHC 8.4.1 clash with Text.PrettyPrint
--import GF.Data.Utilities --import GF.Data.Utilities
import GF.Infra.Option import GF.Infra.Option
@@ -18,7 +19,7 @@ import GF.Grammar.CFG
import GF.Speech.RegExp import GF.Speech.RegExp
import GF.Speech.SISR import GF.Speech.SISR
import GF.Speech.SRG import GF.Speech.SRG
import PGF2 import PGF
import Data.Char import Data.Char
import Data.List import Data.List
@@ -30,8 +31,8 @@ width :: Int
width = 75 width = 75
jsgfPrinter :: Options jsgfPrinter :: Options
-> PGF -> PGF
-> Concr -> String -> CId -> String
jsgfPrinter opts pgf cnc = renderStyle st $ prJSGF sisr $ makeNonLeftRecursiveSRG opts pgf cnc jsgfPrinter opts pgf cnc = renderStyle st $ prJSGF sisr $ makeNonLeftRecursiveSRG opts pgf cnc
where st = style { lineLength = width } where st = style { lineLength = width }
sisr = flag optSISR opts sisr = flag optSISR opts

View File

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

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