Compare commits

..

1273 Commits

Author SHA1 Message Date
Krasimir Angelov
3ee4f6ce9c added MonadFix and fix how return is defined 2025-11-13 10:58:16 +01:00
Krasimir Angelov
b480ead393 pretty printing for VPatt 2025-10-14 08:43:29 +02:00
Krasimir Angelov
72028c7ae7 merge 2025-09-17 10:17:37 +02:00
Krasimir Angelov
09e98ed323 Merge pull request #180 from phantamanta44/majestic
majestic: fix bubbling + type annotations for option metadata
2025-06-08 09:28:00 +02:00
Eve
f64d6b045b Revert bubble re-implementation 2025-05-26 18:21:04 +02:00
Eve
9c422c8224 Type annotations for option labels + new bubble impl 2025-05-26 18:16:49 +02:00
Eve
6429ed7148 Choice-splitting versions of mapVariants and mapConstVs 2025-05-26 18:13:11 +02:00
Krasimir Angelov
e54f748efa serialization for Markup and Reset 2025-05-18 07:08:11 +02:00
Krasimir Angelov
03421f6bc7 fix in the typechecking of one and default 2025-05-09 19:15:28 +02:00
Krasimir Angelov
d54fab0bbf fix typo 2025-05-09 19:10:51 +02:00
Krasimir Angelov
3d7c8ade17 a draft for the generalized control operators 2025-05-09 18:58:27 +02:00
Krasimir Angelov
544bbd9049 special handling for empty variants in the bubbling 2025-05-05 11:46:50 +02:00
Krasimir Angelov
d5e3e8f649 whitespace 2025-05-03 07:32:06 +02:00
Krasimir Angelov
4c0644fd55 another bug in the typechecker 2025-05-03 07:31:44 +02:00
Krasimir Angelov
188b77b083 improvement on the typechecker 2025-05-02 13:52:17 +02:00
Krasimir Angelov
dbfa9e4faf type inference for lambda abstractions 2025-04-16 12:29:50 +02:00
Krasimir Angelov
a9d4fecd33 added export for EPatt 2025-04-15 08:40:30 +02:00
Krasimir Angelov
cc4d07f168 Export a grammar in source format to JSON 2025-04-14 11:16:27 +02:00
Krasimir Angelov
3432e6f571 serialization for expressions in daison 2025-04-13 08:36:25 +02:00
Krasimir Angelov
c2d64efe68 cannonical export now may contain some resource modules with parameters 2025-04-11 10:47:43 +02:00
Krasimir Angelov
aa3a03e7af Merge pull request #179 from phantamanta44/majestic
majestic: predef evaluation + option..of construct
2025-04-06 17:25:16 +02:00
Krasimir Angelov
f0b42f4783 Merge pull request #178 from EkaterinaVoloshina/majestic
Create ServerInstructions.md
2025-03-31 19:07:43 +02:00
Eve
b29ec2a47a Option evaluation + basic repl support for option manipulation 2025-03-31 17:56:36 +02:00
Eve
8bd0d13dd6 Port builtin improvements to new evaluator + opt parsing 2025-03-31 17:54:06 +02:00
Eve
3de005f11c Replace open term check for predefs with canonical term check 2025-03-31 17:54:06 +02:00
Eve
223604526e Better predef evaluation semantics, avoid value2term 2025-03-31 17:54:06 +02:00
Ekaterina Voloshina
2361adad93 Create ServerInstructions.md 2025-03-31 13:35:15 +02:00
Krasimir Angelov
c95a526ca9 missed to add the JSON file 2025-03-27 14:29:38 +01:00
Krasimir Angelov
5dcd1108c7 take into account the result type during overload reasolution 2025-03-27 14:28:42 +01:00
Krasimir Angelov
e6c4775ade the JSON dump now supports the entire GF language 2025-03-26 14:56:08 +01:00
Krasimir Angelov
65e4ca309c Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2025-03-21 07:02:23 +01:00
Krasimir Angelov
4c24fc904d another case for evaluation under a table 2025-03-21 07:00:58 +01:00
Inari Listenmaa
945cd65220 Merge pull request #176 from EkaterinaVoloshina/patch-1
excluded outdated info
2025-03-20 17:40:02 +01:00
Ekaterina Voloshina
3c5c8424e0 excluded outdated info 2025-03-20 17:38:14 +01:00
Krasimir Angelov
81d472235a function application under tables 2025-03-20 16:06:33 +01:00
Krasimir Angelov
b0d363c311 added missing cases 2025-03-17 19:06:41 +01:00
Krasimir Angelov
a7c0be2fd5 fix typo 2025-03-14 07:38:33 +00:00
Krasimir Angelov
b008aa7de0 sketch an implementation for reset 2025-03-13 19:01:18 +00:00
Krasimir Angelov
271991ef10 added missing cases for VMarkup 2025-03-10 16:38:18 +00:00
Krasimir Angelov
e59ae98aa1 export bubble 2025-03-10 16:08:55 +00:00
Krasimir Angelov
88ae6bff71 added missing case for VCRecType 2025-03-10 14:42:36 +00:00
Krasimir Angelov
22a22aacbb added evaluation for markup 2025-03-10 14:26:51 +00:00
Krasimir Angelov
854739eee4 support for non-flat forms 2025-03-10 15:22:59 +01:00
Krasimir Angelov
16f9f86248 start using the new typechecker and evaluator in the cc command 2025-03-10 15:22:31 +01:00
Krasimir Angelov
084ffa1ce9 fix quantification 2025-03-08 12:42:46 +00:00
Krasimir Angelov
344481634f the pure evaluator 2025-03-07 23:27:05 +00:00
Krasimir Angelov
364c8c023c switch to using pure functional evaluator 2025-03-07 20:50:28 +00:00
Krasimir Angelov
c9aadf7382 added missing case 2025-03-07 08:57:55 +01:00
Krasimir Angelov
d97292cfd4 AC_PROG_LIBTOOL not necessary anymore 2025-03-07 08:57:11 +01:00
Krasimir Angelov
84fa6522de bump upper version of the network package 2025-02-26 12:06:29 +00:00
Krasimir Angelov
176dcdf2fa import liftA2 2025-02-25 12:31:05 +00:00
Krasimir Angelov
a501784a32 Merge pull request #173 from phantamanta44/majestic
majestic: Type-checking improvements + unifying overload resolution + simple REPL
2025-02-25 13:05:00 +01:00
Eve
19c5b410f2 Predef combinators 2025-02-21 15:25:25 +01:00
Eve
815dfcc2fc Unification for function types 2025-02-15 23:07:29 +01:00
Eve
265db698ac Dereference metavariables in types before structural inspections 2025-02-15 22:27:06 +01:00
Eve
b4b9974d54 More comprehensive open term check for builtin eval 2025-02-09 16:53:03 +01:00
Eve
80de452e6d Fix inverted check in implicit arg app type check, disambiguate implicit args in reapply instead of tcApp 2025-02-08 10:23:23 +01:00
Eve
4750ccfb7e Nondeterministic overload resolution in new type checker 2025-02-04 14:14:16 +01:00
Eve
41cdf5e56a Load prelude in repl 2025-02-03 09:54:13 +01:00
Eve
8290f79f52 Rudimentary resource REPL in gf-compiler 2025-01-26 09:13:24 +01:00
Eve
3b58ccbeef Don't evaluate builtins with free variables as arguments 2025-01-26 01:14:25 +01:00
Eve
d9ed763ace Fix tcApp on pi types, split check/infer into variants inside and outside EvalM 2025-01-26 01:13:58 +01:00
Eve
1747b46274 Add alex/happy as build tool dependencies, bump up unix version in gf-compiler 2025-01-26 01:12:29 +01:00
Krasimir Angelov
ac427d63f2 fix compilation in -resource mode 2024-10-22 09:02:03 +02:00
Krasimir Angelov
3b36b381aa save use of jments 2024-10-22 08:30:51 +02:00
Krasimir Angelov
f3a1fadd0c use evalError instead of erro 2024-10-22 08:29:30 +02:00
Krasimir Angelov
ebececef6d added MonadFix 2024-10-22 08:28:51 +02:00
Krasimir Angelov
00addd4a0c update the cabal file 2024-10-14 17:00:14 +02:00
Krasimir Angelov
00fd704405 the server package is now merged with the compiler 2024-10-14 16:56:35 +02:00
Krasimir Angelov
db58a4e7d6 bugfix 2024-09-21 16:12:21 +02:00
Krasimir Angelov
b86097a580 bugfix 2024-09-21 15:50:09 +02:00
Krasimir Angelov
43671f3679 concrete revisions not longer take space in the revision registry 2024-09-21 11:56:19 +02:00
Krasimir Angelov
8878eddb7d an API to retrieve a single language 2024-09-20 17:34:10 +02:00
Krasimir Angelov
e722916728 pattern matching with PChar 2024-09-05 18:00:27 +02:00
Krasimir Angelov
6c2a94d428 comment out the call to the LRTableMaker 2024-09-05 14:03:07 +02:00
Krasimir Angelov
5239ce5458 an experimental left-corner table maker 2024-09-05 14:01:22 +02:00
Krasimir Angelov
d43d2cbdb1 fix potential crashes 2024-09-03 16:41:22 +02:00
Krasimir Angelov
c519d4bfae switch to the new and nicer vector API 2024-08-28 11:20:45 +02:00
Krasimir Angelov
cda3e99bd2 an alternative vector implementation 2024-08-27 22:40:05 +02:00
Krasimir Angelov
6a75e4d595 Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2024-08-26 13:47:58 +02:00
Krasimir Angelov
676a01db2c a work in progress implementation for reset 2024-08-26 13:47:39 +02:00
Krasimir Angelov
92cd2df143 fix broken patch 2024-08-26 12:15:34 +02:00
Krasimir Angelov
428287346a optimize pattern matching on strings 2024-08-26 11:58:36 +02:00
Krasimir Angelov
d515cfd89d Data.XML must escape the data as well 2024-05-17 11:46:37 +02:00
Krasimir Angelov
6d7071fe9c typechecking and evaluation for markup 2024-05-17 11:37:44 +02:00
Krasimir Angelov
efe00f88e3 refactoring pgfMain now takes the file path directly 2024-05-16 19:34:02 +02:00
Krasimir Angelov
02e8dcbb56 make it possible to control whether to expand variants or not 2024-04-27 14:55:01 +02:00
Krasimir Angelov
541f6b23ab try again 2024-04-15 11:23:57 +02:00
Krasimir Angelov
cce5465f2b try python 3.10 as minimal version 2024-04-15 11:16:31 +02:00
Krasimir Angelov
51c34e3e26 set deployment target mac-12.0 2024-04-15 10:37:29 +02:00
Krasimir Angelov
c80da9b5dd try macOS-latest 2024-04-15 10:34:20 +02:00
Krasimir Angelov
580c0c252f another attempt to fix compilation on macOS 2024-04-15 10:19:05 +02:00
Krasimir Angelov
8764c2fb51 try skipping Python 3.7 for macOS 2024-04-15 09:30:44 +02:00
Krasimir Angelov
876e3c734a added Graphviz visualizations 2024-04-15 09:19:11 +02:00
Krasimir Angelov
ef659f3e97 yet another fix for Python on Windows 2024-04-11 11:44:41 +02:00
Krasimir Angelov
77752f02ec another fix for Python on Windows 2024-04-11 11:00:28 +02:00
Krasimir Angelov
7153490986 switch back to macos-latest-xlarge 2024-04-11 10:59:12 +02:00
Krasimir Angelov
8827221493 git commit the __attribute__ pragma is only for GCC 2024-04-11 10:56:59 +02:00
Krasimir Angelov
2f7c65c207 update the testsuite 2024-04-11 10:48:44 +02:00
Krasimir Angelov
82308426c6 merge variants when the | operator is used 2024-04-09 19:23:14 +02:00
Krasimir Angelov
f637abe92e steps towards an NLG language 2024-04-07 10:39:43 +02:00
Krasimir Angelov
81717e7822 fixed space leaks 2024-04-06 10:59:37 +02:00
Krasimir Angelov
6126d36a54 bugfix and dead code elimination 2024-04-05 20:11:13 +02:00
Krasimir Angelov
d48a8d06c1 much faster grammar loading and dynamic updates 2024-03-21 16:42:41 +01:00
Krasimir Angelov
614f4b2dc9 'reset' for delimited continuations 2024-03-15 09:11:26 +01:00
Krasimir Angelov
1fd0e9d8e2 fetch languages on demand to reduce database references 2024-03-14 20:05:19 +01:00
Krasimir Angelov
a8c5a4f93f properly skip unknown languages in pgf_write_pgf 2024-03-14 18:08:22 +01:00
Krasimir Angelov
280e11cab6 HOAS in the type checker 2024-03-10 19:31:45 +01:00
Krasimir Angelov
518e57141b detect keywords in the lookahead 2024-03-08 09:27:01 +01:00
Krasimir Angelov
5a2e1a847d Merge branch 'matheussbernardo-majestic' into majestic 2024-03-06 19:31:36 +01:00
Krasimir Angelov
52c56feaf2 fix the disambiguation of html tags 2024-03-06 19:27:16 +01:00
Krasimir Angelov
b0f71ce0ac Merge branch 'majestic' of github.com:matheussbernardo/gf-core into matheussbernardo-majestic 2024-03-06 09:34:13 +01:00
Krasimir Angelov
5426b4209f first draft of a typechecker 2024-03-06 09:08:15 +01:00
Krasimir Angelov
14a9a8d463 Updated compilation instructions 2024-03-04 09:12:10 +01:00
Krasimir Angelov
76f7579363 defined STG_UNUSED for macOS 2024-03-02 20:35:53 +01:00
Matheus Bernardo
1e6e84c5a6 Adding html tags to the parser and lexer 2024-03-01 16:52:15 +01:00
Krasimir Angelov
f6c736f020 make the table of references more compact 2024-02-09 20:30:29 +01:00
Krasimir Angelov
83d5c883c3 A pgf doesn't always have a file location 2024-02-08 16:40:24 +01:00
Krasimir Angelov
3b4f12e621 create lin/lincat can now fetch the definitions from the source grammar 2024-02-08 15:14:05 +01:00
Krasimir Angelov
ab30f1f9e5 fix the parsing for source commands 2024-02-08 13:38:45 +01:00
Krasimir Angelov
9fd1c5da80 The type signatures in Predef are no longer hard coded 2024-02-06 08:36:43 +01:00
Krasimir Angelov
9a6fc7fc9e export Thunk, newThunk 2024-02-06 07:34:40 +01:00
Krasimir Angelov
d5871b120d normalStringForm now returns a list 2024-02-06 07:31:19 +01:00
Krasimir Angelov
e74661c592 export the force function 2024-01-31 08:21:29 +01:00
Krasimir Angelov
c46dd599f9 restore commented out code 2024-01-31 08:20:59 +01:00
Krasimir Angelov
c94d0f31bc now we can load PGF files as precompiled modules 2024-01-30 13:02:40 +01:00
Krasimir Angelov
021e271f29 an FFI for GF 2024-01-23 17:33:39 +01:00
Krasimir Angelov
c72fb9b958 update after the changes in http-slim 2024-01-22 17:29:57 +01:00
Krasimir Angelov
a82095d117 reintroduce the compiler API 2024-01-18 20:58:10 +01:00
Krasimir Angelov
282c6fc50f bump the version number since the update in the C runtime 2024-01-18 12:31:11 +01:00
Krasimir Angelov
577ea67bde potentially speed up the database expansion on Windows and macOS 2024-01-18 12:19:38 +01:00
Krasimir Angelov
5e664b6f69 update 2024-01-17 14:45:46 +01:00
Krasimir Angelov
413e92e7c3 support ghc 9.4 2024-01-17 13:58:52 +01:00
Krasimir Angelov
88e3b2aac4 support ghc 9.4 2024-01-17 13:56:58 +01:00
Krasimir Angelov
e8f8044432 temporary add gf-scribe to the compiler 2024-01-17 13:17:04 +01:00
Krasimir Angelov
0ba5b59737 another attempt 2024-01-16 16:11:16 +01:00
Krasimir Angelov
9c556ac19d another attempt 2024-01-16 16:09:39 +01:00
Krasimir Angelov
8bfda6538d rename the action to macos-xlarge-runtime 2024-01-16 16:02:31 +01:00
Krasimir Angelov
dab53ed4cf try to build the runtime on macOS for arm 2024-01-16 16:01:25 +01:00
Krasimir Angelov
0a8e287948 fix a type error detected on macOS 2024-01-12 19:18:16 +01:00
Krasimir Angelov
73b4b68460 expose the random generation API 2024-01-12 19:08:58 +01:00
Krasimir Angelov
1a840d5cee update after the changes in the pretty printer 2024-01-11 09:43:16 +01:00
Krasimir Angelov
2fd2948e6e yet another attempt to fix CI 2024-01-11 09:24:03 +01:00
Krasimir Angelov
ad65cb8c3e yet annother attempt to fix CI 2024-01-11 09:17:10 +01:00
Krasimir Angelov
42755f0ce8 yet another attempt to fix CI 2024-01-11 07:52:36 +01:00
Krasimir Angelov
eea4dbbf78 yet another attempt to fix CI 2024-01-11 07:45:14 +01:00
Krasimir Angelov
e0b74a143c another attempt to fix CI 2024-01-11 07:39:26 +01:00
Krasimir Angelov
546d9ea65d restore build-majestic 2024-01-11 07:34:58 +01:00
Krasimir Angelov
7c34a5a481 try fixing the CI 2024-01-11 07:32:58 +01:00
Krasimir Angelov
d8e953e7e6 try fixing the failure of actions/upload-artifact 2024-01-11 07:29:23 +01:00
Krasimir Angelov
cfe6290c01 bugfix in the duplication detection 2024-01-10 13:56:39 +01:00
Krasimir Angelov
9fd68cd592 in debug mode print some productions that I missed before 2024-01-10 11:50:52 +01:00
Krasimir Angelov
ea9cd82428 initialize transaction_object = 0; 2024-01-10 11:19:40 +01:00
Krasimir Angelov
bbbdb7093c another memory leak patch 2024-01-10 11:13:17 +01:00
Krasimir Angelov
0078be88c7 fix memory leaks in the parser.cxx 2024-01-09 20:11:33 +01:00
Krasimir Angelov
f647f43274 fix all space leaks in PgfLRTableMaker 2024-01-09 11:12:19 +01:00
Krasimir Angelov
dee0047ba6 remove redundant method name 2024-01-05 12:29:06 +01:00
Krasimir Angelov
8e605eac88 revert some unintended changes 2024-01-05 11:05:11 +01:00
Krasimir Angelov
b5ed0dd0ea implement pre and support more syntagmatic words 2024-01-05 11:03:17 +01:00
Krasimir Angelov
24b96ba874 support CAPIT & ALLCAPIT 2024-01-04 10:37:25 +01:00
Krasimir Angelov
c327cf063e support for BIND/SOFT_BIND/SOFT_SPACE 2024-01-04 10:34:55 +01:00
Krasimir Angelov
68da9226b1 support syntagmatic words 2024-01-02 16:31:22 +01:00
Krasimir Angelov
51ea3926a5 bugfixes 2023-12-30 23:08:17 +01:00
Krasimir Angelov
87b6094ade introduce a version of namespace_iter with a lambda function 2023-12-28 10:50:08 +01:00
Krasimir Angelov
d78aea4170 bug fixes 2023-12-28 10:12:39 +01:00
Krasimir Angelov
da9e037b62 bugfixes 2023-12-23 18:53:54 +01:00
Krasimir Angelov
31b52adfa7 fix most space leaks in the LRTableMaker 2023-12-23 15:31:28 +01:00
Krasimir Angelov
ba19ff1f63 bugfix 2023-12-21 11:17:45 +01:00
Krasimir Angelov
93e47b6409 bugfix 2023-12-20 10:18:54 +01:00
Krasimir Angelov
4c701e68e2 more general and simpler implementation for gluing 2023-12-16 12:29:13 +01:00
Krasimir Angelov
9313b45a4f store the index with every production 2023-12-15 10:25:09 +01:00
Krasimir Angelov
f2d269ff65 restore epsilons while parsing 2023-12-14 18:16:10 +01:00
Krasimir Angelov
ad57f73298 Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2023-12-05 15:03:27 +01:00
Krasimir Angelov
85f3aa3eca add const specifier to make md5 more general 2023-12-05 15:02:49 +01:00
Krasimir Angelov
d0e3c30ea6 remove phrasetable_lookup_epsilons which is no longer in use 2023-12-05 14:01:11 +01:00
Krasimir Angelov
86315bc8c2 remove a premature optimization that caused problems 2023-12-05 13:56:56 +01:00
Krasimir Angelov
2631f0af8f partial implementation for type inference with records 2023-12-01 15:26:24 +01:00
Krasimir Angelov
8540e44e9d small fixes 2023-11-29 08:47:40 +01:00
Krasimir Angelov
5232364a9e typechecking without Value<->Term conversion 2023-11-28 21:21:34 +01:00
Krasimir Angelov
1d64d166be fix the so command in case of dependent types 2023-11-28 14:07:09 +01:00
Krasimir Angelov
54e06b5371 refactoring 2023-11-28 10:25:27 +01:00
Krasimir Angelov
6b9bda3328 fully restore the parser 2023-11-28 07:39:54 +01:00
Krasimir Angelov
eb71557627 ensure that metavariable IDs are always in sync 2023-11-27 13:46:21 +01:00
Krasimir Angelov
65002fb586 allow Exp instead of Exp1 for the source commands 2023-11-24 09:41:23 +01:00
Krasimir Angelov
4f28d2b3a3 the evaluator and the typechecker now share the same monad 2023-11-24 09:40:28 +01:00
Krasimir Angelov
bd9bd8b32f the experimental typechecker is almost converted to the new evaluator 2023-11-24 08:35:11 +01:00
Krasimir Angelov
e996d78b18 make "cc", "so", "create lin", "create lincat" usable even without loaded grammar 2023-11-23 20:26:48 +01:00
Krasimir Angelov
511fdeee44 the normalForm for terms now compresses variants 2023-11-23 19:35:18 +01:00
Krasimir Angelov
fcc80b545d started porting the experimental type checker to the new evaluator 2023-11-20 14:53:36 +01:00
Krasimir Angelov
da135bea8b started node.js binding 2023-10-03 09:11:42 +02:00
Krasimir Angelov
46ccde4abc more details in the LR graph 2023-09-20 18:05:40 +02:00
Krasimir Angelov
7d42e7cfc9 extend the LR(0) visualization 2023-09-20 13:42:20 +02:00
Krasimir Angelov
dccb9681a2 started a graphviz visualization for the LR(0) automaton 2023-09-19 21:19:54 +02:00
Krasimir Angelov
2582719fab prepare for context-sensitive parsing 2023-09-19 21:17:55 +02:00
Krasimir Angelov
22e6b30193 refactoring 2023-09-19 08:33:43 +02:00
Krasimir Angelov
5de4d9dd5c trigger a new uppload to PyPI 2023-09-18 14:20:09 +02:00
Krasimir Angelov
30717ac8b7 temporary disable the automaton generation for the GitHub version 2023-09-18 13:14:15 +02:00
Krasimir Angelov
f0c5299839 bugfix in the automaton generation 2023-09-17 14:06:31 +02:00
Krasimir Angelov
b3968d95b9 first variant of the parser which precompiles epsilons 2023-09-15 18:22:35 +02:00
Krasimir Angelov
d2cbe7b6a1 finished the unmarshaller 2023-09-14 11:38:55 +02:00
Krasimir Angelov
d557f45ebd started a WASM version of the runtime 2023-09-13 20:24:35 +02:00
Krasimir Angelov
e17d435284 add a link to GF WordNet 2023-09-11 21:45:32 +02:00
Krasimir Angelov
b0bd3ffbf8 fix the variable name 2023-09-10 19:23:59 +02:00
Krasimir Angelov
343e2d46bc try again with a different token 2023-09-10 19:02:41 +02:00
Krasimir Angelov
2df5538084 rename the python package to pgf-majestic and uppload to PyPI 2023-09-10 18:30:19 +02:00
Krasimir Angelov
2bc6e28ab0 fix after the patch in http-slim 2023-09-07 15:05:11 +02:00
Krasimir Angelov
d065e1de66 make it possible to download larger files but incremental upload 2023-09-07 15:04:34 +02:00
Krasimir Angelov
91681088ca make it possible to download a grammar 2023-09-07 10:30:43 +02:00
Krasimir Angelov
349c5b82ad fix compilation on Windows 2023-09-07 10:24:42 +02:00
Krasimir Angelov
dde9fc1228 fix the type signature for macOS 2023-09-07 10:19:36 +02:00
Krasimir Angelov
b265249fe9 don't use PyObject_CallOneArg for compatibility with old Python 2023-09-07 10:17:00 +02:00
Krasimir Angelov
f1af1c8be4 make it possible to bootstrap an .ngf from a cookie 2023-09-07 10:07:49 +02:00
Krasimir Angelov
d110140107 update 2023-09-04 17:53:55 +02:00
Krasimir Angelov
295458ab03 two more fixes 2023-09-04 17:52:09 +02:00
Krasimir Angelov
56c5b8e3e9 a second try on writePGF_ 2023-09-04 17:46:21 +02:00
Krasimir Angelov
251d313d1b remove redundant type 2023-09-04 17:17:26 +02:00
Krasimir Angelov
d49ef33054 try an implementation for writePGF_ on macOS 2023-09-04 17:14:02 +02:00
Krasimir Angelov
fc23e8b9fe try ubuntu-latest 2023-09-04 16:49:47 +02:00
Krasimir Angelov
844c4dccff try actions/checkout@v4 2023-09-04 16:36:47 +02:00
Krasimir Angelov
62cad0f1ba make it possible to write grammars via a cookie in glibc 2023-09-04 16:20:49 +02:00
Krasimir Angelov
9a6d5a99bf partial implementation for deserialization with daison 2023-09-01 11:56:23 +02:00
Krasimir Angelov
034fe569c4 added hasLinearization 2023-08-31 22:05:02 +02:00
Krasimir Angelov
a33f64d236 added lookupMorpho 2023-08-31 19:51:51 +02:00
Krasimir Angelov
e0c820be17 update checkoutBranch 2023-08-26 07:58:12 +02:00
Krasimir Angelov
d1e9454dfa add documentation and type information for VS Code 2023-08-25 18:10:30 +02:00
Krasimir Angelov
7c93a594e0 fix an out of date comment 2023-08-25 18:09:47 +02:00
Krasimir Angelov
22c41367ec fix typo 2023-08-25 18:09:16 +02:00
Krasimir Angelov
1a17234a9c progress on the parser 2023-06-02 11:52:47 +02:00
Krasimir Angelov
58b1a9a535 added hashing for expressions 2023-05-31 09:15:33 +02:00
Krasimir Angelov
bc0d7f8fd2 don't publish Python packages yet 2023-05-31 08:53:39 +02:00
Krasimir Angelov
fb0f1db74d fix the pretty printer for expression states 2023-05-11 12:34:47 +02:00
Krasimir Angelov
8f1e7a908f fix another space leak 2023-05-11 08:45:03 +02:00
Krasimir Angelov
92cedfb479 Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2023-05-11 05:54:30 +02:00
Krasimir Angelov
53e7cd5609 fix space leaks from the LR table maker 2023-05-11 05:53:58 +02:00
Krasimir Angelov
98165bd8b5 fix warnings detected by MSVC 2023-05-11 05:52:39 +02:00
Krasimir Angelov
a514500bba try fixing the linkage error with MSVC 2023-05-11 05:28:11 +02:00
Krasimir Angelov
392f002124 int -> size_t to silence warnings with MSVC 2023-05-10 14:01:46 +02:00
Krasimir Angelov
18d995af52 enable the compilation with MSVC which doesn't define ssize_t 2023-05-10 13:32:11 +02:00
Krasimir Angelov
7eac9ea2ab first draft of an LR parser 2023-05-10 12:01:48 +02:00
Krasimir Angelov
54352b507a Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2023-05-09 09:49:31 +02:00
Krasimir Angelov
aa090607d8 restore the priority after each pattern matching 2023-05-09 09:45:33 +02:00
Krasimir Angelov
028625988f remove incorrect optimization 2023-04-17 21:13:49 +02:00
Krasimir Angelov
a8630ddcd2 fix: [] + "ser" == "ser" 2023-04-06 11:36:21 +02:00
Krasimir Angelov
4d83be454f second bump 2023-03-31 10:52:51 +02:00
Krasimir Angelov
7a54889d14 bump the version 2023-03-31 10:41:16 +02:00
Krasimir Angelov
95b916339d yet another detail with (+) 2023-03-30 12:05:44 +02:00
Krasimir Angelov
22c45d8d34 fix how (+) interacts with special tokens 2023-03-30 11:55:47 +02:00
Krasimir Angelov
848142b353 fix the signature for pgf_parse 2023-03-25 09:19:11 +01:00
Krasimir Angelov
51be26a3fe yet another windows fix 2023-03-24 13:22:40 +01:00
Krasimir Angelov
2465abd7c7 the PGF finder should be last not first 2023-03-24 13:20:00 +01:00
Krasimir Angelov
3b4729f3db another windows fix 2023-03-24 13:04:58 +01:00
Krasimir Angelov
973807247b fix the compilatin with VC++ 2023-03-24 12:57:00 +01:00
Krasimir Angelov
beef722f2c .ngf files should have priority when importing a grammar module 2023-03-24 12:43:05 +01:00
Krasimir Angelov
5d205a06e8 a custom module finder makes it possible to load grammars directly 2023-03-24 12:32:07 +01:00
Krasimir Angelov
eb104e162d for the memoisation to be effective we need a custom comparator 2023-03-18 10:35:14 +01:00
Krasimir Angelov
f6d62c3d9b a refactoring to make it easier to use C++ closures 2023-03-18 10:16:18 +01:00
Krasimir Angelov
edbfe25f87 try to fix the compilation with VC++ 2023-03-17 14:28:56 +01:00
Krasimir Angelov
8bda030854 respect the depth in the exhaustive generator 2023-03-17 11:38:13 +01:00
Krasimir Angelov
6c3a4f5dcd random generation always produces something if possible 2023-03-16 17:22:42 +01:00
Krasimir Angelov
de5f027bde fix potential race condition 2023-03-15 17:09:25 +01:00
Krasimir Angelov
66e0511141 gr and gt now take into account the -lang flag 2023-03-14 18:58:37 +01:00
Krasimir Angelov
87b5c0da6c refactoring 2023-03-14 16:27:18 +01:00
Krasimir Angelov
af7b504e36 allow the generation of literals under lambdas 2023-03-14 12:12:14 +01:00
Krasimir Angelov
9a0a730820 _Rb_tree doesn't exist on Windows and macOS. Go back to using map 2023-03-14 09:40:38 +01:00
Krasimir Angelov
92c2840b2b restore the depth flag for gt and gr 2023-03-13 14:01:14 +01:00
Krasimir Angelov
ed45bf9ebd HOAS in exhaustive generation 2023-03-13 13:30:17 +01:00
Krasimir Angelov
fc1b560eeb added exhaustive generation 2023-03-11 19:23:19 +01:00
Krasimir Angelov
23c0b322ce exhaustive generation without HOAS and depth limit 2023-03-11 19:20:54 +01:00
Krasimir Angelov
62d24b9431 the Haskell marshaller/unmarshaller are now statically allocated 2023-03-10 23:34:28 +01:00
Krasimir Angelov
4863ab0ec9 PGFs merging should update the probspace only once 2023-03-09 12:59:18 +01:00
Krasimir Angelov
dfa2c7873b fix merge_pgf after the latest refactory 2023-03-08 19:21:18 +01:00
Krasimir Angelov
9dc36a0f5f added the "alter lin" command 2023-03-07 15:29:58 +01:00
Krasimir Angelov
c7e988dacf added the generator files 2023-03-05 13:32:29 +01:00
Krasimir Angelov
ee717fb022 added random generation 2023-03-05 13:18:14 +01:00
Krasimir Angelov
97bb8ae3f6 fix the parsing of large integers 2023-03-02 10:45:51 +01:00
Krasimir Angelov
f7ca8afa81 fast word completion for functions names in the shell 2023-03-02 10:28:00 +01:00
Krasimir Angelov
adc8a2fa29 fix space leak 2023-03-02 09:55:11 +01:00
Krasimir Angelov
a9279511da fix tests 2023-03-02 09:51:41 +01:00
Krasimir Angelov
aa5566f256 forgot to add probspace.(cxx|h) 2023-03-02 09:46:19 +01:00
Krasimir Angelov
8fc73b5d05 introduce probspace and maintain consistency after delete 2023-03-02 09:40:39 +01:00
Krasimir Angelov
23a5a3cdef another way to test for big numbers 2023-03-02 09:37:21 +01:00
Krasimir Angelov
b8c9569f04 fix transaction accounting in pgf_boot_ngf & pgf_checkout_revision 2023-03-02 09:08:14 +01:00
Krasimir Angelov
91769c7ff2 if createConcrete/alterConcrete fail, report the error correctly 2023-03-01 15:24:30 +01:00
Krasimir Angelov
c9a83e496c try fixing the artifact upload 2023-02-24 08:58:25 +01:00
Krasimir Angelov
56d8ecd240 fix the compilation without a server 2023-02-24 08:49:39 +01:00
Krasimir Angelov
6e12d7fee9 install happy & alex 2023-02-24 08:41:43 +01:00
Krasimir Angelov
e879b374a7 remove duplicated module 2023-02-24 08:30:42 +01:00
Krasimir Angelov
963dd67c91 try building the compiler 2023-02-24 08:24:26 +01:00
Krasimir Angelov
9702d13059 try building the compiler 2023-02-24 08:15:40 +01:00
Krasimir Angelov
48fa373dc0 try building the compiler 2023-02-24 08:09:26 +01:00
Krasimir Angelov
4da2778776 skip Python 3.6 on macOS 2023-02-24 07:57:02 +01:00
Krasimir Angelov
1b2c8ce961 restored the word alignment API 2023-02-23 20:17:23 +01:00
Krasimir Angelov
57126f6d28 handle nonExist in parse the tree visualization and reclaim memory 2023-02-23 14:19:48 +01:00
Krasimir Angelov
9d330b6fb2 document case_sensitive 2023-02-23 10:30:31 +01:00
Krasimir Angelov
f40072a5f4 pre now does case insensitive matching if case_sensitive=off is set 2023-02-23 10:21:50 +01:00
Krasimir Angelov
35e47b9fac robustness by reinitializing the locks if dead processes are found 2023-02-22 17:41:50 +01:00
Krasimir Angelov
476075246d bugfix 2023-02-16 18:53:46 +01:00
Krasimir Angelov
88faaa4e04 filter out results in linearize_all when there is a nonExist 2023-02-14 23:06:29 +01:00
Krasimir Angelov
310634bbe2 remove the import for Debug.Trace 2023-02-10 12:04:47 +01:00
Krasimir Angelov
be951d9265 fix the compilation for parameters of type Ints n 2023-02-10 12:04:21 +01:00
Krasimir Angelov
810e529e41 another way to fix the one value parameter types 2023-02-10 10:52:09 +01:00
Krasimir Angelov
9bedcb038e ellimate parameters with only one possible value 2023-02-08 16:38:05 +01:00
Krasimir Angelov
bd8e86214a file was closed twice 2023-02-05 10:16:20 +01:00
Krasimir Angelov
6d856b2ce0 make it possible to control the initial NGF size 2023-01-29 21:04:08 +01:00
Krasimir Angelov
8ee624bc68 bump version 2023-01-29 14:01:51 +01:00
Krasimir Angelov
1e1719239a spotted more potential crashes 2023-01-29 13:44:32 +01:00
Krasimir Angelov
5551960698 fix typos 2023-01-29 13:05:41 +01:00
Krasimir Angelov
76ebf4d939 remap lseek to _lseeki64 on Windows 2023-01-29 13:04:52 +01:00
Krasimir Angelov
36ffc7747f fix the call to CreateFileMapping 2023-01-29 10:39:17 +01:00
Krasimir Angelov
8fca37cfeb writePGF now allows to select list of languages 2023-01-28 11:59:39 +01:00
Krasimir Angelov
471adbf63a bump the python version 2023-01-27 18:19:36 +01:00
Krasimir Angelov
0375f0f36d try --skip-existing 2023-01-27 17:17:52 +01:00
Krasimir Angelov
cd3372de35 remove basic.ngf when starting test since on Windows we cannot remove files that are still open 2023-01-27 17:01:34 +01:00
Krasimir Angelov
1e3eb44843 explicitly close the file before removal 2023-01-27 16:00:29 +01:00
Krasimir Angelov
0e81dd7ada fix potential crashes in the reader.cxx 2023-01-27 15:07:31 +01:00
Krasimir Angelov
e7cd5cd3f2 make the .ngf file read/write on Windows 2023-01-27 15:07:04 +01:00
Krasimir Angelov
a2df7ed2a6 another fix 2023-01-27 10:44:51 +01:00
Krasimir Angelov
2d2af272a7 fix compilation 2023-01-27 10:28:01 +01:00
Krasimir Angelov
057cb7a3a6 fix the marshaller as well 2023-01-27 09:40:43 +01:00
Krasimir Angelov
660dd95cf2 fix the marshaller for integers on Windows 2023-01-27 09:31:25 +01:00
Krasimir Angelov
bd11364234 prevent possible crash 2023-01-27 08:34:17 +01:00
Krasimir Angelov
2bf3fcfc9c fix transactions on Windows 2023-01-27 08:33:04 +01:00
Krasimir Angelov
bdb9a20f7e fix int->size_t types 2023-01-26 21:53:59 +01:00
Krasimir Angelov
213de48eb1 reenable testing on windows 2023-01-26 19:31:53 +01:00
Krasimir Angelov
d32ba0538d fix the read/write lock on Windows 2023-01-26 19:30:24 +01:00
Krasimir Angelov
dc2a3cb3d4 temporary export even for embeded runtime 2023-01-26 14:36:46 +01:00
Krasimir Angelov
6faab424dd forgot closing the file 2023-01-26 14:35:29 +01:00
Krasimir Angelov
ea99bb8ad8 another fix 2023-01-26 11:49:22 +01:00
Krasimir Angelov
9c07ab73ca upgrade version for actions/download-artifact 2023-01-26 11:22:01 +01:00
Krasimir Angelov
20efd1578f fix artefact name 2023-01-26 11:20:32 +01:00
Krasimir Angelov
05e5c1692a temporary disable testing on Windows 2023-01-26 11:10:01 +01:00
Krasimir Angelov
618e627352 make the path an argument to pytest 2023-01-26 09:45:53 +01:00
Krasimir Angelov
8cac0610f8 make tests executable from a different path 2023-01-26 09:44:36 +01:00
Krasimir Angelov
64d439601d test 2023-01-26 09:25:25 +01:00
Krasimir Angelov
bec841878a annother attempt 2023-01-26 09:18:32 +01:00
Krasimir Angelov
7ee92b5116 normalize / to \ for Windows 2023-01-26 09:17:47 +01:00
Krasimir Angelov
7fa3c5c221 try cibuildwheel on Windows again 2023-01-26 09:10:52 +01:00
Krasimir Angelov
74e0880eca silence some warnings for MSVC 2023-01-26 09:07:41 +01:00
Krasimir Angelov
c327b7e1d9 restore type signatures that accidentally changed 2023-01-26 08:57:14 +01:00
Krasimir Angelov
5d72714ef3 use strunct PgfConcrLin for consistency 2023-01-26 08:51:59 +01:00
Krasimir Angelov
60fa0b6314 disable warning C4200 for MSVC 2023-01-26 08:51:00 +01:00
Krasimir Angelov
86f8562d36 add EXTERN_C for all API function for MSVC 2023-01-26 08:44:47 +01:00
Krasimir Angelov
14d8b14827 rename strdup to _strdup for MSVC 2023-01-26 08:42:42 +01:00
Krasimir Angelov
7c13168bff use pragmas on when compiled with GCC 2023-01-26 08:40:27 +01:00
Krasimir Angelov
42c522954d use struct instead of class for consistency 2023-01-26 08:40:02 +01:00
Krasimir Angelov
8926a4f4c2 alloca.h -> malloc.h 2023-01-26 08:35:11 +01:00
Krasimir Angelov
54d594aa07 use struct PgfSequenceItor for consistency 2023-01-26 08:33:24 +01:00
Krasimir Angelov
b138d0c89b use alloca for compatibility with MSVC 2023-01-26 08:31:44 +01:00
Krasimir Angelov
ee96bcbb1c define PgfDB as class for C++ and as struct for C 2023-01-26 08:22:14 +01:00
Krasimir Angelov
69c70694aa define COMPILING_STATIC_PGF for MSVC 2023-01-26 08:20:14 +01:00
Krasimir Angelov
1d5dffa7a6 printf annotation compatible with MSVC 2023-01-26 07:28:43 +01:00
Krasimir Angelov
e689a35ee5 setup the include directory for MSVC 2023-01-26 00:22:04 +01:00
Krasimir Angelov
58e686c901 define ssize_t for MSVC 2023-01-26 00:18:08 +01:00
Krasimir Angelov
8cefedd8ef fix 2023-01-26 00:14:30 +01:00
Krasimir Angelov
a1df64987e rename _open,_lseek,_close 2023-01-26 00:09:51 +01:00
Krasimir Angelov
7432569578 include <io.h> for MSVC 2023-01-26 00:04:11 +01:00
Krasimir Angelov
57a3f1d02a detach Python(Windows) from Runtime(MinGW64) 2023-01-25 23:57:08 +01:00
Krasimir Angelov
89a9806925 PGF_API->PGF_API_DECL 2023-01-25 23:47:38 +01:00
Krasimir Angelov
ed5d0269ac PGF_INTERNAL->PGF_INTERNAL_DECL 2023-01-25 23:35:25 +01:00
Krasimir Angelov
fc6ded1759 one more fix for thread local on MSVC 2023-01-25 23:26:09 +01:00
Krasimir Angelov
696a9ffb16 thread local for MSVC 2023-01-25 23:16:02 +01:00
Krasimir Angelov
e4cc9bc0a7 bugfix 2023-01-25 20:59:06 +01:00
Krasimir Angelov
1ca1828fef on Windows link the C runtime statically into the Python binding 2023-01-25 20:50:32 +01:00
Krasimir Angelov
82683bd1a5 redefine alloca as _alloca for VC++ 2023-01-25 20:32:12 +01:00
Krasimir Angelov
3bc492ec69 use alloca for compatibility with VC++ 2023-01-25 20:20:32 +01:00
Krasimir Angelov
3f44c3541a PGF_API -> PGF_API_DECL 2023-01-25 20:11:23 +01:00
Krasimir Angelov
cd5f8aa6d5 test 2023-01-25 19:56:25 +01:00
Krasimir Angelov
e8c59ffc3f test 2023-01-25 19:46:56 +01:00
Krasimir Angelov
b4c6e60cd3 test 2023-01-25 19:40:37 +01:00
Krasimir Angelov
00a44f30ef suppress flags when building on Windows 2023-01-25 19:32:21 +01:00
Krasimir Angelov
97019a1524 test 2023-01-25 19:21:00 +01:00
Krasimir Angelov
8621cf4db6 test 2023-01-25 19:10:28 +01:00
Krasimir Angelov
11f0044b7c test 2023-01-25 17:44:52 +01:00
Krasimir Angelov
0cc462e6f1 test 2023-01-25 17:43:33 +01:00
Krasimir Angelov
76ddbff9c6 test 2023-01-25 17:23:32 +01:00
Krasimir Angelov
b0e1e1f86c test 2023-01-25 17:03:06 +01:00
Krasimir Angelov
e556a9a801 test 2023-01-25 16:54:49 +01:00
Krasimir Angelov
a8dfe75a4c test 2023-01-25 16:10:58 +01:00
Krasimir Angelov
6faf1102cf test 2023-01-25 15:49:16 +01:00
Krasimir Angelov
d70ed72bef test 2023-01-25 15:39:23 +01:00
Krasimir Angelov
a115b60bc1 test 2023-01-25 15:33:21 +01:00
Krasimir Angelov
5e687ba838 test 2023-01-25 15:28:39 +01:00
Krasimir Angelov
6bf41c87f7 test 2023-01-25 15:18:49 +01:00
Krasimir Angelov
f23f690939 test 2023-01-25 15:09:34 +01:00
Krasimir Angelov
92f15c1900 test 2023-01-25 15:07:23 +01:00
Krasimir Angelov
c12fdbdfad test 2023-01-25 15:03:29 +01:00
Krasimir Angelov
2a921b0084 test 2023-01-25 14:59:58 +01:00
Krasimir Angelov
83c85afff3 test 2023-01-25 14:57:13 +01:00
Krasimir Angelov
dea46e82cf test 2023-01-25 14:47:00 +01:00
Krasimir Angelov
091e9bbd4f test 2023-01-25 14:32:12 +01:00
Krasimir Angelov
6ecb448c58 test 2023-01-25 14:28:56 +01:00
Krasimir Angelov
3bf8ed8f55 test 2023-01-25 14:21:12 +01:00
Krasimir Angelov
ed13967db8 test 2023-01-25 14:18:36 +01:00
Krasimir Angelov
5062c1015b test 2023-01-25 14:15:05 +01:00
Krasimir Angelov
c35a42e31d try with CIBW_ENVIRONMENT 2023-01-25 12:14:37 +01:00
Krasimir Angelov
dc1d5de563 try using /usr instead of /usr/local 2023-01-25 12:05:16 +01:00
Krasimir Angelov
8363cf6143 another attempt at ubuntu on wheels 2023-01-25 11:43:14 +01:00
Krasimir Angelov
73a6fa1b08 skip building for pypy 2023-01-25 11:38:17 +01:00
Krasimir Angelov
5ff03007c6 try using wheels on ubuntu 2023-01-25 11:18:40 +01:00
Krasimir Angelov
ea66124317 try with python 3.8 2023-01-25 11:16:40 +01:00
Krasimir Angelov
c330dcdc00 change the CWD when running pytest 2023-01-25 11:05:22 +01:00
Krasimir Angelov
4abad5e2fc register pgf_EmbeddedGrammarType only for python > 3.6 2023-01-25 10:54:50 +01:00
Krasimir Angelov
b652163b0a fallback to linear time embedding for python 3.6 2023-01-25 10:44:01 +01:00
Krasimir Angelov
3f39719e65 fourth attempt 2023-01-25 10:25:33 +01:00
Krasimir Angelov
bf484da2ae third attempt 2023-01-25 10:15:51 +01:00
Krasimir Angelov
a15f028d39 another attempt 2023-01-25 10:00:47 +01:00
Krasimir Angelov
d241134024 try running the tests with cibuildwheel 2023-01-25 09:48:20 +01:00
Krasimir Angelov
2ae05d00dd another attempt 2023-01-25 09:41:07 +01:00
Krasimir Angelov
83474b62dd try skipping setup-python 2023-01-25 09:36:51 +01:00
Krasimir Angelov
bf2791ce3f temporary disable tests for python on macOS 2023-01-25 09:19:22 +01:00
Krasimir Angelov
b838b02a37 try fix the compilation for Python 3.6 2023-01-25 09:01:40 +01:00
Krasimir Angelov
2a902531a5 try compiling with wheel 2023-01-25 08:34:33 +01:00
Krasimir Angelov
9ca2398eb5 upgrade python 2023-01-24 21:32:20 +01:00
Krasimir Angelov
7e5ea7e1a2 try without cibuildwheels 2023-01-24 21:22:21 +01:00
Krasimir Angelov
5886a645bd specify python version 2023-01-24 21:18:59 +01:00
Krasimir Angelov
a2c6d6524e add cibuildwheel 2023-01-24 21:14:49 +01:00
Krasimir Angelov
26078d4df5 back to macOS-11 2023-01-24 20:37:44 +01:00
Krasimir Angelov
f3a059afc0 try building on macOS-10 2023-01-24 20:22:59 +01:00
Krasimir Angelov
8f3dbe150d restore the package name 2023-01-24 20:20:16 +01:00
Krasimir Angelov
0bfb3794c1 temporary rename the package to test the build action for macOS 2023-01-24 20:13:33 +01:00
Krasimir Angelov
efe92fb5be upgrade to haskell/actions/setup@v2 2023-01-24 19:10:46 +01:00
Krasimir Angelov
62506dc59d upgrade to actions/checkout@v3 2023-01-24 19:03:10 +01:00
Krasimir Angelov
6fb064e82c switch to setuptools 2023-01-23 22:23:35 +01:00
Krasimir Angelov
a912da9b13 fix bracketed linearization for metavariables 2023-01-23 21:37:06 +01:00
Krasimir Angelov
e895ccdaee an attempt to fix the compilation on Windows 2023-01-23 19:13:34 +01:00
Krasimir Angelov
dae9009c86 report the right function in the bracket even if there is no lin 2023-01-16 13:33:02 +01:00
Krasimir Angelov
7d189aa933 fix for BIND in bracketedLinearize 2022-12-17 17:01:04 +01:00
Krasimir Angelov
82039c22d3 added bracketed linearize 2022-12-17 10:21:43 +01:00
Krasimir Angelov
04a263d7d4 fix bracketed linearization in case of nonExist 2022-12-10 20:18:23 +01:00
Krasimir Angelov
a3111f3be7 fix after the introduction of name patterns 2022-12-10 20:17:10 +01:00
Krasimir Angelov
00227014b8 simpler but working name allocator 2022-12-10 18:43:26 +01:00
Krasimir Angelov
8f7e4c084c an API to create unique function names 2022-12-05 08:11:43 +01:00
Krasimir Angelov
a6aa6c2a5a constant time and space grammar embedding 2022-11-16 09:43:09 +01:00
Krasimir Angelov
045f708a76 use pgf_free_concr_revision instead of pgf_free_revision 2022-11-14 20:58:49 +01:00
Krasimir Angelov
3b77edb8d0 Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2022-11-12 19:46:22 +01:00
Krasimir Angelov
fd3c31b74d fix space leak during the first transaction 2022-11-12 19:45:47 +01:00
Krasimir Angelov
9214f2a074 fix compilation with older GHC versions 2022-11-10 19:19:19 +01:00
Krasimir Angelov
5ca00ded84 added version constraints 2022-11-10 15:44:34 +01:00
Krasimir Angelov
fda1353148 add consistant version numbers 2022-11-10 15:33:51 +01:00
Krasimir Angelov
43934e04de don't save the history in -run and -server modes to avoid space leaks 2022-11-04 22:53:44 +01:00
Krasimir Angelov
a88c412e87 "create lin/lincat" should be able to see funs & cats in the current transaction 2022-11-04 22:03:29 +01:00
Krasimir Angelov
58910975ad fix compilation for Python < 3.10 2022-10-26 07:40:21 +02:00
Krasimir Angelov
d784e2584b A lower-level transaction API and a transaction command in the shell 2022-10-24 10:44:40 +02:00
Krasimir Angelov
4b2e5d2f4c guard for missing linearization 2022-10-24 10:42:11 +02:00
Krasimir Angelov
39ac59c2b9 bugfixes related to old pointers 2022-10-24 10:37:38 +02:00
Krasimir Angelov
d8aab2962c check for lins without funs 2022-10-21 13:41:41 +02:00
Krasimir Angelov
7ef4fe7555 basic linearization API 2022-10-19 14:33:38 +02:00
Krasimir Angelov
073459ad56 bugfix 2022-10-10 15:17:54 +02:00
Krasimir Angelov
be721f3415 PGF.embed can now augment existing modules 2022-10-08 17:21:36 +02:00
Krasimir Angelov
706b74a15b bugfix: check for 0 before free_ref 2022-10-08 08:08:30 +02:00
Krasimir Angelov
35d6a12074 fix a space leak 2022-10-07 23:30:26 +02:00
Krasimir Angelov
b39f481316 check for zero epsilon or backref pointers 2022-10-04 12:04:18 +02:00
Krasimir Angelov
e2a7974853 partial support for epsilon rules 2022-10-04 11:44:22 +02:00
Krasimir Angelov
693ca7ffa5 Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2022-10-03 11:55:37 +02:00
Krasimir Angelov
2accfa57f1 bugfix: the viterbi prob. of a state is computable only after we know the chunks 2022-10-03 11:54:17 +02:00
Krasimir Angelov
0bc7e8ea2e reuse PgfParser::before instead of the new PgfParser::fetch_state 2022-10-03 11:51:34 +02:00
Krasimir Angelov
c15b5271a9 fix the printing of meta items 2022-10-03 11:48:40 +02:00
Krasimir Angelov
9f2cbe70fe fix the printer for the debug output after the last change 2022-10-03 11:47:36 +02:00
Krasimir Angelov
f05b0ff82a pgf_expr_prob is now compatible with the parse model 2022-09-30 15:56:07 +02:00
Krasimir Angelov
855fa7ebf3 use TextSpots for correct extraction of unknown words 2022-09-30 11:58:09 +02:00
Krasimir Angelov
6b63c2f779 faster expression extraction 2022-09-30 11:34:04 +02:00
Krasimir Angelov
106d963d39 fix the printing of ExprItem 2022-09-30 10:45:14 +02:00
Krasimir Angelov
74f4317b98 detect chunks with more than one words 2022-09-29 18:49:31 +02:00
Krasimir Angelov
cd280272f3 bottom up prediction and maximal chunks 2022-09-23 11:33:16 +02:00
Krasimir Angelov
f8cfed15b4 add PGF_INTERNAL_DECL 2022-09-21 11:26:19 +02:00
Krasimir Angelov
e600d5e623 PGF_INTERNAL_DECL -> PGF_INTERNAL 2022-09-21 11:24:30 +02:00
Krasimir Angelov
3e0cc91a02 first rudimentary version of a parser 2022-09-16 12:34:46 +02:00
Krasimir Angelov
bcb1076dda don't try to translate empty sentences 2022-09-16 12:29:27 +02:00
Krasimir Angelov
1219b365a9 sync with the changes in http-slim 2022-09-09 12:33:10 +02:00
Krasimir Angelov
a5468359ce switch to using http-slim 2022-09-09 09:43:02 +02:00
Krasimir Angelov
8c705d54b8 switch to using http-slim 2022-09-09 09:42:19 +02:00
Krasimir Angelov
173128bd46 Merge branch 'master' into majestic 2022-08-24 20:31:10 +02:00
Krasimir Angelov
8fd5c1e176 Merge branch 'master' into majestic 2022-08-24 20:09:28 +02:00
Krasimir Angelov
dc8dce90a0 added a Setup script to compile without cabal-install 2022-08-24 14:00:22 +02:00
Krasimir Angelov
e9bbd38f68 gf --version now prints the shared folder to be used by the RGL 2022-08-24 12:02:10 +02:00
Krasimir Angelov
3fac8415ca forgot to mention sudo 2022-08-24 12:00:43 +02:00
Krasimir Angelov
1294269cd6 workaround for the Nix madness 2022-08-24 11:57:47 +02:00
Krasimir Angelov
bcd9184ede initial adaptation to the new runtime 2022-08-19 17:26:59 +02:00
Krasimir Angelov
743c473526 linearization for chunks 2022-08-19 16:37:56 +02:00
Krasimir Angelov
a27e2dbbb4 fix a leak of stable pointers 2022-08-19 11:34:27 +02:00
Krasimir Angelov
44c78e8cc7 remove dead code 2022-08-17 10:33:54 +02:00
Krasimir Angelov
aec123bb7d fix compilation on Mac as well. 2022-08-17 10:30:37 +02:00
Krasimir Angelov
01c46479c6 another attempt to fix compilation 2022-08-17 10:22:12 +02:00
Krasimir Angelov
b378834756 try to restrict the GHC version for now 2022-08-17 10:14:25 +02:00
Krasimir Angelov
464c0001c4 remove the version limit for base 2022-08-17 09:56:32 +02:00
Krasimir Angelov
24cac8e41a update the Makefile to use the new style cabal 2022-08-17 09:54:32 +02:00
Krasimir Angelov
6d81306320 Try to remove the upper version for base 2022-08-17 09:49:37 +02:00
Krasimir Angelov
c8f37680f5 trying to fix the compilation on github 2022-08-17 09:44:04 +02:00
Krasimir Angelov
62344d1325 manually copy the logo to the www directory. Copying in Setup.hs doesn't work with the new Cabal 2022-08-16 21:03:44 +02:00
Krasimir Angelov
3bdd9dc022 add missing MonadFail constraint for newer GHC 2022-08-16 20:06:51 +02:00
Krasimir Angelov
6c0e4bc08e switch to the new style cabal 2022-08-16 20:05:55 +02:00
krangelov
3acb7d2da4 silence harmless warnings 2022-08-12 10:54:43 +02:00
krangelov
08fb29e6b8 fix the reference counting for pgf.BIND 2022-08-12 10:51:56 +02:00
Krasimir Angelov
ada8ff8faa bugfix which makes lookupCohorts fast again 2022-07-30 18:22:58 +02:00
Inari Listenmaa
f69babef6d add link to Inari's blog 2022-07-27 14:53:58 +02:00
Krasimir Angelov
a42cec2107 support for BIND tokens in the Python bindings 2022-07-16 20:29:36 +02:00
Krasimir Angelov
eb41d2661f bugfix in readContext 2022-07-14 15:56:11 +02:00
Krasimir Angelov
9ded2096fd readExpr/readType/readContext can now identify local variables 2022-07-14 15:10:28 +02:00
Krasimir Angelov
3ba3f24e3a disable macos-javascript as well 2022-07-14 11:52:59 +02:00
Krasimir Angelov
826a346e19 building the JavaScript binding is disabled until someone takes care of it 2022-07-14 11:50:35 +02:00
Krasimir Angelov
bc47a01223 another try 2022-07-14 11:46:19 +02:00
Krasimir Angelov
4d3e414776 another try 2022-07-14 11:37:36 +02:00
Krasimir Angelov
833a86960b fix the binding after the API change 2022-07-14 11:25:00 +02:00
Krasimir Angelov
4d0f33e3c3 make it possible to replace the probabilities while reading a new .pgf 2022-07-14 11:04:45 +02:00
Krasimir Angelov
f1cad40394 lookupMorpho/lookupCohorts now report only lexical items 2022-07-12 14:02:08 +02:00
Krasimir Angelov
5b8212020f finished the implementation of lookupCohorts 2022-07-12 12:46:50 +02:00
Krasimir Angelov
e546c2a0ce added a simple implementation for priority queues. 2022-07-08 16:19:11 +02:00
Krasimir Angelov
b509d22482 show match positions for ma -all|-longest|-best 2022-07-07 19:37:06 +02:00
Krasimir Angelov
acc6f85041 fix to show all prefixes in lookupCohorts 2022-07-07 19:29:26 +02:00
Krasimir Angelov
cfd9fbc5ed better documentation for "ma" 2022-07-07 14:18:29 +02:00
Krasimir Angelov
6c9f0cfe9c make also filterLongest and filterBest available from the shell 2022-07-07 14:11:31 +02:00
Krasimir Angelov
a66693770c started with lookupCohorts 2022-07-07 14:03:07 +02:00
Krasimir Angelov
c783da51a4 bugfix in lookupMorpho 2022-07-06 19:25:37 +02:00
Krasimir Angelov
c3c1cf2a64 on POSIX systems use mprotect to protect the data from accidental changes 2022-07-05 15:59:06 +02:00
Krasimir Angelov
73d4e326f7 consolidation of free blocks 2022-07-05 13:21:53 +02:00
Krasimir Angelov
96304a52d1 added checks to control compilation with emscripten 2022-07-04 14:26:04 +02:00
Krasimir Angelov
feb9b3373f fix the type cast, to avoid warnings on some platforms 2022-07-04 14:25:17 +02:00
Krasimir Angelov
1862ba5cec Define custom isdigit version. The expression parser now uses the custom isspace and isdigit 2022-07-04 14:24:06 +02:00
Krasimir Angelov
4d446fcd3f Merge branch 'master' of github.com:GrammaticalFramework/gf-core 2022-07-04 10:42:59 +02:00
Krasimir Angelov
ae460e76b6 allow compilation with emscripten 2022-07-04 10:42:34 +02:00
Krasimir Angelov
69a2b8a448 second attempt to fix the compilation 2022-06-29 21:48:48 +02:00
Krasimir Angelov
46a9a8f07d fix the compilation on Windows and macOS 2022-06-29 21:40:51 +02:00
Krasimir Angelov
88477a8834 added mutex for single writer exclusion 2022-06-29 16:28:01 +02:00
Krasimir Angelov
edb9ff33c5 another fix for linearizeAll and undefined lins 2022-06-28 18:21:58 +02:00
Krasimir Angelov
5b645ab42f normalForm should also sort the fields in a record type 2022-06-28 14:34:56 +02:00
Krasimir Angelov
42d01578ec added test for an unknown function at the top of an expression 2022-06-24 22:27:39 +02:00
Krasimir Angelov
635dc380a3 handle linref when the argument is an unknown function 2022-06-24 06:31:28 +02:00
Krasimir Angelov
f51f6240b6 remove redundant pattern 2022-06-23 14:53:58 +02:00
Krasimir Angelov
663cca2d06 fix the resolution of linrefs 2022-06-23 14:52:47 +02:00
Krasimir Angelov
44431d6a69 when in server mode reuse the NGF cache in the shell as well 2022-06-23 10:25:16 +02:00
Krasimir Angelov
7544e8dfbc remove duplicated export 2022-06-22 11:29:09 +02:00
Krasimir Angelov
174cc57eb7 restore the FastCGI service and move some files back to src/server 2022-06-22 11:18:56 +02:00
John J. Camilleri
65308861bc Merge branch 'master' of github.com:GrammaticalFramework/gf-core 2022-06-18 21:09:23 +02:00
Krasimir Angelov
a8ad145aeb move gf.cabal and all compiler dependent files into src/compiler 2022-06-18 20:42:31 +02:00
Krasimir Angelov
96c8218564 remove left out debug message 2022-06-16 18:21:54 +02:00
Krasimir Angelov
8ac0d881ed the server must checkout the grammar if an .ngf file changes 2022-06-16 18:20:18 +02:00
Krasimir Angelov
ad8a32ce86 safe parsing of "" and '' 2022-06-16 11:22:15 +02:00
Krasimir Angelov
247a48e5bb restore missing case in the JSON instance for BracketedString 2022-05-31 11:38:02 +02:00
Krasimir Angelov
418aa1a2b2 the web server now serves both .pgf and .ngf files 2022-05-31 11:32:02 +02:00
Krasimir Angelov
4c433b6b9d Merge branch 'master' into majestic 2022-05-31 10:20:22 +02:00
Krasimir Angelov
b7672b67a3 adjust the -view command depending on the OS 2022-05-31 10:15:50 +02:00
Krasimir Angelov
03fe38124f Merge branch 'master' into majestic 2022-05-31 08:05:00 +02:00
Krasimir Angelov
e33de168fd use a relative link to WordNet 2022-05-31 07:44:25 +02:00
Krasimir Angelov
18f70b786f first draft for lookupMorpho 2022-05-30 21:16:34 +02:00
Krasimir Angelov
92fbe08f51 small correction 2022-05-29 08:07:35 +02:00
Krasimir Angelov
109f8c86e8 more bugfixes in the allocator 2022-05-28 07:43:56 +02:00
Krasimir Angelov
02e45f478f avoid std::min since it is not available on macOS 2022-05-25 08:13:03 +02:00
Krasimir Angelov
363abce351 small fixes 2022-05-24 14:07:17 +02:00
Krasimir Angelov
eb06ff77bf pgf_clone_concrete must release the old concrete 2022-05-23 20:09:46 +02:00
Krasimir Angelov
fc09bc776b transactions should always start with the last revision and release it when done 2022-05-23 19:50:41 +02:00
Krasimir Angelov
d66cf23811 Revisions now correspond to revision_entry:s in the database. 2022-05-23 13:59:03 +02:00
Krasimir Angelov
a3d73fa658 register_revision must refresh the transaction to the latest 2022-05-23 11:33:47 +02:00
Krasimir Angelov
165de70172 debug messages for revision handling 2022-05-23 11:05:59 +02:00
Krasimir Angelov
31e20ffd84 more debug messages 2022-05-23 10:31:29 +02:00
Krasimir Angelov
e794f46e49 merge set_active_revision() with commit() 2022-05-23 09:58:43 +02:00
Krasimir Angelov
8a7d8ce246 at the end of the transaction the old revision is already released. 2022-05-23 09:52:25 +02:00
Krasimir Angelov
35176cc721 descriptors released in the last transaction are now reused in the next 2022-05-23 09:50:58 +02:00
Krasimir Angelov
9cd5634873 better debugging output in the allocator 2022-05-20 20:21:22 +02:00
Krasimir Angelov
3c1a3fb899 bugfix 2022-05-20 19:49:27 +02:00
Krasimir Angelov
483285e193 bug fixes in the allocator 2022-05-20 17:49:45 +02:00
Krasimir Angelov
f82b0088ed fix for Windows 2022-05-20 16:20:45 +02:00
Krasimir Angelov
37e1707f18 hopefully last attempt 2022-05-20 16:15:45 +02:00
Krasimir Angelov
607b8d6d23 next attempt to fix Windows 2022-05-20 16:08:10 +02:00
Krasimir Angelov
825a43caf2 third fix for Windows 2022-05-20 15:58:21 +02:00
Krasimir Angelov
ddce47270b more Windows fixes 2022-05-20 15:49:23 +02:00
Krasimir Angelov
43ca1079d7 fix the compilation on Windows 2022-05-20 15:40:59 +02:00
Krasimir Angelov
6faaf0b7be update the JavaScript binding 2022-05-20 15:15:13 +02:00
Krasimir Angelov
22d98833f9 fix the compilation on MacOS 2022-05-20 15:09:33 +02:00
Krasimir Angelov
cad564741b bump the base package version 2022-05-20 15:01:31 +02:00
Krasimir Angelov
5594679a83 first draft of the new allocator with transactions support 2022-05-20 13:55:45 +02:00
Inari Listenmaa
fc5b3e9037 Merge pull request #141 from anka-213/hardcode-utf8
Always use UTF8 encoding in the gf executable
2022-05-18 09:46:03 +02:00
Andreas Källberg
9b9905c0b2 Always use UTF8 encoding in the gf executable
This fixes many of the "Invalid character" messages
you can get on different platforms.

This has helped both with a nix-installation that didn't have global
locale set and with a windows installation.
2022-05-18 14:42:01 +08:00
Inari Listenmaa
ec70e4a83e Merge pull request #136 from mengwong/ghc9
compiles with GHC 9.0.2
2022-05-06 03:26:00 +02:00
Inari Listenmaa
e6ade90679 update nightly to latest lts 2022-05-06 08:45:12 +08:00
Inari Listenmaa
6414bc8923 Merge pull request #140 from anka-213/no-profile-bind
Don't add automatic cost centres to Data.Binary.Get
2022-05-04 10:46:37 +02:00
Andreas Källberg
b0b2a06f3b Improve comment 2022-05-03 13:10:29 +08:00
Andreas Källberg
221597bd79 When profiling, don't add cost centres in Data.Binary.Get
This change speeds up profiling by an order of magnitude.
Without it, the >>= function for Get dominates runtime completely during profiling.
2022-05-03 13:08:35 +08:00
Inari Listenmaa
862aeb5d9b Update base <4.15 to <4.16 for tests + pgf*.cabal 2022-03-05 13:42:11 +08:00
Inari Listenmaa
25dd1354c7 Merge pull request #135 from mengwong/base-4-15
prepare for GHC 9, base 4.15, by using Buffer constructor interface
2022-03-05 06:28:17 +01:00
Inari Listenmaa
b762e24a82 Add ghc-9.0.2 to CI 2022-03-05 13:25:26 +08:00
Meng Weng Wong
20453193fe add compilation support for ghc 9.0.2 2022-03-05 13:15:40 +08:00
Meng Weng Wong
b53a102c98 if this PR is accepted we don't need these instructions 2022-03-05 12:59:25 +08:00
Meng Weng Wong
bc14a56f83 "now try this" instructions for people flailing with Apple Silicon M1 2022-03-05 12:59:25 +08:00
Meng Weng Wong
3a1213ab37 prepare for GHC 9, base 4.15, by using Buffer constructor interface 2022-03-05 12:59:25 +08:00
Inari Listenmaa
1b41e94f83 Merge pull request #138 from anka-213/patch-1
Fix stack ci
2022-03-05 05:49:43 +01:00
Andreas Källberg
308f4773dc Upgrade to ghc-8.10.7
This version has better support for m1 macbooks
2022-03-05 12:25:46 +08:00
Andreas Källberg
05fc093b5e Add restore key to cache 2022-03-05 12:25:46 +08:00
Andreas Källberg
4caf6d684e Another attempt at fixing linker errors 2022-03-05 12:25:46 +08:00
Andreas Källberg
bfd8f9c16d Upgrade haskell setup action 2022-03-05 12:24:38 +08:00
Andreas Källberg
aefac84670 Clear stack cache and make cache-key more fine-grained
Attempt at fixing #137
2022-03-05 12:24:10 +08:00
Krasimir Angelov
546dc01b5d fix the compilation on Windows and Mac 2022-02-09 10:39:36 +01:00
Krasimir Angelov
8960e00e26 speed up booting by implementing realloc+padovan 2022-02-09 10:36:42 +01:00
Krasimir Angelov
fdd33b63d9 remove redundancies in the .pgf format kept for lagacy reasons 2022-02-08 19:04:08 +01:00
Krasimir Angelov
4ee671e59d fourth attempt 2022-02-08 17:38:08 +01:00
Krasimir Angelov
f50e1299ce third attempt 2022-02-08 17:33:44 +01:00
Krasimir Angelov
eedd424f5d second attempt 2022-02-08 17:32:43 +01:00
Krasimir Angelov
816225a054 try to fix the compilation on Mac 2022-02-08 17:25:34 +01:00
Krasimir Angelov
2ea78be6d8 third attempt 2022-02-08 17:01:38 +01:00
Krasimir Angelov
fd1891111b another attempt 2022-02-08 16:54:35 +01:00
Krasimir Angelov
d9efc1f615 try to restore compilation on Windows 2022-02-08 16:48:15 +01:00
Krasimir Angelov
4d240f7260 working fullFormLexicon. Slows down loading and compilation 2022-02-08 16:38:30 +01:00
Krasimir Angelov
fc7c1249b0 release the reference when done with it 2022-02-07 12:57:19 +01:00
Krasimir Angelov
9513c968db fix the sanity checking for valid revisions 2022-02-02 11:49:16 +01:00
Krasimir Angelov
f0045e910e better output for 'pg -fullform' 2022-01-28 17:32:40 +01:00
Krasimir Angelov
78b462c607 partial implementation for fullFormLexicon 2022-01-11 15:07:03 +01:00
Krasimir Angelov
c119349479 remove repeated export 2022-01-11 14:58:33 +01:00
Krasimir Angelov
c36d804c11 an attempt to fix the compilation on Mac 2022-01-11 14:57:41 +01:00
Krasimir Angelov
a216c1aa6d ensure left-to-right pattern maching of records 2022-01-11 13:31:44 +01:00
Krasimir Angelov
310b40be31 strip redundant code 2022-01-11 13:31:00 +01:00
Krasimir Angelov
54993bce12 deepForce VSymCat 2022-01-11 12:48:14 +01:00
Krasimir Angelov
a8c40db453 bugfix in pgf_tabular_linearize 2022-01-10 11:59:20 +01:00
Krasimir Angelov
8a432ee47b fix case-insensitive comparison 2022-01-10 11:08:37 +01:00
Krasimir Angelov
d87b3ce166 get rid of the destructive updates for seq_ids 2022-01-10 10:27:09 +01:00
Krasimir Angelov
19f7fb8d5e added const specifier 2022-01-09 18:20:47 +01:00
Krasimir Angelov
f2572d3bd5 mark Vector as internal 2022-01-09 14:59:55 +01:00
Krasimir Angelov
73fa1d98c3 std::exp -> expf 2022-01-09 14:58:36 +01:00
Krasimir Angelov
262e44c208 fix typo 2022-01-09 08:24:41 +01:00
Krasimir Angelov
f5435dba38 restore the rigt order for terms 2022-01-09 08:00:05 +01:00
Krasimir Angelov
99e639c861 handle failed linearization in tabularLinearize 2022-01-09 07:37:03 +01:00
Krasimir Angelov
f3d54a02e3 update the testsuite 2022-01-08 20:04:23 +01:00
Krasimir Angelov
e65a3a06c9 fix the serialization 2022-01-08 20:02:40 +01:00
Krasimir Angelov
00f857559d restore the sharing of sequences. Shrinks the grammar by ~45% 2022-01-08 19:49:42 +01:00
Krasimir Angelov
cd2c6aa32a cleanup transient revisions only after a transaction is opened 2021-12-29 14:52:21 +01:00
Krasimir Angelov
f118e644d9 finished 'create lincat' 2021-12-29 14:06:24 +01:00
Krasimir Angelov
daebed0b7b check the resource and the compiled grammar for compatibility 2021-12-29 12:28:50 +01:00
Krasimir Angelov
859d6ad5a5 restore categoryFields in the API 2021-12-29 12:06:29 +01:00
Krasimir Angelov
dca6611d84 synchronize the mmap sizes between processes 2021-12-29 11:16:21 +01:00
Krasimir Angelov
294ff3251c fix reference counting 2021-12-29 10:19:21 +01:00
Krasimir Angelov
16b0eea568 code cleanup 2021-12-28 13:38:19 +01:00
Krasimir Angelov
c9b90a509c first draft of a working "create lin" command 2021-12-28 13:36:53 +01:00
Krasimir Angelov
1959dd4499 added LT_INIT 2021-12-28 13:11:31 +01:00
krangelov
8b602d6c9f mergePGF now detects when grammars have different abstract syntaxes 2021-12-24 16:19:14 +01:00
krangelov
21d38a7b4a detect when we load a grammar with a different abstract and don't try to merge 2021-12-24 16:01:42 +01:00
krangelov
39853b3c04 add command "import -resource" 2021-12-24 14:46:07 +01:00
krangelov
cb10e2fe32 add commands to add/remove concrete syntaxes 2021-12-24 13:56:27 +01:00
krangelov
67a7e928f6 the import command can also boot images from .pgf files now 2021-12-24 12:52:29 +01:00
krangelov
cf87f55fa0 remove the trace message 2021-12-24 12:41:02 +01:00
krangelov
f606547209 the import command can now create blank grammars 2021-12-24 12:35:12 +01:00
krangelov
8b05257d6c restore the web server 2021-12-24 11:41:03 +01:00
krangelov
56824cb645 error -> fail 2021-12-24 11:15:10 +01:00
krangelov
4ec0c334c3 remove PGF2.Type 2021-12-24 10:53:36 +01:00
krangelov
5c16693da3 started create/drop with lin & lincat 2021-12-23 23:04:31 +01:00
krangelov
b000b80159 added commands create cat & drop cat 2021-12-23 19:21:55 +01:00
krangelov
f03779dfed fix Fun -> Cat 2021-12-23 18:06:08 +01:00
krangelov
f5798350fd commands "create fun" & "drop fun" in the shell 2021-12-23 14:55:26 +01:00
krangelov
5b5ecc6934 prevent crashes 2021-12-23 14:26:51 +01:00
krangelov
4792665241 back to storing rwlocks in a separate file to avoid moving the lock 2021-12-22 22:19:56 +01:00
krangelov
12b4958b99 make it possible to merge PGF files in the compiler 2021-12-22 10:47:22 +01:00
krangelov
c4bd898dc0 remove dead code 2021-12-22 09:31:11 +01:00
krangelov
d18c6d07ea use a diferent target name to avoid accidentally removing test.pgf 2021-12-21 19:10:36 +01:00
krangelov
a6f9eb15ad added Data instances for backwards compatibility 2021-12-21 14:38:28 +01:00
krangelov
13b6d51d43 support records as parameter types 2021-12-21 11:16:01 +01:00
krangelov
5811720d3a code cleanup 2021-12-21 09:19:18 +01:00
krangelov
0a8b6d2586 make sure that types in ResValue are precomputed 2021-12-21 09:16:53 +01:00
krangelov
f2b6f36e02 generalize the syntax for pre patterns 2021-12-20 15:44:30 +01:00
krangelov
2be3fd7e78 eval pattern macroses 2021-12-20 15:03:15 +01:00
krangelov
ef84adf107 refactoring 2021-12-19 14:18:19 +01:00
krangelov
f6789fdfbf refactor VC -> VC & VEmpty 2021-12-19 14:13:37 +01:00
krangelov
275f8f37ce handle pre when it is in the arguments of a Predef function 2021-12-19 10:43:06 +01:00
krangelov
b266c55f8a narrowing for table [...] 2021-12-17 17:26:23 +01:00
krangelov
2cb4fda502 more clean up 2021-12-17 10:05:20 +01:00
krangelov
2f79892463 clean up imports 2021-12-17 10:01:07 +01:00
krangelov
8e841d8c9b remove some dead code 2021-12-16 19:04:53 +01:00
krangelov
c8dcc10325 another fix for cc 2021-12-16 14:00:25 +01:00
krangelov
4ed287a809 bug fix and refactoring in the cc command 2021-12-16 13:14:29 +01:00
krangelov
8466692584 a bit more refactoring 2021-12-16 10:58:40 +01:00
krangelov
60c9d46141 simplify the Ident type 2021-12-16 09:53:39 +01:00
krangelov
7dea9598a4 remove the trace messages 2021-12-16 08:46:37 +01:00
krangelov
937a78c628 drop the -trace option 2021-12-15 13:08:10 +01:00
krangelov
f793ed4413 generate PMCFG only for complete modules 2021-12-15 09:53:45 +01:00
krangelov
b61e870783 a better error message 2021-12-15 09:36:12 +01:00
krangelov
8cb0383864 fix in the variable resolution 2021-12-15 09:31:02 +01:00
krangelov
4b7eaaf43f make sure that everything is evaluated before conversion 2021-12-15 08:23:31 +01:00
krangelov
14feb56140 bugfix in the conversion of parameters to numbers 2021-12-14 19:08:01 +01:00
krangelov
e2b6774bd3 the elimination of empty tokens is moved to the typechecker 2021-12-14 15:59:13 +01:00
krangelov
7556662344 compile record expansions with let bindings to avoid duplication 2021-12-14 15:27:53 +01:00
krangelov
f332a03c79 support Ints n as a parameter type 2021-12-14 15:27:03 +01:00
krangelov
51e337a910 prevent the compilation of empty tokens 2021-12-14 11:39:18 +01:00
krangelov
48c40f3170 fix the pretty printing for linearization variables 2021-12-14 11:08:27 +01:00
krangelov
cbcbbc9134 if there are no productions for a function, don't create PgfConcrLin at all 2021-12-14 10:15:32 +01:00
krangelov
77693dca3e one more trivial optimization for string patterns 2021-12-14 09:25:08 +01:00
krangelov
4886c7ce3b optimize certain pathological pattern matchings for strings 2021-12-14 09:16:40 +01:00
krangelov
9efb6b002f if a module is compiled with -no-pmcfg the PMCFG is generated on demand 2021-12-13 11:17:10 +01:00
krangelov
88ac47621a remove deprecated module 2021-12-13 11:10:20 +01:00
krangelov
404feea345 a bit of refactoring 2021-12-13 11:04:13 +01:00
krangelov
bb053119b3 when a pattern macro is invoked, the operation must be computed first 2021-12-13 09:55:37 +01:00
krangelov
f7bf18d101 fix value2term for predefined functions 2021-12-13 09:44:28 +01:00
krangelov
ad4c5029a3 fix the implementation for Predef.tk & Predef.dp 2021-12-10 12:05:01 +01:00
krangelov
b0672afc67 fully implement the linearize command 2021-12-10 10:34:57 +01:00
krangelov
73c16504d2 added bracketedLinearizeAll 2021-12-10 10:30:25 +01:00
krangelov
3a39fb5f9d added tabularLinearizeAll 2021-12-10 09:56:51 +01:00
krangelov
494f4c8193 added linearizeAll 2021-12-10 09:13:45 +01:00
krangelov
9b0b038984 handle records of parameters 2021-12-09 17:45:39 +01:00
krangelov
e413293657 tabularLinearize should continue after nonExist 2021-12-09 15:04:19 +01:00
krangelov
1ccfdfce5f another update 2021-12-09 10:09:42 +01:00
krangelov
5b324faeec update the JavaScript tests 2021-12-09 10:07:21 +01:00
krangelov
7bbdbbe917 update the testsuite for python 2021-12-09 10:00:31 +01:00
krangelov
b0d364f8e8 implement tabularLinearize 2021-12-09 09:51:09 +01:00
krangelov
09de911499 drop the symbol_meta method 2021-12-09 08:56:32 +01:00
krangelov
72982d2344 added testsuite for linearization 2021-12-09 08:46:29 +01:00
krangelov
0069946f42 linearization for HOAS expressions 2021-12-09 08:45:53 +01:00
krangelov
d1b1cd6e8c an API for constructing HOAS expressions 2021-12-09 07:46:49 +01:00
krangelov
e312a10882 fix a potential crash 2021-12-08 19:34:28 +01:00
krangelov
a7686cddde detect an attempt to linearize tree with partial application 2021-12-08 19:32:53 +01:00
krangelov
3f8642d0b9 linearize discontinuous categories with linref 2021-12-08 15:49:13 +01:00
krangelov
ac3b654b6c handle functions without lin rules as well as meta variables 2021-12-08 12:00:53 +01:00
krangelov
cd3f290ff2 always generate PMCFG for the literal categories 2021-12-07 15:51:34 +01:00
krangelov
f71ba14f6a fix bracketed linearization for literals 2021-12-07 15:51:05 +01:00
krangelov
e177aa5d01 added graphiviz.cxx 2021-12-06 19:20:20 +01:00
krangelov
2c79b81565 missed graphviz.h 2021-12-06 19:05:32 +01:00
krangelov
d274f4856e compile lindef & linref rules 2021-12-06 15:47:57 +01:00
krangelov
0b8a1a0de8 fix the order in which HOAS variables are shown in pgf_graphviz_abstract_tree 2021-12-04 18:09:08 +01:00
krangelov
a3d680f317 restored graphvizAbstractTree 2021-12-04 16:05:24 +01:00
krangelov
3d1123eed4 restore graphvizParseTree 2021-12-04 14:12:23 +01:00
krangelov
bbff79aaa3 added API for print names 2021-12-03 16:49:36 +01:00
krangelov
655576c291 the variable labeling should start with 0. 2021-12-03 15:00:04 +01:00
krangelov
348963d13c flush the pre stack at the end of the linearization as well 2021-12-03 14:52:31 +01:00
krangelov
d10f63c16b fix the ranges for brackets around pre 2021-12-03 13:55:29 +01:00
krangelov
0132a70b94 take into account the order in which CAPIT && ALL_CAPIT appears 2021-12-03 11:40:00 +01:00
krangelov
df82e1e7ca complete the linearization of pre 2021-12-03 11:29:01 +01:00
krangelov
baf78528d3 implement bracketedLinearize 2021-12-03 09:44:03 +01:00
krangelov
dc344fccc0 detect failures to resolve linearization 2021-12-02 15:28:48 +01:00
krangelov
9ca68b1b4b support for Int,Float and String 2021-12-01 15:54:34 +01:00
krangelov
15c03816ea implemented nonExist 2021-12-01 14:10:34 +01:00
krangelov
7e1a2447c2 PgfSymbolLit is the same as PgfSymbolCat for the linearizer 2021-12-01 13:58:12 +01:00
krangelov
03a5353c08 implement CAPIT & ALL_CAPIT 2021-12-01 13:56:52 +01:00
krangelov
0562d3fbdb various small bugfixes 2021-12-01 13:56:14 +01:00
krangelov
8e19b7d31c fix the memory leaks in the linearizer 2021-12-01 10:30:08 +01:00
krangelov
483f93822c fix in the PMCFG generation 2021-12-01 10:13:01 +01:00
krangelov
9ed74d7772 basic linearization is working 2021-11-30 17:54:36 +01:00
krangelov
ae08d42d6e started the linearizer 2021-11-26 18:44:17 +01:00
krangelov
3134a89307 reduce import symbols 2021-11-26 15:00:24 +01:00
krangelov
4a68ea93b3 generate and store the ranges for all linearization rules 2021-11-26 14:05:03 +01:00
krangelov
794e15aca3 fix in the PMCFG generation 2021-11-26 08:32:00 +01:00
krangelov
857e85c8a1 implement pre {..} 2021-11-25 19:04:35 +01:00
krangelov
3fd668e525 fix failure is the printout is empty 2021-11-25 13:51:19 +01:00
krangelov
f845889702 fix potential crashes 2021-11-25 11:50:09 +01:00
krangelov
fa1d7cf859 started on the typechecker 2021-11-19 10:39:06 +01:00
krangelov
1107b245da remove obsolete code 2021-11-19 09:38:04 +01:00
krangelov
a5cbf3e894 fix other potential allocation failures 2021-11-18 18:16:41 +01:00
krangelov
9dc80f7706 fix the crash in the python testsuite 2021-11-18 14:11:35 +01:00
krangelov
f8fb64a53e added test case for showPGF 2021-11-18 13:55:57 +01:00
krangelov
06980404a9 correctly distinguish between fun and data judgements 2021-11-18 13:50:09 +01:00
krangelov
7ff38bfcbe show field names in double quotes 2021-11-18 11:43:44 +01:00
krangelov
09731b985c fix showPGF for the case where a category has no fields 2021-11-18 11:41:24 +01:00
krangelov
5ada91f026 fix the serialization for empty strings 2021-11-18 11:36:18 +01:00
krangelov
ad068151f8 simple fix for showPGF 2021-11-18 11:19:35 +01:00
krangelov
aae6123e9e fix: call symks instead of symvar 2021-11-18 11:17:20 +01:00
krangelov
dc609d2fff change from curly braces to square brackets 2021-11-18 10:57:12 +01:00
krangelov
71020baa5e added sanity checking in the linearization builder 2021-11-18 10:33:20 +01:00
krangelov
ec76223b41 properly release memory for PgfConcrLincat & PgfConcrLin 2021-11-18 08:24:24 +01:00
krangelov
070f63a049 complete showPGF 2021-11-17 14:03:04 +01:00
krangelov
6295b32405 generate field names and pipe them to the runtime 2021-11-17 11:34:31 +01:00
Krasimir Angelov
9e00cdd7f4 Update README.md 2021-11-17 08:23:07 +01:00
Krasimir Angelov
e1f6a24371 Update transactions.md 2021-11-17 08:11:24 +01:00
Krasimir Angelov
ed6b0f303e Update README.md 2021-11-16 21:45:19 +01:00
krangelov
c4ff30cc34 add libwinpthread-1.dll as well 2021-11-16 21:42:55 +01:00
krangelov
0784b00a47 grab the extra .dll dependencies from MinGW as well 2021-11-16 21:27:20 +01:00
krangelov
6838aaa1fe add the .dll to the artifact as well 2021-11-16 21:04:36 +01:00
krangelov
6b301f916d add msys64 to the artifact path 2021-11-16 20:53:25 +01:00
krangelov
83e28f47f9 third guess 2021-11-16 20:45:50 +01:00
krangelov
2c11c25940 another attempt to build the artifact 2021-11-16 20:34:25 +01:00
krangelov
4750de888a an attempt to upload the windows build as an artifact 2021-11-16 20:26:58 +01:00
krangelov
f469b9979f no sudo on Windows 2021-11-16 20:05:08 +01:00
krangelov
f5fea82020 set working directory 2021-11-16 19:49:08 +01:00
krangelov
e00378c820 attempt to build the Windows runtime 2021-11-16 19:40:14 +01:00
krangelov
2c38ba6ca4 test msys 2021-11-16 19:36:02 +01:00
krangelov
7797aa6ed5 build instructions for Windows 2021-11-16 19:19:21 +01:00
Krasimir Angelov
30c5109bfd install GCC for MinGW 2021-11-16 19:13:56 +01:00
Krasimir Angelov
051eb737f2 Try to setup Windows build 2021-11-16 19:06:32 +01:00
krangelov
2cbf59d75b fix the include for WINDOWS 2021-11-16 17:23:03 +01:00
krangelov
1e3efd9fa4 progress on showPGF 2021-11-16 16:15:22 +01:00
krangelov
10e26575de started on showPGF 2021-11-16 12:07:38 +01:00
krangelov
5649bc1ef0 started piping PMCFG rules to the runtime 2021-11-16 11:49:02 +01:00
krangelov
db92bcfff6 fix for MacOS 2021-11-16 09:53:41 +01:00
krangelov
4a62ea02f4 destroy the r/w lock if there is no shared file 2021-11-16 09:48:50 +01:00
krangelov
c26f3b3cd5 an attempt to fix the failure on MacOS 2021-11-16 09:36:26 +01:00
krangelov
f5e6c695a7 make r/w lock shared only if there is a shared file as well 2021-11-16 08:53:22 +01:00
krangelov
c80ef3549c fix error reporting when the r/w lock is created 2021-11-16 08:47:07 +01:00
krangelov
58b805606b correct mode for pgf_boot_ngf on WIN32 2021-11-16 08:33:50 +01:00
krangelov
e0b93a37e2 fix the compilation on Windows again 2021-11-15 13:39:47 +01:00
krangelov
c1690ffa77 the r/w lock is now in the database itself 2021-11-15 13:13:00 +01:00
krangelov
0a204a47f7 Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2021-11-13 05:41:20 +01:00
krangelov
92ecc8cc1d finished porting to Windows 2021-11-13 05:40:38 +01:00
Krasimir Angelov
158666f29a Update README.md 2021-11-11 11:25:22 +01:00
krangelov
397d22b49b define macro to control dllexport on WINDOWS 2021-11-10 17:41:59 +01:00
krangelov
9804d993e4 remove the dependency to pthread on Windows 2021-11-10 17:27:45 +01:00
krangelov
68fd5460f4 fix cleanup after exceptions in PgfDB::PgfDB 2021-11-10 17:10:31 +01:00
krangelov
c806ce2d26 minimal changes to make the runtime compilable on Windows 2021-11-10 15:52:02 +01:00
krangelov
81eb2217ac more instructions for Windows 2021-11-10 15:22:47 +01:00
krangelov
064136cafd another fix for Windows 2021-11-10 14:40:45 +01:00
krangelov
5b7363d5c9 Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2021-11-09 19:09:28 +01:00
krangelov
befb61b0e3 first steps towards porting to Windows 2021-11-09 19:08:49 +01:00
Krasimir Angelov
9f84523a63 Instructions for compilation on Windows 2021-11-09 18:43:32 +01:00
krangelov
9eb88f9281 a number of new API functions for the concrete syntax. 2021-11-09 09:16:20 +01:00
krangelov
a4ad17a478 pgf_create_lin now has access to the abstract function 2021-11-09 08:50:54 +01:00
krangelov
02a84b12da simplify types 2021-11-09 08:08:14 +01:00
krangelov
1aacc34deb fix reference counting for concrete revisions 2021-11-09 08:02:20 +01:00
krangelov
73b52bf4b5 started on pgf_create_lin 2021-11-09 02:20:42 +01:00
krangelov
2bed0b708c PgfVector -> Vector 2021-11-09 02:10:17 +01:00
krangelov
6552bcf909 Unify the data model between the C runtime and the Haskell binding 2021-11-09 02:04:36 +01:00
John J. Camilleri
9f2a3de7a3 Add simpler VSCode extension to editor modes page 2021-11-08 12:30:21 +01:00
krangelov
b3ef14c39b another fix for MacOS 2021-11-08 10:41:09 +01:00
krangelov
d6cf023258 reading & writing grammars in the new format 2021-11-08 10:39:05 +01:00
krangelov
02b9915d11 attempt to fix compilation on Mac 2021-11-07 20:22:41 +01:00
krangelov
06b59b1f10 fix 2021-11-07 19:48:35 +01:00
krangelov
aef9c668e5 Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2021-11-07 19:46:04 +01:00
krangelov
3f261c2854 first draft of the data model for the concrete syntax 2021-11-07 19:45:11 +01:00
Krasimir Angelov
eaa0e55922 Update LambdaCalculus.md 2021-11-04 19:10:23 +01:00
Krasimir Angelov
5342844b33 Update LambdaCalculus.md 2021-11-04 17:26:47 +01:00
Krasimir Angelov
6fc3a2177c Update LambdaCalculus.md 2021-11-04 16:42:23 +01:00
Krasimir Angelov
86dfebd925 Update LambdaCalculus.md 2021-11-04 12:40:46 +01:00
Krasimir Angelov
478287c12f Update LambdaCalculus.md 2021-11-04 12:37:57 +01:00
Krasimir Angelov
3351cc224e Update LambdaCalculus.md 2021-11-04 11:03:13 +01:00
Krasimir Angelov
82980eb935 Update LambdaCalculus.md 2021-11-04 10:31:20 +01:00
Krasimir Angelov
45a8f21df8 Update LambdaCalculus.md 2021-11-04 09:38:15 +01:00
krangelov
6fcec8f864 Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2021-11-04 08:31:43 +01:00
krangelov
e806e94be9 fix typo 2021-11-04 08:31:31 +01:00
Krasimir Angelov
18083c09b1 Update LambdaCalculus.md 2021-11-03 16:33:25 +01:00
Krasimir Angelov
02e728ca1e Update LambdaCalculus.md 2021-11-03 16:32:00 +01:00
Krasimir Angelov
d44ae435c7 Update LambdaCalculus.md 2021-11-03 16:31:28 +01:00
Krasimir Angelov
eb3baa5c43 Update LambdaCalculus.md 2021-11-03 16:29:10 +01:00
Krasimir Angelov
208998d1f9 Update LambdaCalculus.md 2021-11-03 15:08:53 +01:00
Krasimir Angelov
f96cb85341 Update LambdaCalculus.md 2021-11-03 14:57:29 +01:00
Krasimir Angelov
19c3935855 Update transactions.md 2021-11-03 14:16:28 +01:00
krangelov
547783e50e PgfDB::ref_count must be size_t 2021-11-03 11:50:21 +01:00
krangelov
43f40e701a test cases for the concrete syntax 2021-11-03 11:40:34 +01:00
krangelov
309a16d471 reference counting for concrete syntaxes 2021-11-03 10:48:20 +01:00
krangelov
2320c6b3b0 export alterConcrete too 2021-10-28 19:32:37 +02:00
krangelov
7e0fc159ce use newForeignPtrEnv instead of Foreign.Concurrent.newForeignPtr 2021-10-26 20:24:35 +02:00
krangelov
611fe95322 fix typo 2021-10-26 10:28:33 +02:00
krangelov
a607799bb3 always unlock the mutex in case of failure 2021-10-26 10:22:29 +02:00
krangelov
fd40c204e2 more aggressive cleanup for dead processes 2021-10-26 10:14:16 +02:00
krangelov
00ba552026 ipc_release_file_rwlock should not assume that the file exists 2021-10-26 09:35:56 +02:00
krangelov
157574763f now we use inter-process locking 2021-10-25 19:14:25 +02:00
krangelov
d061403ba2 fix typo in the comment 2021-10-25 18:21:20 +02:00
krangelov
204e645616 update ipc.h 2021-10-25 15:52:32 +02:00
krangelov
186b151a90 rewrite ipc.cxx to support dynamic allocation of rwlocks 2021-10-25 15:51:06 +02:00
krangelov
2acc4be306 better error control 2021-10-25 09:30:22 +02:00
krangelov
d1c25ce1c1 add INCREF in embed() 2021-10-22 09:52:36 +02:00
krangelov
bfc2ab27e6 fix reference counting 2021-10-22 09:42:01 +02:00
krangelov
3f742497e4 restore the embed function 2021-10-22 09:34:19 +02:00
krangelov
19338a8de1 fix typo 2021-10-22 09:20:38 +02:00
krangelov
2889581a45 writeToFile -> writePGF for consistancy with Haskell & C 2021-10-22 09:07:26 +02:00
krangelov
777adaedfc fix the compilation 2021-10-22 09:04:28 +02:00
krangelov
1413c273cc API for adding concrete syntaxes. Garbage collection to be fixed! 2021-10-21 19:18:14 +02:00
krangelov
259ed52a77 fix the compilation of pre 2021-10-21 10:10:04 +02:00
krangelov
38d189f8ef bugfix for predefined operations 2021-10-21 08:55:22 +02:00
krangelov
64ccd82958 make record extension more compact after typechecking 2021-10-20 19:57:42 +02:00
krangelov
b6047463a9 we can finally compile the English RGL 2021-10-20 19:39:02 +02:00
John J. Camilleri
ad3489f0f9 Use actions/setup-node instead of nvm
Even though it should be installed, I was getting
nvm: command not found
in the CI logs.
2021-10-18 14:47:37 +02:00
John J. Camilleri
0b13d04ac4 Use Node.js 12 in CI 2021-10-18 14:42:37 +02:00
John J. Camilleri
42c1ec4448 Merge branch 'majestic' into majestic-macos 2021-10-18 14:27:30 +02:00
John J. Camilleri
ac93f2dd10 Don't call msync in PgfDB::sync on macOS 2021-10-18 13:54:13 +02:00
John J. Camilleri
a2d843f8ed Skip JavaScript in CI 2021-10-18 08:48:50 +02:00
John J. Camilleri
61e95bcfeb Fix compilation errors of Python bindings on macOS 2021-10-18 08:27:19 +02:00
krangelov
0e98c30973 fix space leak in PySequence_AsHypos. PyList_FromHypos->PyTuple_FromHypos 2021-10-16 21:12:16 +02:00
krangelov
0eb6e9f724 fix reference counting 2021-10-16 20:12:53 +02:00
krangelov
5e335a7df2 add unpack & __reduce_ex__ for backward compatibility 2021-10-16 19:57:47 +02:00
krangelov
768cd6ae71 Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2021-10-16 19:50:52 +02:00
krangelov
382456415e overload pgf.Type for backward compatibility and support for dependent and simple types 2021-10-16 19:50:01 +02:00
John J. Camilleri
c9b668a583 Fix compilation with macOS mmap/malloc workaround. Add Python (macOS) to CI. 2021-10-15 17:34:19 +02:00
John J. Camilleri
8cd0bb5ec1 Use malloc/realloc on macOS when fd < 0... but doesn't compile 2021-10-15 15:24:15 +02:00
John J. Camilleri
a5fb51ff3d Add some notes about uninstalling runtime 2021-10-14 22:23:39 +02:00
John J. Camilleri
26069e7ffe Set LD_LIBRARY_PATH globally in all workflow jobs/steps 2021-10-14 22:09:55 +02:00
John J. Camilleri
d218c286eb Re-enable macOS build in CI. Minor cleanup. 2021-10-14 21:52:41 +02:00
John J. Camilleri
900a0985a8 Put back bindings in all languages as separate jobs 2021-10-14 15:31:05 +02:00
John J. Camilleri
6b93c6fde4 Be more conservative when displaying /usr/local 2021-10-14 15:25:04 +02:00
John J. Camilleri
60a578bd6f add pipe ro run command 2021-10-14 15:21:11 +02:00
John J. Camilleri
04dd99c56c sudo mv 2021-10-14 15:19:25 +02:00
John J. Camilleri
d304e57b6e Move after download 2021-10-14 15:17:55 +02:00
John J. Camilleri
5bf0c9b7ad mkdir /usr/local/lib and /usr/local/include 2021-10-14 15:13:20 +02:00
John J. Camilleri
a044adfc8b Download artifacts to /usr/local 2021-10-14 15:08:18 +02:00
John J. Camilleri
695025d1a2 Display structure of downloaded files 2021-10-14 15:05:03 +02:00
John J. Camilleri
57b9080234 First attempt at separating the different language bindings in CI workflow 2021-10-14 15:01:37 +02:00
John J. Camilleri
30e3e6ba52 Cleanup, update README 2021-10-14 11:26:30 +02:00
John J. Camilleri
2d3c390e7d missing \ 2021-10-14 11:14:38 +02:00
John J. Camilleri
9b591129ed Install build tools with brew 2021-10-14 11:13:31 +02:00
John J. Camilleri
8e03b63237 Add glibtoolize to macOS CI 2021-10-14 11:07:38 +02:00
John J. Camilleri
86246c6fb8 Add macOS to CI 2021-10-14 11:05:41 +02:00
krangelov
5ee960ed7c fix the evaluation for Prod 2021-10-14 10:24:20 +02:00
krangelov
45ee985fda safe error reporting in case of mmap failure 2021-10-13 21:33:55 +02:00
krangelov
27f0ff14a3 VT should preserve its environment 2021-10-13 19:43:01 +02:00
krangelov
a909a85537 Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2021-10-13 19:15:32 +02:00
krangelov
c3eb6973f4 working PMCFG generation 2021-10-13 19:14:56 +02:00
John J. Camilleri
fc57f94e8a Finish unmarshalling of types. Add mkType et al. Add showType tests, but implementation is just stub. 2021-10-13 16:59:11 +02:00
John J. Camilleri
2686e63e58 Use memcpy instead of strcpy 2021-10-13 14:56:42 +02:00
John J. Camilleri
6497a3dd95 runTestTTAndExit requires HUnit >= 1.6.1.0 2021-10-12 23:47:49 +02:00
John J. Camilleri
3bdfe1a336 Minor cleanup 2021-10-12 23:27:49 +02:00
krangelov
2a5434df96 avoid using the wildcard constant 2021-10-12 19:07:21 +02:00
krangelov
a2e7d20b7a avoid using EOF in the expression parser 2021-10-12 18:47:04 +02:00
John J. Camilleri
ead1160a75 More changes to compile on macOS (incomplete) 2021-10-12 15:29:29 +02:00
krangelov
f9c6e94672 Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2021-10-12 12:07:17 +02:00
krangelov
8c721e063c partial support for runtime parameters 2021-10-12 12:06:59 +02:00
John J. Camilleri
1401a6d209 Fix (most) macOS compilation problems 2021-10-12 10:46:39 +02:00
Krasimir Angelov
5e65db2e17 Update CompilationOverview.md 2021-10-11 09:47:44 +02:00
krangelov
0977e9073f started the chapters about the compiler 2021-10-11 09:07:06 +02:00
krangelov
8d075b1d57 move the runtime documentation to the main doc folder 2021-10-11 08:59:28 +02:00
krangelov
95c81ec2b7 Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2021-10-08 19:25:39 +02:00
krangelov
62d5ed5b42 small progress on PMCFG 2021-10-08 19:25:21 +02:00
John J. Camilleri
0e011955be Add tests for reading & equality of various expressions 2021-10-08 15:06:34 +02:00
John J. Camilleri
71536e8e37 Handle errors in readExpr 2021-10-08 12:54:36 +02:00
John J. Camilleri
a27cf6a17b Implement all Expr unmarshalling (untested). Put wordsize logic in constants.ts. Some README additions. 2021-10-08 12:39:42 +02:00
krangelov
15e3ca9acd use prependModule to make the current module available 2021-10-08 11:56:28 +02:00
krangelov
6a9254816d Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2021-10-08 11:53:42 +02:00
krangelov
98f42051b1 first steps towards PMCFG generation 2021-10-08 11:53:07 +02:00
John J. Camilleri
dae39d8b10 Remove 'only' from test suite 2021-10-08 08:54:28 +02:00
John J. Camilleri
0d43ec8971 Unmarshalling for floats and strings, but strings crashes after multiple invocations 2021-10-07 23:25:25 +02:00
John J. Camilleri
16ee006735 Add stubs for all un/marshalling functions. Refactoring. 2021-10-07 15:58:59 +02:00
John J. Camilleri
db0cbf60cb Support big and negative integers 2021-10-07 15:07:14 +02:00
John J. Camilleri
db66144c25 Get marshalling of integers working 2021-10-07 12:54:02 +02:00
krangelov
e33d881ce8 finished the partial evaluator 2021-10-07 11:47:51 +02:00
krangelov
fd6cd382c5 added VGlue to cover the case where we can't precompute the glue 2021-10-05 19:39:24 +02:00
krangelov
d9db0ef4a7 Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2021-10-05 19:32:16 +02:00
krangelov
2a2d7269cf remove the Term(Error) constructor. Better propagation of errors. 2021-10-05 19:31:12 +02:00
krangelov
dc59d9f3f9 trivial implementation for EPatt & EPattType 2021-10-05 15:45:16 +02:00
krangelov
3c4e7dd20c partial evaluation for (+) 2021-10-05 15:37:42 +02:00
John J. Camilleri
1b3a197aac JavaScript unmarshalling WIP 2021-10-05 15:33:19 +02:00
John J. Camilleri
b7e7319542 Switch to 'standard' linting 2021-10-05 13:56:41 +02:00
John J. Camilleri
869c5d094b Implement categoryProbability, functionProbability, functionIsConstructor, functionsByCategory 2021-10-05 13:39:51 +02:00
krangelov
93c2f47752 missed VStr -> string2value 2021-10-05 13:38:00 +02:00
krangelov
51954c60ea fix the printer for strings with escape characters 2021-10-05 13:36:54 +02:00
krangelov
3c5741c846 fix in str_char 2021-10-05 13:36:21 +02:00
krangelov
94884ed59e Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2021-10-05 13:25:01 +02:00
krangelov
6d898fc325 fix the gold standard 2021-10-05 13:24:44 +02:00
John J. Camilleri
c1adbedc25 Implement bootNGF, readNGF, PgfText_FromString 2021-10-05 11:57:24 +02:00
krangelov
557cdb82a7 strings computed from a predefined operation should be tokenized 2021-10-05 11:50:59 +02:00
krangelov
26be741dea most primitives in Predef.gf are now implemented 2021-10-05 11:31:39 +02:00
John J. Camilleri
ca2f2bfd89 Change from ffi to ffi-napi since the former seems unsupported
This should also fix installation problem of node-gyp in CI
2021-10-05 01:02:02 +02:00
John J. Camilleri
634508eaa8 Add linting 2021-10-04 15:26:50 +02:00
John J. Camilleri
1f72ef77c4 Add bootNGF. Organise tests better. 2021-10-04 15:07:23 +02:00
John J. Camilleri
7551926383 Add FFI bindings for all API functions. Implement getCategories and getFunctions 2021-10-04 14:15:35 +02:00
John J. Camilleri
45db11b669 Add proper tests, exception handling, implement getAbstractName 2021-10-04 12:10:29 +02:00
John J. Camilleri
314db3ea7f Beginnings of JavaScript bindings 2021-10-01 12:47:39 +02:00
krangelov
e6960e30f6 fix the estimation of the character size in PgfExprParser::putc 2021-10-01 12:22:15 +02:00
krangelov
c21627950a remove the accidentally added debug messages 2021-10-01 12:01:05 +02:00
krangelov
0708f6e0cc when at EOF don't try to read further 2021-10-01 11:57:31 +02:00
John J. Camilleri
ad0832903a Add FreeHypos function. Remove old Python 2 preproc definition 2021-09-30 10:45:01 +02:00
krangelov
0fa739e6e3 one more test 2021-09-30 05:18:02 +02:00
krangelov
0229329d7c implemented pattern macros 2021-09-29 17:38:53 +02:00
krangelov
6efb878c43 pattern matching for "x"* 2021-09-29 14:57:18 +02:00
krangelov
edd7081dea implement measured patterns 2021-09-29 13:26:06 +02:00
krangelov
2137324f81 safe pattern matching in the presence of a variable 2021-09-29 09:32:09 +02:00
krangelov
86326d282f pattern matching on strings 2021-09-29 09:18:52 +02:00
krangelov
fee186feca fix table selection with meta variables and lambda variables 2021-09-28 13:49:35 +02:00
John J. Camilleri
808e8db141 Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2021-09-28 11:58:31 +02:00
John J. Camilleri
16eb5f1a89 Type initialiser accepts sequences, stores internally as tuples. Add tests which try to break things. 2021-09-28 11:58:22 +02:00
krangelov
28dd0eda22 evaluation for Prod 2021-09-28 11:47:31 +02:00
krangelov
0771906206 Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2021-09-28 11:13:58 +02:00
krangelov
fcad8dd3e2 no more space leaks 2021-09-28 11:13:45 +02:00
krangelov
67f83ebf8a don't add_ref if the revision doesn't exist 2021-09-28 11:12:12 +02:00
John J. Camilleri
388829d63d Make hypos tuples again 😥 2021-09-28 10:35:19 +02:00
krangelov
9863f32d05 fix a memory leak 2021-09-28 09:53:40 +02:00
krangelov
5334174923 fix reference counting but valgrind says that there are more leaks 2021-09-27 20:24:57 +02:00
krangelov
2b725861fb mark 10000000000000000000 as UL 2021-09-27 19:47:24 +02:00
John J. Camilleri
8c3f9c8d73 Use PyBool instead of PyLong for bind_type 2021-09-27 15:37:33 +02:00
John J. Camilleri
7dafeee57b Raise KeyError in prob functions for undefined functions/categories 2021-09-27 14:33:14 +02:00
John J. Camilleri
19251e5e61 Add exprProbability 2021-09-27 14:22:13 +02:00
krangelov
af45e96108 Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2021-09-27 14:12:24 +02:00
krangelov
38de1bf924 pgf_category_prob should return INFINITY for non-existant categories 2021-09-27 14:11:52 +02:00
John J. Camilleri
a7a20d72e7 Use preprocessing directive in module initialisation 2021-09-27 14:03:12 +02:00
krangelov
455fd07e12 Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2021-09-27 13:46:49 +02:00
krangelov
6d234a7d7e bugfix 2021-09-27 13:46:37 +02:00
John J. Camilleri
02d180ad88 Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2021-09-27 13:33:52 +02:00
John J. Camilleri
8c04eed5c3 Add bindings for global/abstract flag functions 2021-09-27 13:33:34 +02:00
krangelov
6c2d180544 Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2021-09-27 13:29:11 +02:00
krangelov
d1e6b78a45 overload ExprApp for backward compatibility 2021-09-27 13:28:53 +02:00
John J. Camilleri
6ce619c146 Solve the mystery of the segfaults when reading args in createCategory
it was a missing `&`
2021-09-27 11:51:58 +02:00
John J. Camilleri
2deae9d402 Add PGF.writeToFile. Add categoryProbability, but it seems pgf_category_prob always returns 0. 2021-09-27 11:37:52 +02:00
John J. Camilleri
187ded6d3d Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2021-09-27 09:40:59 +02:00
John J. Camilleri
6f94957857 Make Hypo its own class instead of using tuples 2021-09-27 09:00:46 +02:00
krangelov
561862e1bd restore Expr_unpack 2021-09-27 08:53:43 +02:00
krangelov
07c3f4b88a fix Expr_visit 2021-09-27 07:27:44 +02:00
krangelov
4dcf43dbf3 make all members READONLY to avoid crashes later 2021-09-27 06:18:33 +02:00
krangelov
97ca7b112c remove Expr_getsetters 2021-09-27 06:15:00 +02:00
krangelov
fbd0be2c3e restore Expr_visit 2021-09-27 06:12:14 +02:00
krangelov
b12e8a6969 fix Expr_call 2021-09-27 05:30:00 +02:00
krangelov
809a02f3bc added Expr_subclass_new 2021-09-26 22:54:09 +02:00
krangelov
3716990b8d remove the redundany _new functions 2021-09-26 21:02:57 +02:00
krangelov
729a3102b4 added Expr_new and Expr_reduce_ex for backward compatibility 2021-09-26 20:34:36 +02:00
John J. Camilleri
28bb236248 Add deallocator functions to all classes 2021-09-26 15:45:34 +02:00
John J. Camilleri
1fce5144f8 Rename fields to match those in runtime. Use tp_members instead of tp_getattro for getters. 2021-09-26 15:14:04 +02:00
krangelov
4a0efda0e6 fix the handling of PGF_EXN_OTHER_ERROR 2021-09-25 08:11:05 +02:00
krangelov
f82f19ba68 better error handling 2021-09-24 19:54:29 +02:00
krangelov
f83ea160da more patterns in the partial evaluator 2021-09-24 19:14:48 +02:00
krangelov
466fd4a7da Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2021-09-24 17:20:48 +02:00
krangelov
c5b6432016 implemented tables and parameters 2021-09-24 17:20:25 +02:00
John J. Camilleri
a46b91fe10 Missed one 'free' 2021-09-24 16:13:36 +02:00
John J. Camilleri
a2e4e74644 Add getters for Type and Expr attributes, with tests 2021-09-24 16:10:48 +02:00
krangelov
ad9fbdef6f added test case for parameters 2021-09-24 15:55:59 +02:00
krangelov
eba37f5b09 fix typo 2021-09-24 15:49:41 +02:00
krangelov
d294033822 added more tests 2021-09-24 15:43:53 +02:00
krangelov
886592f345 renamed tests 2021-09-24 15:41:05 +02:00
krangelov
ac304ccd7c more low-handing fruits in the partial evaluator 2021-09-24 15:14:52 +02:00
krangelov
dea2176115 Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2021-09-24 15:01:01 +02:00
krangelov
3dc2af61a6 done with partial evaluation for records and variants 2021-09-24 15:00:34 +02:00
John J. Camilleri
4719e509a5 Add FreePgfText function 2021-09-24 15:00:10 +02:00
krangelov
d17ca06faf Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2021-09-24 13:57:29 +02:00
krangelov
a9a8ed8bf3 fix the dependency on librt 2021-09-24 13:57:11 +02:00
John J. Camilleri
fc12749124 Complete transaction tests 2021-09-24 13:46:46 +02:00
krangelov
2c01eab355 Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2021-09-24 13:36:21 +02:00
krangelov
d72017409a added -lrt 2021-09-24 13:35:51 +02:00
John J. Camilleri
90b7134eef Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2021-09-24 13:09:36 +02:00
John J. Camilleri
d0ce218ae1 Add helper functions for common conversions 2021-09-24 13:09:26 +02:00
John J. Camilleri
917c223db7 Add checkoutBranch function. Fix incorrect INCREF of non-Python object. 2021-09-24 11:47:46 +02:00
krangelov
bd629452ac Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2021-09-24 11:26:49 +02:00
krangelov
bdd84f10f9 got started on inter-process communication 2021-09-24 11:25:58 +02:00
John J. Camilleri
139e851f22 Add null check before freeing DB
Was causing segfaults in load-failure tests
2021-09-24 08:20:31 +02:00
John J. Camilleri
0ff4b0079d Minor changes to transactions.md 2021-09-24 07:57:52 +02:00
Krasimir Angelov
00d5b238a3 Update transactions.md 2021-09-23 17:56:09 +02:00
Krasimir Angelov
c843cec096 Update transactions.md 2021-09-23 15:28:49 +02:00
Krasimir Angelov
3ee0d54878 Update transactions.md 2021-09-23 15:07:13 +02:00
Krasimir Angelov
5e46c27d86 Update transactions.md 2021-09-23 15:01:19 +02:00
Krasimir Angelov
2a3d5cc617 Update transactions.md 2021-09-23 14:07:50 +02:00
Krasimir Angelov
001e727c29 Update transactions.md 2021-09-23 13:35:11 +02:00
Krasimir Angelov
cb6d3c4a2d Update transactions.md 2021-09-23 13:03:18 +02:00
Krasimir Angelov
cfc1e15fcf Update transactions.md 2021-09-23 12:01:28 +02:00
Krasimir Angelov
bebd56438b Update transactions.md 2021-09-23 10:59:36 +02:00
krangelov
a2102b43bd got started with the new partial evaluation 2021-09-22 18:17:50 +02:00
krangelov
c4f739c754 Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2021-09-22 18:14:44 +02:00
krangelov
18e54abf12 make it possible to run specific tests 2021-09-22 18:14:18 +02:00
John J. Camilleri
4611d831ff Add helper function for checking and converting list of hypos 2021-09-22 15:37:33 +02:00
John J. Camilleri
21ee96da9b Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2021-09-22 15:14:49 +02:00
John J. Camilleri
b1fd1f1a5e Fix segfaults with Python 3.8 in Transaction_createCategory. Tweaks to enter/exit functions. 2021-09-22 15:14:42 +02:00
krangelov
bcbf9efa5f started a page about transactions 2021-09-22 14:44:56 +02:00
krangelov
2d74fc4d64 Merge branch 'master' into majestic 2021-09-22 14:15:35 +02:00
krangelov
e4b2f281d9 Merge branch 'master' of github.com:GrammaticalFramework/gf-core 2021-09-22 14:11:27 +02:00
krangelov
063c517f3c more tests for variants 2021-09-22 14:11:11 +02:00
krangelov
dd65f9f365 a better way to handle double releases 2021-09-22 13:44:03 +02:00
krangelov
e11e775a96 merge pgf_free and pgf_free_revision since otherwise we cannot control the finalizers in Haskell 2021-09-22 13:21:07 +02:00
krangelov
74c63b196f Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2021-09-22 11:16:52 +02:00
krangelov
58b8c2771e fix double release for stable pointers 2021-09-22 11:16:29 +02:00
krangelov
be43b0ba35 fix variable type 2021-09-22 11:03:16 +02:00
krangelov
1d1d1aad81 small optimization 2021-09-22 11:02:45 +02:00
John J. Camilleri
04fcaaaac2 Declare context differently in Transaction_createCategory
This is an attempt to try fix the segfaults in CI which I cannot reproduce locally
2021-09-22 08:34:18 +02:00
krangelov
70566fc6d6 Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2021-09-22 07:35:30 +02:00
krangelov
432bc26b23 bugfix in PgfExprProbEstimator 2021-09-22 07:35:07 +02:00
John J. Camilleri
60c9ab4c53 Fix handlers for 'with' syntax in Transaction object 2021-09-21 23:54:55 +02:00
John J. Camilleri
4af807c982 Fix createCategory. Add functionProbability. 2021-09-21 23:34:03 +02:00
John J. Camilleri
b4b8572af3 Header and source file cleanup 2021-09-21 22:28:44 +02:00
John J. Camilleri
71dac482c8 Started adding support for 'with' construct, failing tests commented out 2021-09-21 17:23:38 +02:00
John J. Camilleri
6edf7e6405 Add Transaction type to Python bindings, get first tests working. 2021-09-21 14:55:20 +02:00
John J. Camilleri
7dba3465d0 Refactor modules in Python bindings. Start work on grammar-update functions, but without transactions. 2021-09-20 23:42:50 +02:00
krangelov
e41feae82a database synchronization only on commit 2021-09-17 16:43:54 +02:00
John J. Camilleri
44b5d0f870 Add newNGF to Python bindings 2021-09-17 14:33:36 +02:00
John J. Camilleri
6359537894 Add last of tests from basic.hs to Python testsuite. Some tests with quoted identifiers skipped. 2021-09-17 13:53:53 +02:00
krangelov
348c348e14 the compiler can now boot and load an .ngf file 2021-09-17 13:15:58 +02:00
krangelov
b583faa042 Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2021-09-17 12:01:28 +02:00
krangelov
2e30c7f6cb bugfix 2021-09-17 12:01:14 +02:00
John J. Camilleri
a3203143ba Add Type constructor, showType, mk[Dep]Hypo, bind type constants 2021-09-17 11:27:19 +02:00
krangelov
ddb01b41be In case of exception, report the offending function 2021-09-17 11:22:18 +02:00
krangelov
3f31d86d0d errno is not set for FILE I/O so we do our best 2021-09-17 10:06:11 +02:00
John J. Camilleri
a8bda009a4 Add and pass all the abstraction test cases. Some header cleanup. 2021-09-16 15:38:02 +02:00
John J. Camilleri
b393efff59 Fix richcompare functions: second argument could be of any type 2021-09-16 13:28:30 +02:00
krangelov
f456f09054 finally fix the test caused by the change in readNGF behaviour 2021-09-16 12:08:22 +02:00
krangelov
24a30b344e another fix 2021-09-16 12:04:25 +02:00
krangelov
89e99d829c fix the tests in richcompare 2021-09-16 11:50:50 +02:00
krangelov
56d47ad561 forgot to update the testsuite 2021-09-16 11:31:09 +02:00
krangelov
c4fee30baf fix the compilation in Type_richcompare and simplify a bit 2021-09-16 11:26:40 +02:00
krangelov
b408650125 createFunction now takes arity as argument 2021-09-16 11:04:45 +02:00
krangelov
fc268a16df We can now compile abstract grammars 2021-09-16 10:59:48 +02:00
krangelov
a79fff548d readNGF now fails if the file doesn't exist. Instead there is newNGF 2021-09-16 10:34:51 +02:00
krangelov
3d0450cb2a Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2021-09-15 19:59:09 +02:00
krangelov
e00be98ac6 added writePGF 2021-09-15 19:58:42 +02:00
John J. Camilleri
238f01c9fc Add remaining Expr subclasses, tests failing 2021-09-15 16:27:58 +02:00
krangelov
c6d6914688 switch to using FILE * in the reader 2021-09-15 08:06:18 +02:00
krangelov
9fe6ee3cce bugfixes for showContext & showType 2021-09-14 19:54:38 +02:00
krangelov
a7bf47cb87 added showContext 2021-09-14 19:10:01 +02:00
krangelov
3675e5cfc6 Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2021-09-14 17:33:43 +02:00
krangelov
e82fb7f32f added exprProbability 2021-09-14 17:33:22 +02:00
John J. Camilleri
fd61a6c0d3 Add ExprApp to Python bindings 2021-09-14 15:28:39 +02:00
John J. Camilleri
6ebb8e5fda Add ExprFun to Python bindings 2021-09-14 15:07:03 +02:00
krangelov
05813384e0 Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2021-09-14 09:34:22 +02:00
krangelov
22f62be511 added PGF(pIdent,pExpr) 2021-09-14 09:34:00 +02:00
John J. Camilleri
be5751060a Add showExpr and tests for it using variable expressions 2021-09-14 00:18:45 +02:00
John J. Camilleri
9e3d329528 Update behaviour for bindings to categoryContext when cat is non-existant 2021-09-13 22:44:04 +02:00
John J. Camilleri
a715d029f7 Fix Haskell tests after changes to categoryContext and functionProb 2021-09-13 22:35:23 +02:00
John J. Camilleri
e78e9102be Add variable expressions 2021-09-13 22:29:23 +02:00
krangelov
cf7673525f the compiler now compiles with the new runtime 2021-09-13 18:32:57 +02:00
John J. Camilleri
c5ce2fd4b7 Add ExprMeta type, with two basic tests 2021-09-13 16:18:32 +02:00
John J. Camilleri
d8a7aef46b Add constructor for ExprLit, use it in tests 2021-09-13 15:47:15 +02:00
John J. Camilleri
7e747fbd17 int -> size_t 2021-09-13 15:23:07 +02:00
John J. Camilleri
3d25efd38a Add functionIsConstructor function 2021-09-13 15:15:16 +02:00
John J. Camilleri
c83a31708d Add categoryContext function 2021-09-13 15:05:38 +02:00
John J. Camilleri
919fd5d83e Make Expr_str work for large (size > 1) and negative integers 2021-09-13 14:38:05 +02:00
John J. Camilleri
5f5bd7a83b Implement Expr_str correctly (but doesn't handle big ints yet) 2021-09-13 10:03:26 +02:00
John J. Camilleri
cb6d385fc0 Un-skip read/boot tests 2021-09-13 09:13:36 +02:00
krangelov
6cb4bef521 added API for accessing flags 2021-09-12 12:57:45 +02:00
krangelov
f1e1564228 the reader now controls the PGF version 2021-09-12 08:26:05 +02:00
krangelov
a7f00a4e84 detect and report an attempt to load non .ngf file in readNGF 2021-09-12 08:11:10 +02:00
krangelov
375452063f fix the crashes 2021-09-11 23:32:50 +02:00
krangelov
08923a57b9 fix typo 2021-09-11 22:46:15 +02:00
krangelov
6cfa250b28 PgfDB::sync is now moved to the desctructor for DB_scope 2021-09-11 18:20:28 +02:00
krangelov
4e443374de restore the thread local declarations that were accidentally removed 2021-09-11 18:06:28 +02:00
krangelov
ae0a6aa6b6 clean up everything after revision is not needed anymore. 2021-09-11 16:33:22 +02:00
krangelov
7f0eb34864 fix typo 2021-09-10 22:31:51 +02:00
krangelov
1b09e7293f implemented pgf_free_revision 2021-09-10 11:39:54 +02:00
John J. Camilleri
678d244b21 Trying to complete Type marshaller, keep getting segfaults 2021-09-10 00:28:16 +02:00
John J. Camilleri
2f51c8471c Fix conversion from PyUnicode to PgfText. Remove Python 2-style PyString macros. 2021-09-09 23:41:55 +02:00
John J. Camilleri
4739e3d779 Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2021-09-09 20:42:07 +02:00
John J. Camilleri
8bc171d7a1 Remove int tag from ExprLitObject 2021-09-09 20:42:01 +02:00
krangelov
7c622d2621 fix the definition of PgfMarshallerVtbl for C 2021-09-09 17:58:18 +02:00
krangelov
2f9c784fed Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2021-09-09 17:34:12 +02:00
krangelov
f7aad0c0e0 added createCategory, dropCategory 2021-09-09 17:33:25 +02:00
John J. Camilleri
5eade6f111 Generalise error handling 2021-09-09 11:16:10 +02:00
krangelov
a44787fc4e forgot to add the type signature for pgf_drop_function in the header 2021-09-09 09:52:43 +02:00
krangelov
97c76a9030 Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2021-09-09 09:47:44 +02:00
krangelov
28321cc023 added dropFunction 2021-09-09 09:47:26 +02:00
John J. Camilleri
175349175a Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2021-09-09 09:34:13 +02:00
John J. Camilleri
1d0c4e7c39 Handle unmarshalling of large ints in Python bindings 2021-09-09 09:34:05 +02:00
krangelov
0dae265b05 expand the comment about PgfExn 2021-09-09 07:25:57 +02:00
krangelov
36ccb7ac8f PGF_API -> PGF_API_DECL 2021-09-09 07:22:25 +02:00
krangelov
6e4681d46b Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2021-09-09 07:21:11 +02:00
krangelov
3d4c6031d8 missing call to free after the call to pgf_abstract_name 2021-09-09 07:20:15 +02:00
John J. Camilleri
9739344ca6 Support (small, size = 1) negative integers 2021-09-08 17:25:10 +02:00
John J. Camilleri
3b1907cd8c Add Expr and ExprLit types to Python bindings. Seem to work for readExpr. 2021-09-08 16:03:54 +02:00
krangelov
44ee5718e9 more friendly PgfDB::malloc 2021-09-08 14:27:52 +02:00
krangelov
9d63c8a903 Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2021-09-08 14:10:33 +02:00
krangelov
bcc33af36b added support for branches and explicit transaction commit 2021-09-08 14:09:23 +02:00
John J. Camilleri
c9b7f8e5ee Add exception object to parameters of updated function calls 2021-09-08 11:53:31 +02:00
krangelov
2e846cdf59 added safeguard to ensure that PgfRevision is an actual object 2021-09-08 09:17:12 +02:00
krangelov
f741bd9332 more functions could now fail with an exception 2021-09-07 17:18:03 +02:00
krangelov
a843ddba55 better error handling which always reports the right file name 2021-09-07 15:54:27 +02:00
krangelov
8936e6211e add <*> to Applicative for Transaction 2021-09-07 13:31:28 +02:00
krangelov
31396e46e3 disable rtti 2021-09-07 13:19:02 +02:00
krangelov
e1c23da0a6 forgot updating the header as well 2021-09-07 09:49:45 +02:00
krangelov
2444302482 Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2021-09-07 09:45:59 +02:00
krangelov
4ea4450481 mark methods in PgfDB as internal 2021-09-07 09:45:30 +02:00
John J. Camilleri
e6d8b76dbf Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic
# Conflicts:
#	src/runtime/python/pypgf.c
2021-09-06 23:52:30 +02:00
John J. Camilleri
5b96ede199 Work in progress with marshalling in Python bindings, trying to get Type_str to work without segfaulting 2021-09-06 23:49:53 +02:00
krangelov
1ec4949d90 added working transactions. still not atomic 2021-09-06 19:40:24 +02:00
krangelov
29557ae61e bugfix in the FFI for pgf_function_prob 2021-09-06 19:25:56 +02:00
krangelov
691d3389f7 bugfix in PgfDBUnmarshaller::dtyp 2021-09-06 19:16:26 +02:00
krangelov
9cea2cc70e change the API to allow different grammar revisions 2021-09-06 15:49:39 +02:00
John J. Camilleri
b7cddf206b First attempts at marshalling in Python bindings, not really sure what I'm doing 2021-09-06 15:32:18 +02:00
John J. Camilleri
d58c744361 Implement PGF_getStartCat in Python bindings 2021-09-06 14:15:28 +02:00
John J. Camilleri
a8efc61579 Working readType, functionType, unmarshaller for types (except exprs) in Python bindings 2021-09-06 14:06:57 +02:00
krangelov
9a2d2b345d an unsafe API for adding functions to the grammar. breaks referential transparency 2021-09-04 07:10:04 +02:00
krangelov
55d30d70f5 added PgfDBUnmarshaller 2021-09-04 05:59:11 +02:00
krangelov
b4838649f5 linear time loading of namespaces 2021-09-03 21:10:26 +02:00
krangelov
2e0c93c594 Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2021-09-03 20:02:22 +02:00
krangelov
4c5aad5883 use reference counting to release the namespaces 2021-09-03 20:01:13 +02:00
krangelov
fb2454767a add method "free" 2021-09-03 19:58:28 +02:00
krangelov
4655c2663a fix the memory allocator 2021-09-03 19:57:53 +02:00
krangelov
7f7fe59fc0 fix incorrect index 2021-09-03 19:55:02 +02:00
John J. Camilleri
d53b7587f5 Fill in literal cases in Python unmarshaller (untested) 2021-09-03 15:26:10 +02:00
John J. Camilleri
3ecb937753 Start work on marshalling in Python bindings 2021-09-03 14:14:47 +02:00
Krasimir Angelov
2daf9e2e19 Update abstract_expressions.md 2021-08-31 21:57:13 +02:00
Krasimir Angelov
e03df47911 Update abstract_expressions.md 2021-08-31 21:56:15 +02:00
krangelov
6c06a9f295 readExpr needs an additional call to mask_ 2021-08-31 20:02:49 +02:00
krangelov
3c8e96c3cd fix lint in the C version of PgfUnmarshaller 2021-08-31 19:39:06 +02:00
krangelov
7b9f5144f9 functionsByCat now supports strings containing \0 2021-08-31 18:38:17 +02:00
Krasimir Angelov
6b359a6362 Update abstract_expressions.md 2021-08-31 13:01:04 +02:00
krangelov
4a0b1f2f67 Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2021-08-31 10:21:45 +02:00
krangelov
b1dd94e4b0 fix the testsuite failure after the second run 2021-08-31 10:20:51 +02:00
John J. Camilleri
8061a9e82a Replace uses of PyUnicode_FromString with PyUnicode_FromStringAndSize
See https://github.com/GrammaticalFramework/gf-core/issues/130#issuecomment-908979886
2021-08-31 10:12:27 +02:00
John J. Camilleri
901c3f9086 Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2021-08-31 10:07:55 +02:00
John J. Camilleri
32f6691024 Update error handling in Python bindings, using the new PGF_EXN_OTHER_ERROR 2021-08-31 10:07:42 +02:00
krangelov
5f5b0caba5 more the exception handling in a single place 2021-08-31 10:04:33 +02:00
krangelov
0bf7522291 expand the comment for PGF_EXN_OTHER_ERROR 2021-08-31 09:49:33 +02:00
krangelov
a7321a2e5a Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2021-08-31 09:33:50 +02:00
krangelov
e0288f46dc the namespace iterator now takes a PgfExn parameter like in the old runtime 2021-08-31 09:31:06 +02:00
John J. Camilleri
02dc4e83c5 Remove commented-out error-handling code
See https://github.com/GrammaticalFramework/gf-core/issues/130#issuecomment-908937688
2021-08-31 09:16:16 +02:00
John J. Camilleri
aecaa422ec Add getFunctionsByCat to Python bindings 2021-08-30 23:25:18 +02:00
John J. Camilleri
b7bd5a4561 Add getCategories and getFunctions to Python bindings, but don't know how to handle errors? 2021-08-30 22:26:22 +02:00
John J. Camilleri
50e54d131b Add abstractName getter to Python bindings. Use line comments (//) to make navigating code easier. 2021-08-30 15:03:54 +02:00
John J. Camilleri
ff30169cbf Update CI workflow with new Python test command 2021-08-30 13:46:34 +02:00
John J. Camilleri
3e4f2ba1a0 Use pytest for Python bindings test suite 2021-08-30 13:31:27 +02:00
John J. Camilleri
239fd02249 Add more test cases for read/boot failures, those which incorrectly fail are commented out 2021-08-30 13:22:49 +02:00
John J. Camilleri
ad4600b5c4 Add bootNGF and readNGF to Python bindings 2021-08-30 10:38:10 +02:00
John J. Camilleri
5c5e26cc8d Test bootNGF and readNGF too, run tests on all three PGFs 2021-08-30 09:45:02 +02:00
Krasimir Angelov
f25b518186 Update abstract_expressions.md 2021-08-27 18:25:46 +02:00
krangelov
e9ec4cef67 fill in more gaps in the API 2021-08-27 15:05:42 +02:00
krangelov
3e7d80bf30 reading & showing unicode identifiers 2021-08-27 14:44:42 +02:00
krangelov
41ef5f9539 textdup is now safe in case of memory overflow 2021-08-27 13:03:11 +02:00
krangelov
5271ddd10b PgfPrinter::nprintf dynamically reallocates the printing buffer if needed 2021-08-27 11:57:58 +02:00
krangelov
8195f8b0cb support for unbounded integers 2021-08-27 11:31:10 +02:00
krangelov
684f85ff94 hide PgfDBMarshaller 2021-08-26 19:49:27 +02:00
krangelov
a00a7f4ba5 elaborate the comment about marshallers and unmarshallers 2021-08-26 18:01:25 +02:00
Krasimir Angelov
5982dbc146 Update README.md 2021-08-26 17:38:58 +02:00
Krasimir Angelov
9b2813f48a Create abstract_expressions.md 2021-08-26 17:38:28 +02:00
krangelov
b28e891a6b a type annotated version of marshaller/unmarshaller 2021-08-26 17:27:34 +02:00
krangelov
59e54482a3 added PgfDBMarshaller 2021-08-26 16:36:37 +02:00
krangelov
69f74944e2 The unmarshaller is no longer stored in the PGF object but is passed explicitly to each function that needs it. 2021-08-26 16:14:56 +02:00
krangelov
0d9f2994a0 Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2021-08-26 15:46:41 +02:00
krangelov
275addfcbe pretty printing for expressions and types 2021-08-26 15:46:16 +02:00
John J. Camilleri
03f02ae5d2 A bunch of superficial changes to the docs after reading through them carefully again 2021-08-24 11:27:10 +02:00
John J. Camilleri
fdaf19a5d4 Bump version of Python bindings 2021-08-24 10:04:07 +02:00
John J. Camilleri
91adc09b1f Define LD_LIBRARY_PATH when running Python tests 2021-08-24 09:09:30 +02:00
John J. Camilleri
beab2ad899 Update Python instructions, add simple testsuite (which fails with segmentation fault) 2021-08-24 09:05:16 +02:00
John J. Camilleri
bedb46527d Move Thomas from current to previous on maintainers page 2021-08-17 10:18:34 +02:00
John J. Camilleri
0258a87257 Add IRC, Discord, SO links to "contribute" section at top of homepage 2021-08-17 09:57:50 +02:00
John J. Camilleri
ef0e831c9e Update installation instructions from Hackage, source code 2021-08-17 09:38:20 +02:00
Inari Listenmaa
8ec13b1030 Uncomment installation instructions from Hackage 2021-08-16 09:07:59 +08:00
krangelov
07bda06fb2 missed a line 2021-08-14 21:16:20 +02:00
krangelov
d28c5a0377 a hopefully better error management in the marshaller 2021-08-14 21:13:31 +02:00
krangelov
8b8028bdfe free_ref & free_me in PgfMarshaller too 2021-08-14 20:08:04 +02:00
krangelov
9db352b2bb bugfix 2021-08-14 18:51:16 +02:00
krangelov
b627d4ceb0 fix typo 2021-08-13 20:33:00 +02:00
krangelov
0296f07651 Merge branch 'majestic' of github.com:GrammaticalFramework/gf-core into majestic 2021-08-13 19:29:39 +02:00
krangelov
6beac74265 a draft for the marshaller. still not in use 2021-08-13 19:25:12 +02:00
krangelov
221f0b7853 PgfUnmarshaller now mimics a C++ class. Allows for keeping state 2021-08-13 18:14:56 +02:00
John J. Camilleri
4fd70bc445 Add basic installation instructions 2021-08-13 10:47:06 +02:00
John J. Camilleri
9e5823c350 Tweak base upper bound in pgf2.cabal 2021-08-13 10:28:44 +02:00
John J. Camilleri
2346abeedb Tweaks to pgf2.cabal 2021-08-13 10:25:16 +02:00
John J. Camilleri
3e7926f22d Update pgf2.cabal, including bumping version to 2.0.0 2021-08-13 10:20:49 +02:00
John J. Camilleri
f35dff7c66 Add LD_LIBRARY_PATH to cabal test step 2021-08-13 10:04:21 +02:00
John J. Camilleri
1749908f6c Add --extra-lib-dirs to cabal command 2021-08-13 09:58:31 +02:00
John J. Camilleri
d8e1e2c37d Add sudo to make install 2021-08-13 09:53:17 +02:00
John J. Camilleri
8877243701 Add tests to CI 2021-08-13 09:51:10 +02:00
krangelov
08bcd2f0b5 silence warnings 2021-08-13 08:28:30 +02:00
krangelov
1bc0cfd025 accidentally commited a wrong version of expr.cxx 2021-08-13 08:26:18 +02:00
krangelov
21044264fa forgot adding expr.cxx 2021-08-13 08:12:03 +02:00
John J. Camilleri
058526ec5d Remove Travis CI workflow, we use GitHub actions now
Closes #123
2021-08-12 15:27:10 +02:00
John J. Camilleri
974e8b0835 Typos in homepage 2021-08-12 15:20:29 +02:00
John J. Camilleri
bbe4682c3d Update homepage
- Add Discord link
- Point to GitHub issues, Stack Overflow in "Getting help"
- Remove old news
2021-08-12 15:19:17 +02:00
krangelov
2a8d4232ce Fun -> Cat 2021-08-12 14:45:49 +02:00
krangelov
352dedc26f forgot releasing a stable pointer 2021-08-12 14:45:05 +02:00
krangelov
7e35db47a6 export PGFError 2021-08-12 14:41:50 +02:00
krangelov
edba4fda32 test that we can handle loading failures 2021-08-12 14:23:20 +02:00
krangelov
a8403d48fa the unmarshaller should not be disposed twice in case of error 2021-08-12 14:16:19 +02:00
krangelov
3578355bd0 fix computing the size of the mapped area 2021-08-12 14:04:35 +02:00
krangelov
39f38ed0e2 added startCat 2021-08-12 12:39:05 +02:00
krangelov
01db0224be API for constructing types 2021-08-12 12:16:11 +02:00
krangelov
16dfcb938c more of the abstract API copied from the old runtimes 2021-08-12 12:06:50 +02:00
krangelov
0ece508716 added categoryProb, functionProb, functionIsConstructor 2021-08-12 11:10:27 +02:00
krangelov
72993a178a Merge branch 'majestic' of https://github.com/GrammaticalFramework/gf-core into majestic 2021-08-12 10:42:24 +02:00
krangelov
f2da618e5d implemented categoryContext 2021-08-12 10:42:02 +02:00
krangelov
c97b736a5b fix the reading of expressions 2021-08-12 10:41:23 +02:00
krangelov
82ce76a2ce fix allocation to ensure that top is properly aligned from the beginning 2021-08-12 10:40:33 +02:00
krangelov
d2aec60612 fix typos 2021-08-12 10:38:55 +02:00
John J. Camilleri
ddfc599db3 Add sudo to apt commands 2021-08-12 10:34:38 +02:00
John J. Camilleri
cb30e176bd Add CI workflow for building runtime 2021-08-12 10:33:45 +02:00
John J. Camilleri
e477ce4b1f HTML fix on homepage 2021-08-12 10:05:45 +02:00
John J. Camilleri
7a63ba34b4 Add changelog
This will hopefully help us keep track of changes for the next release
2021-08-12 09:56:34 +02:00
krangelov
c482d3466c added != operator removed function null() 2021-08-12 08:49:20 +02:00
krangelov
4abe7836e0 test case for functionType 2021-08-12 07:53:55 +02:00
krangelov
2c1700776e implemented readExpr & readType 2021-08-11 22:07:01 +02:00
krangelov
a5008c2fe1 implemented functionType and marshalling for types and expressions 2021-08-10 15:07:41 +02:00
John J. Camilleri
723bec1ba0 Changes made in order to get Hackage upload working 2021-08-09 13:41:25 +02:00
krangelov
7b5669a333 Merge branch 'majestic' of https://github.com/GrammaticalFramework/gf-core into majestic 2021-08-08 18:30:07 +02:00
krangelov
91f183ca6a move the C sources to the subfolder pgf again for backwards compatibility 2021-08-08 18:29:16 +02:00
Krasimir Angelov
0187be04ff Update memory_model.md 2021-08-08 16:50:16 +02:00
krangelov
f70e1b8772 fix the DB_scope in pgf_read_ngf 2021-08-08 16:29:51 +02:00
krangelov
8d1cc22622 fix typo 2021-08-08 16:24:29 +02:00
krangelov
e7bd7d00b3 remove the newly created .ngf on error. 2021-08-08 16:20:41 +02:00
krangelov
f3e579bbb1 implement DB_scopes 2021-08-08 16:17:24 +02:00
krangelov
11b630adc1 Merge branch 'majestic' of https://github.com/GrammaticalFramework/gf-core into majestic 2021-08-08 16:12:00 +02:00
krangelov
1088b4ef38 implement grammar loading from Python 2021-08-08 16:11:23 +02:00
Krasimir Angelov
db8843c8bf Update memory_model.md 2021-08-07 20:39:09 +02:00
Krasimir Angelov
bfd839b7b0 Update README.md 2021-08-07 18:29:59 +02:00
Krasimir Angelov
78d6282da2 Create README.md 2021-08-07 18:29:31 +02:00
Krasimir Angelov
cc8db24a46 Update memory_model.md 2021-08-07 10:36:34 +02:00
Krasimir Angelov
72c51f4bf9 Create memory_model.md 2021-08-07 09:44:50 +02:00
krangelov
3a7743afad added the expression type 2021-08-06 20:03:22 +02:00
krangelov
825e8447db make it possible to load several grammars in the same process and ensure reader-writer exclusion 2021-08-06 19:34:02 +02:00
krangelov
2d6bcd1953 a better API for loading PGF & NGF files 2021-08-06 16:50:21 +02:00
krangelov
dc1644563f extend the abstract syntax API 2021-08-06 12:43:30 +02:00
krangelov
87f1e24384 started a testsuite 2021-08-05 20:45:08 +02:00
krangelov
36e87668e0 make sure that changes in the database are always flushed 2021-08-05 20:05:29 +02:00
krangelov
2d3aac5aa1 fixed white space 2021-08-05 19:30:50 +02:00
krangelov
217e0d8cc6 added function abstractName from the API 2021-08-05 19:30:05 +02:00
krangelov
75e19bbffa document the exception handling 2021-08-05 18:05:42 +02:00
krangelov
cc4a215f83 fix the memory leak in case of exceptions 2021-08-05 17:58:04 +02:00
krangelov
7d85d3ca9a fix: when PGF loading forgot reading "functions per cat" 2021-08-05 17:13:11 +02:00
krangelov
e298410e57 read_name -> read_text in literals 2021-08-05 17:06:05 +02:00
krangelov
5e320943c9 started on the Haskell binding 2021-08-05 17:01:49 +02:00
krangelov
54421492b2 fix the balancing to avoid segmentation faults 2021-08-05 16:28:50 +02:00
krangelov
84789c9fbf finished reading the abstract syntax 2021-08-05 12:37:12 +02:00
krangelov
17629e4821 strings are stored as length+text and NULL byte is not a terminator 2021-07-30 13:45:22 +02:00
Krasimir Angelov
a8b3537184 Create DESIDERATA.md 2021-07-30 12:55:33 +02:00
krangelov
db1871cf55 Merge branch 'c-runtime' into majestic 2021-07-30 12:11:19 +02:00
krangelov
8f0a1b8fee started a new database-backed runtime from scratch 2021-07-30 12:08:28 +02:00
658 changed files with 46442 additions and 61307 deletions

View File

@@ -18,7 +18,7 @@ jobs:
ghc:
- "8.6.5"
- "8.8.3"
- "8.10.1"
- "8.10.7"
exclude:
- os: macos-latest
ghc: 8.8.3
@@ -33,7 +33,7 @@ jobs:
- uses: actions/checkout@v2
if: github.event.action == 'opened' || github.event.action == 'synchronize' || github.event.ref == 'refs/heads/master'
- uses: haskell/actions/setup@v1
- uses: haskell/actions/setup@v1.2.9
id: setup-haskell-cabal
name: Setup Haskell
with:
@@ -66,25 +66,32 @@ jobs:
strategy:
matrix:
stack: ["latest"]
ghc: ["7.10.3","8.0.2", "8.2.2", "8.4.4", "8.6.5", "8.8.4"]
ghc: ["7.10.3","8.0.2", "8.2.2", "8.4.4", "8.6.5", "8.8.4", "8.10.7", "9.0.2"]
# ghc: ["8.8.3"]
steps:
- uses: actions/checkout@v2
if: github.event.action == 'opened' || github.event.action == 'synchronize' || github.event.ref == 'refs/heads/master'
- uses: haskell/actions/setup@v1
- uses: haskell/actions/setup@v1.2.9
name: Setup Haskell Stack
with:
ghc-version: ${{ matrix.ghc }}
stack-version: 'latest'
enable-stack: true
# Fix linker errrors on ghc-7.10.3 for ubuntu (see https://github.com/commercialhaskell/stack/blob/255cd830627870cdef34b5e54d670ef07882523e/doc/faq.md#i-get-strange-ld-errors-about-recompiling-with--fpic)
- run: sed -i.bak 's/"C compiler link flags", "/&-no-pie /' /home/runner/.ghcup/ghc/7.10.3/lib/ghc-7.10.3/settings
if: matrix.ghc == '7.10.3'
- uses: actions/cache@v1
name: Cache ~/.stack
with:
path: ~/.stack
key: ${{ runner.os }}-${{ matrix.ghc }}-stack
key: ${{ runner.os }}-${{ matrix.ghc }}-stack--${{ hashFiles(format('stack-ghc{0}', matrix.ghc)) }}
restore-keys: |
${{ runner.os }}-${{ matrix.ghc }}-stack
- name: Build
run: |

369
.github/workflows/build-majestic.yml vendored Normal file
View File

@@ -0,0 +1,369 @@
name: Build majestic runtime
on: push
env:
LD_LIBRARY_PATH: /usr/local/lib
jobs:
linux-runtime:
name: Runtime (Linux)
runs-on: ubuntu-latest
container:
image: quay.io/pypa/manylinux2014_x86_64:2024-01-08-eb135ed
steps:
- uses: actions/checkout@v3
- name: Build runtime
working-directory: ./src/runtime/c
run: |
autoreconf -i
./configure
make
make install
- name: Upload artifact
uses: actions/upload-artifact@v3
with:
name: libpgf-linux
path: |
/usr/local/lib/libpgf*
/usr/local/include/pgf
linux-haskell:
name: Haskell (Linux)
runs-on: ubuntu-latest
needs: linux-runtime
steps:
- uses: actions/checkout@v3
- name: Download artifact
uses: actions/download-artifact@v3
with:
name: libpgf-linux
- run: |
sudo mv lib/* /usr/local/lib/
sudo mv include/* /usr/local/include/
- name: Setup Haskell
uses: haskell/actions/setup@v2
with:
ghc-version: 8
- name: Install Haskell build tools
run: |
cabal v1-install alex happy
- name: build and test the runtime
working-directory: ./src/runtime/haskell
run: |
cabal v1-install --extra-lib-dirs=/usr/local/lib
cabal test --extra-lib-dirs=/usr/local/lib
- name: build the compiler
working-directory: ./src/compiler
run: |
cabal v1-install
- name: Upload artifact
uses: actions/upload-artifact@master
with:
name: compiler-linux
path: |
~/.cabal/bin/gf
linux-python:
name: Python (Linux)
runs-on: ubuntu-latest
needs: linux-runtime
steps:
- uses: actions/checkout@v3
- name: Download artifact
uses: actions/download-artifact@v3
with:
name: libpgf-linux
- name: Install cibuildwheel
run: |
python3 -m pip install git+https://github.com/joerick/cibuildwheel.git@main
- name: Install and test bindings
env:
CIBW_BEFORE_BUILD: cp -r lib/* /usr/lib/ && cp -r include/* /usr/include/
CIBW_TEST_REQUIRES: pytest
CIBW_TEST_COMMAND: "pytest {project}/src/runtime/python"
CIBW_SKIP: "pp* *i686 *musllinux_x86_64"
run: |
python3 -m cibuildwheel src/runtime/python --output-dir wheelhouse
- uses: actions/upload-artifact@master
with:
name: python-linux
path: ./wheelhouse
# linux-javascript:
# name: JavaScript (Linux)
# runs-on: ubuntu-latest
# needs: linux-runtime
#
# steps:
# - uses: actions/checkout@v3
# - name: Download artifact
# uses: actions/download-artifact@master
# with:
# name: libpgf-linux
# - run: |
# sudo mv lib/* /usr/local/lib/
# sudo mv include/* /usr/local/include/
#
# - name: Setup Node.js
# uses: actions/setup-node@v2
# with:
# node-version: '12'
#
# - name: Install dependencies
# working-directory: ./src/runtime/javascript
# run: |
# npm ci
#
# - name: Run testsuite
# working-directory: ./src/runtime/javascript
# run: |
# npm run test
# ----------------------------------------------------------------------------
macos-runtime:
name: Runtime (macOS)
runs-on: macOS-11
steps:
- uses: actions/checkout@v3
- name: Install build tools
run: |
brew install \
autoconf \
automake \
libtool \
- name: Build runtime
working-directory: ./src/runtime/c
run: |
glibtoolize
autoreconf -i
./configure
make
sudo make install
- name: Upload artifact
uses: actions/upload-artifact@master
with:
name: libpgf-macos
path: |
/usr/local/lib/libpgf*
/usr/local/include/pgf
macos-haskell:
name: Haskell (macOS)
runs-on: macOS-11
needs: macos-runtime
steps:
- uses: actions/checkout@v3
- name: Download artifact
uses: actions/download-artifact@master
with:
name: libpgf-macos
- run: |
sudo mv lib/* /usr/local/lib/
sudo mv include/* /usr/local/include/
- name: Setup Haskell
uses: haskell/actions/setup@v2
with:
ghc-version: 8
- name: Build & run testsuite
working-directory: ./src/runtime/haskell
run: |
cabal test --extra-lib-dirs=/usr/local/lib
macos-python:
name: Python (macOS)
runs-on: macOS-11
needs: macos-runtime
env:
EXTRA_INCLUDE_DIRS: /usr/local/include
EXTRA_LIB_DIRS: /usr/local/lib
MACOSX_DEPLOYMENT_TARGET: 11.0
steps:
- uses: actions/checkout@v3
- name: Download artifact
uses: actions/download-artifact@master
with:
name: libpgf-macos
- run: |
sudo mv lib/* /usr/local/lib/
sudo mv include/* /usr/local/include/
- name: Install cibuildwheel
run: |
python3 -m pip install git+https://github.com/joerick/cibuildwheel.git@main
- name: Install and test bindings
env:
CIBW_TEST_REQUIRES: pytest
CIBW_TEST_COMMAND: "pytest {project}/src/runtime/python"
CIBW_SKIP: "pp* cp36* cp37* cp38* cp39*"
run: |
python3 -m cibuildwheel src/runtime/python --output-dir wheelhouse
- uses: actions/upload-artifact@master
with:
name: python-macos
path: ./wheelhouse
# macos-javascript:
# name: JavaScript (macOS)
# runs-on: macOS-11
# needs: macos-runtime
#
# steps:
# - uses: actions/checkout@v3
# - name: Download artifact
# uses: actions/download-artifact@master
# with:
# name: libpgf-macos
# - run: |
# sudo mv lib/* /usr/local/lib/
# sudo mv include/* /usr/local/include/
#
# - name: Setup Node.js
# uses: actions/setup-node@v2
# with:
# node-version: '12'
#
# - name: Install dependencies
# working-directory: ./src/runtime/javascript
# run: |
# npm ci
#
# - name: Run testsuite
# working-directory: ./src/runtime/javascript
# run: |
# npm run test
# ----------------------------------------------------------------------------
mingw64-runtime:
name: Runtime (MinGW64)
runs-on: windows-latest
steps:
- uses: actions/checkout@v3
- name: Setup MSYS2
uses: msys2/setup-msys2@v2
with:
msystem: MINGW64
install: >-
base-devel
autoconf
automake
libtool
mingw-w64-x86_64-toolchain
mingw-w64-x86_64-libtool
- name: Build runtime
shell: msys2 {0}
working-directory: ./src/runtime/c
run: |
autoreconf -i
./configure
make
make install
- name: Upload artifact
uses: actions/upload-artifact@master
with:
name: libpgf-windows
path: |
${{runner.temp}}/msys64/mingw64/bin/libpgf*
${{runner.temp}}/msys64/mingw64/bin/libgcc_s_seh-1.dll
${{runner.temp}}/msys64/mingw64/bin/libstdc++-6.dll
${{runner.temp}}/msys64/mingw64/bin/libwinpthread-1.dll
${{runner.temp}}/msys64/mingw64/lib/libpgf*
${{runner.temp}}/msys64/mingw64/include/pgf
windows-python:
name: Python (Windows)
runs-on: windows-latest
steps:
- uses: actions/checkout@v3
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: '3.10'
- name: Install cibuildwheel
run: |
python3 -m pip install git+https://github.com/joerick/cibuildwheel.git@main
- name: Install and test bindings
env:
CIBW_TEST_REQUIRES: pytest
CIBW_TEST_COMMAND: "pytest {project}\\src\\runtime\\python"
CIBW_SKIP: "pp* *-win32"
run: |
python3 -m cibuildwheel src\runtime\python --output-dir wheelhouse
- uses: actions/upload-artifact@master
with:
name: python-windows
path: ./wheelhouse
upload_pypi:
name: Upload to PyPI
needs: [linux-python, macos-python, windows-python]
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/majestic' && github.event_name == 'push'
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v3
with:
python-version: '3.x'
- name: Install twine
run: pip install twine
- uses: actions/download-artifact@master
with:
name: python-linux
path: ./dist
- uses: actions/download-artifact@master
with:
name: python-macos
path: ./dist
- uses: actions/download-artifact@master
with:
name: python-windows
path: ./dist
- name: Publish
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.pypi_majestic_password }}
run: |
(cd ./src/runtime/python && curl -I --fail https://pypi.org/project/$(python setup.py --name)/$(python setup.py --version)/) || twine upload --skip-existing dist/*

9
.gitignore vendored
View File

@@ -5,6 +5,7 @@
*.jar
*.gfo
*.pgf
*.ngf
debian/.debhelper
debian/debhelper-build-stamp
debian/gf
@@ -46,6 +47,8 @@ src/runtime/c/sg/.dirstamp
src/runtime/c/stamp-h1
src/runtime/java/.libs/
src/runtime/python/build/
src/runtime/python/**/__pycache__/
src/runtime/python/**/.pytest_cache/
.cabal-sandbox
cabal.sandbox.config
.stack-work
@@ -53,6 +56,12 @@ DATA_DIR
stack*.yaml.lock
# Generated source files
src/compiler/api/GF/Grammar/Lexer.hs
src/compiler/api/GF/Grammar/Parser.hs
src/compiler/api/PackageInfo_gf.hs
src/compiler/api/Paths_gf.hs
# Output files for test suite
*.out
gf-tests.html

View File

@@ -1,14 +0,0 @@
sudo: required
language: c
services:
- docker
before_install:
- docker pull odanoburu/gf-src:3.9
script:
- |
docker run --mount src="$(pwd)",target=/home/gfer,type=bind odanoburu/gf-src:3.9 /bin/bash -c "cd /home/gfer/src/runtime/c &&
autoreconf -i && ./configure && make && make install ; cd /home/gfer ; cabal install -fserver -fc-runtime --extra-lib-dirs='/usr/local/lib'"

11
CHANGELOG.md Normal file
View File

@@ -0,0 +1,11 @@
### New since 3.11 (WIP)
- Added a changelog!
### 3.11
See <https://www.grammaticalframework.org/download/release-3.11.html>
### 3.10
See <https://www.grammaticalframework.org/download/release-3.10.html>

View File

@@ -6,41 +6,30 @@ VERSION=$(shell sed -ne "s/^version: *\([0-9.]*\).*/\1/p" gf.cabal)
# Check if stack is installed
STACK=$(shell if hash stack 2>/dev/null; then echo "1"; else echo "0"; fi)
# Check if cabal >= 2.4 is installed (with v1- and v2- commands)
CABAL_NEW=$(shell if cabal v1-repl --help >/dev/null 2>&1 ; then echo "1"; else echo "0"; fi)
ifeq ($(STACK),1)
CMD=stack
else
CMD=cabal
ifeq ($(CABAL_NEW),1)
CMD_PFX=v1-
endif
CMD_OPT="--force-reinstalls"
endif
all: build
all: src/runtime/c/libpgf.la
${CMD} install gf
dist/setup-config: gf.cabal Setup.hs WebSetup.hs
ifneq ($(STACK),1)
cabal ${CMD_PFX}configure
endif
src/runtime/c/libpgf.la: src/runtime/c/Makefile
(cd src/runtime/c; make; sudo make install)
build: dist/setup-config
${CMD} ${CMD_PFX}build
src/runtime/c/Makefile: src/runtime/c/Makefile.in src/runtime/c/configure
(cd src/runtime/c; ./configure)
install:
ifeq ($(STACK),1)
stack install
else
cabal ${CMD_PFX}copy
cabal ${CMD_PFX}register
endif
src/runtime/c/Makefile.in src/runtime/c/configure: src/runtime/c/configure.ac src/runtime/c/Makefile.am
(cd src/runtime/c; autoreconf -i)
doc:
${CMD} ${CMD_PFX}haddock
${CMD} haddock
clean:
${CMD} ${CMD_PFX}clean
${CMD} clean
bash bin/clean_html
html::
@@ -65,6 +54,6 @@ bintar:
# Make a source tar.gz distribution using git to make sure that everything is included.
# We put the distribution in dist/ so it is removed on `make clean`
sdist:
test -d dist || mkdir dist
git archive --format=tar.gz --output=dist/gf-${VERSION}.tar.gz HEAD
# sdist:
# test -d dist || mkdir dist
# git archive --format=tar.gz --output=dist/gf-${VERSION}.tar.gz HEAD

View File

@@ -1,7 +1,9 @@
![GF Logo](doc/Logos/gf1.svg)
![GF Logo](https://www.grammaticalframework.org/doc/Logos/gf1.svg)
# Grammatical Framework (GF)
![Build majestic runtime](https://github.com/GrammaticalFramework/gf-core/actions/workflows/build-majestic.yml/badge.svg?branch=majestic)
The Grammatical Framework is a grammar formalism based on type theory.
It consists of:
@@ -30,16 +32,44 @@ GF particularly addresses four aspects of grammars:
## Compilation and installation
The simplest way of installing GF from source is with the command:
1. First, you need to install the C Runtime.
```Bash
cd src/runtime/c
```
cabal install
Then follow the instructions in the [README.md](src/runtime/c/README.md) in that folder.
2. When the C runtime is installed, you should set up the Haskell runtime
```Bash
cd ../haskell
runghc Setup.hs configure
runghc Setup.hs build
sudo runghc Setup.hs install
```
or:
If the above commands fail because of missing dependencies, then you must install those first. Use something along the lines:
```Bash
cabal v1-install random --global
```
stack install
the same applies for all other dependecies needed here or bellow.
If you use macOS, you might run into problems with installation under ``/usr/lib``, and you should **first** specify the variable for the library path:
```Bash
export DYLD_LIBRARY_PATH=/usr/local/lib
```
and then you run following commands:
```Bash
runghc Setup.hs configure --prefix=/usr/local
runghc Setup.hs build
sudo DYLD_LIBRARY_PATH=/usr/local/lib runghc Setup.hs install
```
3. Then you need to setup the compiler:
```Bash
cd ../../compiler/
runghc Setup.hs configure
runghc Setup.hs build
sudo DYLD_LIBRARY_PATH=/usr/local/lib runghc Setup.hs install
```
For more information, including links to precompiled binaries, see the [download page](http://www.grammaticalframework.org/download/index.html).
For more information, including links to precompiled binaries, see the [download page](https://www.grammaticalframework.org/download/index.html).
## About this repository

View File

@@ -47,11 +47,14 @@ but the generated _artifacts_ must be manually attached to the release as _asset
In order to do this you will need to be added the [GF maintainers](https://hackage.haskell.org/package/gf/maintainers/) on Hackage.
1. Run `make sdist`
1. Run `stack sdist --test-tarball` and address any issues.
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:
1. **Manually**: visit <https://hackage.haskell.org/upload> and upload the file generated by the previous command.
2. **via Stack**: `stack upload . --candidate`
3. After testing the candidate, publish it:
1. **Manually**: visit <https://hackage.haskell.org/package/gf-X.Y.Z/candidate/publish>
1. **via Stack**: `stack upload .`
4. 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

18
ServerInstructions.md Normal file
View File

@@ -0,0 +1,18 @@
# GF server installation
1. First make sure your compiler is installed with a flag server:
```bash
cd gf-core/src/compiler/
runghc Setup.hs configure -f servef
runghc Setup.hs build
sudo runghc Setup.hs install
```
1. You can test it now by running:
```bash
gf -server
```
It will also show the root directory (`ROOT_DIR`)

View File

@@ -1,81 +0,0 @@
import Distribution.System(Platform(..),OS(..))
import Distribution.Simple(defaultMainWithHooks,UserHooks(..),simpleUserHooks)
import Distribution.Simple.LocalBuildInfo(LocalBuildInfo(..),absoluteInstallDirs,datadir)
import Distribution.Simple.Setup(BuildFlags(..),Flag(..),InstallFlags(..),CopyDest(..),CopyFlags(..),SDistFlags(..))
import Distribution.PackageDescription(PackageDescription(..),emptyHookedBuildInfo)
import Distribution.Simple.BuildPaths(exeExtension)
import System.FilePath((</>),(<.>))
import WebSetup
-- | Notice about RGL not built anymore
noRGLmsg :: IO ()
noRGLmsg = putStrLn "Notice: the RGL is not built as part of GF anymore. See https://github.com/GrammaticalFramework/gf-rgl"
main :: IO ()
main = defaultMainWithHooks simpleUserHooks
{ preBuild = gfPreBuild
, postBuild = gfPostBuild
, preInst = gfPreInst
, postInst = gfPostInst
, postCopy = gfPostCopy
}
where
gfPreBuild args = gfPre args . buildDistPref
gfPreInst args = gfPre args . installDistPref
gfPre args distFlag = do
return emptyHookedBuildInfo
gfPostBuild args flags pkg lbi = do
-- noRGLmsg
let gf = default_gf lbi
buildWeb gf flags (pkg,lbi)
gfPostInst args flags pkg lbi = do
-- noRGLmsg
saveInstallPath args flags (pkg,lbi)
installWeb (pkg,lbi)
gfPostCopy args flags pkg lbi = do
-- noRGLmsg
saveCopyPath args flags (pkg,lbi)
copyWeb flags (pkg,lbi)
-- `cabal sdist` will not make a proper dist archive, for that see `make sdist`
-- However this function should exit quietly to allow building gf in sandbox
gfSDist pkg lbi hooks flags = do
return ()
saveInstallPath :: [String] -> InstallFlags -> (PackageDescription, LocalBuildInfo) -> IO ()
saveInstallPath args flags bi = do
let
dest = NoCopyDest
dir = datadir (uncurry absoluteInstallDirs bi dest)
writeFile dataDirFile dir
saveCopyPath :: [String] -> CopyFlags -> (PackageDescription, LocalBuildInfo) -> IO ()
saveCopyPath args flags bi = do
let
dest = case copyDest flags of
NoFlag -> NoCopyDest
Flag d -> d
dir = datadir (uncurry absoluteInstallDirs bi dest)
writeFile dataDirFile dir
-- | Name of file where installation's data directory is recording
-- This is a last-resort way in which the seprate RGL build script
-- can determine where to put the compiled RGL files
dataDirFile :: String
dataDirFile = "DATA_DIR"
-- | Get path to locally-built gf
default_gf :: LocalBuildInfo -> FilePath
default_gf lbi = buildDir lbi </> exeName' </> exeNameReal
where
-- shadows Distribution.Simple.BuildPaths.exeExtension, which changed type signature in Cabal 2.4
exeExtension = case hostPlatform lbi of
Platform arch Windows -> "exe"
_ -> ""
exeName' = "gf"
exeNameReal = exeName' <.> exeExtension

View File

@@ -1,146 +0,0 @@
module WebSetup(buildWeb,installWeb,copyWeb,numJobs,execute) where
import System.Directory(createDirectoryIfMissing,copyFile,doesDirectoryExist,doesFileExist)
import System.FilePath((</>),dropExtension)
import System.Process(rawSystem)
import System.Exit(ExitCode(..))
import Distribution.Simple.Setup(BuildFlags(..),Flag(..),CopyFlags(..),CopyDest(..),copyDest)
import Distribution.Simple.LocalBuildInfo(LocalBuildInfo(..),datadir,buildDir,absoluteInstallDirs)
import Distribution.PackageDescription(PackageDescription(..))
{-
To test the GF web services, the minibar and the grammar editor, use
"cabal install" (or "runhaskell Setup.hs install") to install gf as usual.
Then start the server with the command "gf -server" and open
http://localhost:41296/ in your web browser (Firefox, Safari, Opera or
Chrome). The example grammars listed below will be available in the minibar.
-}
{-
Update 2018-07-04
The example grammars have now been removed from the GF repository.
This script will look for them in ../gf-contrib and build them from there if possible.
If not, the user will be given a message and nothing is build or copied.
(Unfortunately cabal install seems to hide all messages from stdout,
so users won't see this message unless they check the log.)
-}
-- | Notice about contrib grammars
noContribMsg :: IO ()
noContribMsg = putStr $ unlines
[ "Example grammars are no longer included in the main GF repository, but have moved to gf-contrib."
, "If you want them to be built, clone the following repository in the same directory as gf-core:"
, "https://github.com/GrammaticalFramework/gf-contrib.git"
]
example_grammars :: [(String, String, [String])] -- [(pgf, subdir, source modules)]
example_grammars =
[("Letter.pgf","letter",letterSrc)
,("Foods.pgf","foods",foodsSrc)
,("Phrasebook.pgf","phrasebook",phrasebookSrc)
]
where
foodsSrc = ["Foods"++lang++".gf"|lang<-foodsLangs]
foodsLangs = words "Afr Amh Bul Cat Cze Dut Eng Epo Fin Fre Ger Gle Heb Hin Ice Ita Jpn Lav Mlt Mon Nep Pes Por Ron Spa Swe Tha Tsn Tur Urd"
phrasebookSrc = ["Phrasebook"++lang++".gf"|lang<-phrasebookLangs]
phrasebookLangs = words "Bul Cat Chi Dan Dut Eng Lav Hin Nor Spa Swe Tha" -- only fastish languages
letterSrc = ["Letter"++lang++".gf"|lang<-letterLangs]
letterLangs = words "Eng Fin Fre Heb Rus Swe"
contrib_dir :: FilePath
contrib_dir = ".."</>"gf-contrib"
buildWeb :: String -> BuildFlags -> (PackageDescription, LocalBuildInfo) -> IO ()
buildWeb gf flags (pkg,lbi) = do
contrib_exists <- doesDirectoryExist contrib_dir
if contrib_exists
then mapM_ build_pgf example_grammars
-- else noContribMsg
else return ()
where
gfo_dir = buildDir lbi </> "examples"
build_pgf :: (String, String, [String]) -> IO Bool
build_pgf (pgf,subdir,src) =
do createDirectoryIfMissing True tmp_dir
putStrLn $ "Building "++pgf
execute gf args
where
tmp_dir = gfo_dir</>subdir
dir = contrib_dir</>subdir
dest = NoCopyDest
gf_lib_path = datadir (absoluteInstallDirs pkg lbi dest) </> "lib"
args = numJobs flags++["-make","-s"] -- ,"-optimize-pgf"
++["--gfo-dir="++tmp_dir,
--"--gf-lib-path="++gf_lib_path,
"--name="++dropExtension pgf,
"--output-dir="++gfo_dir]
++[dir</>file|file<-src]
installWeb :: (PackageDescription, LocalBuildInfo) -> IO ()
installWeb = setupWeb NoCopyDest
copyWeb :: CopyFlags -> (PackageDescription, LocalBuildInfo) -> IO ()
copyWeb flags = setupWeb dest
where
dest = case copyDest flags of
NoFlag -> NoCopyDest
Flag d -> d
setupWeb :: CopyDest -> (PackageDescription, LocalBuildInfo) -> IO ()
setupWeb dest (pkg,lbi) = do
mapM_ (createDirectoryIfMissing True) [grammars_dir,cloud_dir]
contrib_exists <- doesDirectoryExist contrib_dir
if contrib_exists
then mapM_ copy_pgf example_grammars
else return () -- message already displayed from buildWeb
copyGFLogo
where
grammars_dir = www_dir </> "grammars"
cloud_dir = www_dir </> "tmp" -- hmm
logo_dir = www_dir </> "Logos"
www_dir = datadir (absoluteInstallDirs pkg lbi dest) </> "www"
gfo_dir = buildDir lbi </> "examples"
copy_pgf :: (String, String, [String]) -> IO ()
copy_pgf (pgf,subdir,_) =
do let src = gfo_dir </> pgf
let dst = grammars_dir </> pgf
ex <- doesFileExist src
if ex then do putStrLn $ "Installing "++dst
copyFile src dst
else putStrLn $ "Not installing "++dst
gf_logo = "gf0.png"
copyGFLogo =
do createDirectoryIfMissing True logo_dir
copyFile ("doc"</>"Logos"</>gf_logo) (logo_dir</>gf_logo)
-- | Run an arbitrary system command, returning False on failure
execute :: String -> [String] -> IO Bool
execute command args =
do let cmdline = command ++ " " ++ unwords (map showArg args)
e <- rawSystem command args
case e of
ExitSuccess -> return True
ExitFailure i -> do putStrLn $ "Ran: " ++ cmdline
putStrLn $ command++" exited with exit code: " ++ show i
return False
where
showArg arg = if ' ' `elem` arg then "'" ++ arg ++ "'" else arg
-- | This function is used to enable parallel compilation of the RGL and example grammars
numJobs :: BuildFlags -> [String]
numJobs flags =
if null n
then ["-j","+RTS","-A20M","-N","-RTS"]
else ["-j="++n,"+RTS","-A20M","-N"++n,"-RTS"]
where
-- buildNumJobs is only available in Cabal>=1.20
n = case buildNumJobs flags of
Flag mn | mn/=Just 1-> maybe "" show mn
_ -> ""

View File

@@ -17,9 +17,10 @@ instructions inside.
==Visual Studio Code==
[Grammatical Framework Language Server https://marketplace.visualstudio.com/items?itemName=anka-213.gf-vscode] by Andreas Källberg.
This provides syntax highlighting and a client for the Grammatical Framework language server. Follow the installation instructions in the link.
- [Grammatical Framework Language Server https://marketplace.visualstudio.com/items?itemName=anka-213.gf-vscode] by Andreas Källberg.
This provides syntax highlighting and a client for the Grammatical Framework language server. Follow the installation instructions in the link.
- [Grammatical Framework https://marketplace.visualstudio.com/items?itemName=GrammaticalFramework.gf-vscode] is a simpler extension
without any external dependencies which provides only syntax highlighting.
==Eclipse==

View File

@@ -7,7 +7,6 @@ title: "Grammatical Framework: Authors and Acknowledgements"
The current maintainers of GF are
[Krasimir Angelov](http://www.chalmers.se/cse/EN/organization/divisions/computing-science/people/angelov-krasimir),
[Thomas Hallgren](http://www.cse.chalmers.se/~hallgren/),
[Aarne Ranta](http://www.cse.chalmers.se/~aarne/),
[John J. Camilleri](http://johnjcamilleri.com), and
[Inari Listenmaa](https://inariksit.github.io/).
@@ -22,6 +21,7 @@ and
The following people have contributed code to some of the versions:
- [Thomas Hallgren](http://www.cse.chalmers.se/~hallgren/) (University of Gothenburg)
- Grégoire Détrez (University of Gothenburg)
- Ramona Enache (University of Gothenburg)
- [Björn Bringert](http://www.cse.chalmers.se/alumni/bringert) (University of Gothenburg)

View File

@@ -1224,14 +1224,15 @@ modules.
Here are some flags commonly included in grammars.
flag value description module
------------ -------------------- ---------------------------------- ----------
`coding` character encoding encoding used in string literals concrete
`startcat` category default target of parsing abstract
flag value description module
------------ -------------------- ---------------------------------- ----------
`coding` character encoding encoding used in string literals concrete
`startcat` category default target of parsing abstract
`case_sensitive` on/off controlls the case sensitiveness concrete
The possible values of these flags are specified [here](#flagvalues).
Note that the `lexer` and `unlexer` flags are deprecated. If you need
their functionality, you should use supply them to GF shell commands
their functionality, you should supply them to GF shell commands
like so:
put_string -lextext "страви, напої" | parse
@@ -2294,6 +2295,12 @@ for parsing, random generation, and any other grammar operation that
depends on category. Its legal values are the categories defined or
inherited in the abstract syntax.
The flag `case_sensitive` has value `on` by default which means that
the parser will always match the input with the grammar predictions
in a case sensitive manner. This can be overriden by setting the flag
to `off`. The flag also controlls how the linearizer matches the
prefixes in the `pre` construction.
### Compiler pragmas

View File

@@ -0,0 +1,11 @@
# Compilation
The GF language is designed to be easy for the programmers to use but be able to run it efficiently we need to reduce it to a more low-level language. The goal of this chapter is to give an overview of the different steps in the compilation. The program transformation goes throught the following phases:
- renaming - here all identifiers in the grammar are made explicitly qualified. For example, if you had used the identifier PredVP somewhere, the compiler will search for a definition of that identifier in either the current module or in any of the modules imported from the current one. If a definition is found in, say in a module called Sentence, then the unqualified name PredVP will be replaced with the explicit qualification Sentence.PredVP. On the other hand, if the source program is already using an explicit qualification like Sentence.PredVP, then the compiler will check whether PredVP is indeed defined in the module Sentence.
- type checking - here the compiler will check whether all functions and variables are used correctly with respect to their types. For each term that the compiler checks it will also generate a new version of the term after the type checking. The input and output terms may not need to be the same. For example, the compiler may insert explicit type information. It might fill-in implicit arguments, or it may instantiate meta variables.
- partial evaluation - here is where the real compilation starts. The compiler will fully evaluate the term for each linearization to a normal. In the process, all uses of operations will be inlined. This is part of reducing the GF language to a simpler language which does not support operations.
- PMCFG generation - the language that the GF runtime understands is an extension of the PMCFG formalism. Not all features permitted in the GF language are allowed on that level. Most of the uses for that extra features have been eliminated via partial evaluation. If there are any left, then the compilation will abort. The main purpose of the PMCFG generation is to get rid of most of the parameter types in the source grammar. That is possible by generating several specialized linearization rules from a single linearization rule in the source.

View File

@@ -0,0 +1,51 @@
This is an experiment to develop **a majestic new GF runtime**.
The reason is that there are several features that we want to have and they all require a major rewrite of the existing C runtime.
Instead of beating the old code until it starts doing what we want, it is time to start from scratch.
# New Features
The features that we want are:
- We want to support **even bigger grammars that don't fit in the main memory** anymore. Instead, they should reside on the disc and parts will be loaded on demand.
The current design is that all memory allocated for the grammars should be from memory-mapped files. In this way the only limit for the grammar size will
be the size of the virtual memory, i.e. 2^64 bytes. The swap file is completely circumvented, while all of the available RAM can be used as a cache for loading parts
of the grammar.
- We want to be able to **update grammars dynamically**. This is a highly desired feature since recompiling large grammars takes hours.
Instead, dynamic updates should happen instantly.
- We want to be able to **store additional information in the PGF**. For example that could be application specific semantic data.
Another example is to store the source code of the different grammar rules, to allow the compiler to recompile individual rules.
- We want to **allow a single file to contain slightly different versions of the grammar**. This will be a kind of a version control system,
which will allow different users to store their own grammar extensions while still using the same core content.
- We want to **avoid the exponential explosion in the size of PMCFG** for some grammars. This happens because PMCFG as a formalism is too low-level.
By enriching it with light-weight variables, we can make it more powerful and hopefully avoid the exponential explosion.
- We want to finally **ditch the old Haskell runtime** which has long outlived its time.
There are also two bugs in the old C runtime whose fixes will require a lot of changes, so instead of fixing the old runtime we do it here:
- **Integer literals in the C runtime** are implemented as 32-bit integers, while the Haskell runtime used unlimited integers.
Python supports unlimited integers too, so it would be nice to support them in the new runtime as well.
- The old C runtime assumed that **String literals are terminated with the NULL character**. None of the modern languages (Haskell, Python, Java, etc) make
that assumption, so we should drop it too.
# Consequences
The desired features will have the following implementation cosequences.
- The switch from memory-based to disc-based runtime requires one big change. Before it was easy to just keep a pointer from one object to another.
Unfortunately this doesn't work with memory-mapped files, since every time when you map a file into memory it may end up at a different virtual address.
Instead we must use file offsets. In order to make programming simpler, the new runtime will be **implemented in C++ instead of C**. This allows us to overload
the arrow operator (`->`) which will dynamically convert file offsets to in-memory pointers.
- The choice of C++ also allows us to ditch the old `libgu` library and **use STL** instead.
- The content of the memory mapped files is platform-specific. For that reason there will be two grammar representations:
- **Native Grammar Format** (`.ngf`) - which will be instantly loadable by just mapping it to memory, but will be platform-dependent.
- **Portable Grammar Format** (`.pgf`) - which will take longer to load but will be more compact and platform independent.
The runtime will be able to load `.pgf` files and convert them to `.ngf`. Conversely `.pgf` can be exported from the current `.ngf`.

View File

@@ -0,0 +1,217 @@
The concrete syntax in GF is expressed in a special kind of functional language. Unlike in other functional languages, all GF programs are computed at compile time. The result of the computation is another program in a simplified formalized called Parallel Multiple Context-Free Grammar (PMCFG). More on that later. For now we will only discuss how the computations in a GF program work.
At the heart of the GF compiler is the so called partial evaluator. It computes GF terms but it also have the added super power to be able to work with unknown variables. Consider for instance the term ``\s -> s ++ ""``. A normal evaluator cannot do anything with it, since in order to compute the value of the lambda function, you need to know the value of ``s``. In the computer science terminology the term is already in its normal form. A partial evaluator on the other hand, will just remember that ``s`` is a variable with an unknown value and it will try to compute the expression in the body of the function. After that it will construct a new function where the body is precomputed as much as it goes. In the concrete case the result will be ``\s -> s``, since adding an empty string to any other string produces the same string.
Another super power of the partial evaluator is that it can work with meta variables. The syntax for meta variables in GF is ``?0, ?1, ?2, ...``, and they are used as placeholders which mark parts of the program that are not finished yet. The partial evaluator has no problem to work with such incomplete programs. Sometimes the result of the computation depends on a yet unfinished part of the program, then the evaluator just suspends the computation. In other cases, the result is completely independent of the existance of metavariables. In the later, the evaluator will just return the result.
One of the uses of the evaluator is during type checking where we must enforce certain constraints. The constraints may for instance indicate that the only way for them to be satisfied is to assign a fixed value to one or more of the meta variables. The partial evaluator does that as well. Another use case is during compilation to PMCFG. The compiler to PMCFG, in certain cases assigns to a metavariable all possible values that the variable may have and it then produces different results.
In the rest of we will discuss the implementation of the partial evaluator.
# Simple Lambda Terms
We will start with the simplest possible subset of the GF language, also known as simple lambda calculus. It is defined as an algebraic data type in Haskell, as follows:
```Haskell
data Term
= Vr Ident -- i.e. variables: x,y,z ...
| Cn Ident -- i.e. constructors: cons, nil, etc.
| App Term Term -- i.e. function application: @f x@
| Abs Ident Term -- i.e. \x -> t
```
The result from the evaluation of a GF term is either a constructor applied to a list of other values, or an unapplied lambda abstraction:
```Haskell
type Env = [(Ident,Value)]
data Value
= VApp Ident [Value] -- i.e. constructor application
| VClosure Env Term -- i.e. a closure contains an environment and the term for a lambda abstraction
| VGen Int [Value] -- we will also need that special kind of value for the partial evaluator
```
For the lambda abstractions we build a closure which preserves the environment as it was when we encountered the abstraction. That is necessary since its body may contain free variables whose values are defined in the environment.
The evaluation itself is simple:
```Haskell
eval env (Vr x) args = apply (lookup x env) args
eval env (Cn c) args = VApp c args
eval env (App t1 t2) args = eval env t1 (eval env t2 : args)
eval env (Abs x t) [] = VClosure env (Abs x t)
eval env (Abs x t) (arg:args) = eval ((x,v):env) t args
apply (VApp c vs) args = VApp c (vs++args)
apply (VClosure env (Abs x t)) (arg:args) = eval ((x,arg):env) t args
apply (VGen i vs) args = VGen i (vs++args)
```
Here the we use the `apply` function to apply an already evaluated term to a list of arguments.
When we talk about functional languages, we usually discuss the evaluation order and we differentiate between about lazy and strict languages. Simply speaking, a strict language evaluates the arguments of a function before the function is called. In a lazy language, on the other hand, the arguments are passed unevaluated and are computed only if the value is really needed for the execution of the function. The main advantage of lazy languages is that they guarantee the termination of the computation in some cases where strict languages don't. The GF language does not allow recursion and therefore all programs terminate. Looking from only that angle it looks like the evaluation order is irrelevant in GF. Perhaps that is also the reason why this has never been discussed before. The question, however, becomes relevant again if we want to have an optimal semantics for variants. As we will see in the next section, the only way to get that is if we define GF as a lazy language.
After that discussion, there is an interesting question. Does the eval/apply implementation above define a strict or a lazy language? We have the rule:
```Haskell
eval env (App t1 t2) vs = eval env t1 (eval env t2 : vs)
```
where we see that when a term `t1` is applied to a term `t2` then both get evaluated. The answer to the question then depends on the semantics of the implementation language. Since the evaluation is implemented in Haskell, `eval env t2` would not be computed unless if its value is really neeeded. Therefore, our implementation defines a new lazy language. On the other hand, if the same algorithm is directly transcribed in ML then it will define a strict one instead of a lazy one.
So far we only defined the evaluator which does the usual computations, but it still can't simplify terms like ``\s -> s ++ ""`` where the simplification happens under the lambda abstraction. The normal evaluator would simply return the abstraction unchanged. To take the next step, we also need a function which takes a value and produces a new term which is precomputed as much as possible:
```Haskell
value2term i (VApp c vs) =
foldl (\t v -> App t (value2term i v)) (Cn c) vs
value2term i (VGen j vs) =
foldl (\t v -> App t (value2term i v)) (Vr ('v':show j)) vs
value2term i (VClosure env (Abs x t)) =
let v = eval ((x,VGen i []):env) t []
in Abs ('v':show i) (value2term (i+1) v)
```
The interesting rule here is how closures are turned back to terms. We simply evaluate the body of the lambda abstraction with an environment which binds the variable with the special value `VGen i []`. That value stands for the free variable bound by the `i`-th lambda abstraction counted from the outset of the final term inwards. The only thing that we can do with a free variable is to apply it to other values and this is exactly what `apply` does above. After we evaluate the body of the lambda abstraction, the final value is turned back to a term and we reapply a lambda abstraction on top of it. Note that here we also use `i` as a way to generate fresh variables. Whenever, `value2term` encounters a `VGen` it concerts it back to a variable, i.e. `Vr ('v':show j)`.
Given the two functions `eval` and `value2term`, a partial evaluator is defined as:
```Haskell
normalForm t = value2term 0 (eval [] t [])
```
Of course the rules above describe only the core of a functional language. If we really want to be able to simplify terms like ``\s -> s ++ ""``, then we must
add string operations as well. The full implementation of GF for instance knows that an empty string concatenated with any other value results in the same value. This is true even if the other value is actually a variable, i.e. a `VGen` in the internal representation. On the other hand, it knows that pattern matching on a variable is impossible to precompute. In other words, the partial evaluator would leave the term:
```GF
\x -> case x of {
_+"s" -> x+"'"
_ -> x+"'s"
}
```
unchanged since it can't know whether the value of `x` ends with `"s"`.
# Variants
GF supports variants which makes its semantics closer to the language [Curry](https://en.wikipedia.org/wiki/Curry_(programming_language)) than to Haskell. We support terms like `("a"|"b")` which are used to define equivalent linearizations for one and the same semantic term. Perhaps the most prototypical example is for spelling variantions. For instance, if we want to blend British and American English into the same language then we can use `("color"|"colour")` whenever either of the forms is accepted.
The proper implementation for variants complicates the semantics of the language a lot. Consider the term `(\x -> x + x) ("a"|"b")`! Its value depends on whether our language is defined as lazy or strict. In a strict language, we will first evaluate the argument:
```GF
(\x -> x + x) ("a"|"b")
=> ((\x -> x + x) "a") | ((\x -> x + x) "b")
=> ("a"+"a") | ("b"+"b")
=> ("aa"|"bb")
```
and therefore there are only two values `"aa"´ and `"bb"´. On the other hand in a lazy language, we will do the function application first:
```GF
(\x -> x + x) ("a"|"b")
=> ("a"|"b") + ("a"|"b")
=> ("aa"|"ab"|"ba"|"bb")
```
and get four different values. The experience shows that a semantics producing only two values is more useful since it gives us a way to control how variants are expanded. If you want the same variant to appear in two different places, just bind the variant to a variable first! It looks like a strict evaluation order has an advantage here. Unfortunately that is not always the case. Consider another example, in a strict order:
```GF
(\x -> "c") ("a"|"b")
=> ((\x -> "c") "a") | ((\x -> "c") "b")
=> ("c" | "c")
```
Here we get two variants with one and the same value "c". A lazy evaluation order would have avoided the redundancy since `("a"|"b")` would never have been computed.
The best strategy is to actually use lazy evaluation but not to treat the variants as values. Whenever we encounter a variant term, we just split the evaluation in two different branches, one for each variant. At the end of the computation, we get a set of values which does not contain variants. The partial evaluator converts each value back to a term and combines all terms back to a single one by using a top-level variant. The first example would then compute as:
```GF
(\x -> x + x) ("a"|"b")
=> x + x where x = ("a"|"b")
-- Branch 1:
=> x + x where x = "a"
=> "a" + "a" where x = "a"
=> "aa"
-- Branch 2:
=> x + x where x = "b"
=> "b" + "b" where x = "b"
=> "bb"
```
Here the first step proceeds without branching. We just compute the body of the lambda function while remembering that `x` is bound to the unevaluated term `("a"|"b")`. When we encounter the concatenation `x + x`, then we actually need the value of `x`. Since it is bound to a variant, we must split the evaluation into two branches. In each branch `x` is rebound to either of the two variants `"a"` or `"b"`. The partial evaluator would then recombine the results into `"aa"|"bb"`.
If we consider the second example, it will proceed as:
```GF
(\x -> "c") ("a"|"b")
=> "c" where x = ("a"|"b")
=> "c"
```
since we never ever needed the value of `x`.
There are a lot of other even more interesting examples when we take into account that GF also supports record types and parameter types. Consider this:
```GF
(\x -> x.s1+x.s1) {s1="s"; s2="a"|"b"}
=> x.s1+x.s1 where x = {s1="s"; s2="a"|"b"}
=> "s"+"s"
=> "ss"
```
Here when we encounter `x.s1`, we must evaluate `x` and then its field `s1` but not `s2`. Therefore, there is only one variant. On the other hand, here:
```GF
(\x -> x.s2+x.s2) {s1="s"; s2="a"|"b"}
=> x.s2+x.s2 where x = {s1="s"; s2="a"|"b"}
-- Branch 1
x.s2+x.s2 where x = {s1="s"; s2="a"}
"a"+"a"
"aa"
-- Branch 2
x.s2+x.s2 where x = {s1="s"; s2="b"}
"b"+"b"
"bb"
```
we branch only after encountering the variant in the `s2` field.
The implementation for variants requires the introduction of a nondeterministic monad with a support for mutable variables. See this [paper](https://gup.ub.gu.se/file/207634):
Claessen, Koen & Ljunglöf, Peter. (2000). Typed Logical Variables in Haskell. Electronic Notes Theoretical Computer Science. 41. 37. 10.1016/S1571-0661(05)80544-4.
for possible implementations. Our concrete implemention is built on top of the `ST` monad in Haskell and provides the primitives:
```Haskell
newThunk :: Env s -> Term -> EvalM s (Thunk s)
newEvaluatedThunk :: Value s -> EvalM s (Thunk s)
force :: Thunk s -> EvalM s (Value s)
msum :: [EvalM s a] -> EvalM s a
runEvalM :: (forall s . EvalM s a) -> [a]
```
Here, a `Thunk` is either an unevaluated term or an already computed value. Internally, it is implement as an `STRef`. If the thunk is unevaluated, it can be forced to an evaluated state by calling `force`. Once a thunk is evaluated, it remains evaluated forever. `msum`, on the other hand, makes it possible to nondeterministically branch into a list of possible actions. Finally, `runEvalM` takes a monadic action and returns the list of all possible results.
The terms and the values in the extended language are similar with two exceptions. We add the constructor `FV` for encoding variants in the terms, and the constructors for values now take lists of thunks instead of values:
```Haskell
data Term
= Vr Ident -- i.e. variables: x,y,z ...
| Cn Ident -- i.e. constructors: cons, nil, etc.
| App Term Term -- i.e. function application: @f x@
| Abs Ident Term -- i.e. \x -> t
| FV [Term] -- i.e. a list of variants: t1|t2|t3|...
type Env s = [(Ident,Thunk s)]
data Value s
= VApp Ident [Thunk s] -- i.e. constructor application
| VClosure (Env s) Term -- i.e. a closure contains an environment and the term for a lambda abstraction
| VGen Int [Thunk s] -- i.e. an internal representation for free variables
```
The eval/apply rules are similar
```Haskell
eval env (Vr x) args = do tnk <- lookup x env
v <- force tnk
apply v args
eval env (Cn c) args = return (VApp c args)
eval env (App t1 t2) args = do tnk <- newThunk env t2
eval env t1 (tnk : args)
eval env (Abs x t) [] = return (VClosure env (Abs x t))
eval env (Abs x t) (arg:args) = eval ((x,arg):env) t args
eval env (FV ts) args = msum [eval env t args | t <- ts]
apply (VApp f vs) args = return (VApp f (vs++args))
apply (VClosure env (Abs x t)) (arg:args) = eval ((x,arg):env) t args
apply (VGen i vs) args = return (VGen i (vs++args))
```
```Haskell
value2term i (VApp c tnks) =
foldM (\t tnk -> fmap (App t) (force tnk >>= value2term i)) (Cn c) tnks
value2term i (VGen j tnks) =
foldM (\t tnk -> fmap (App t) (force tnk >>= value2term i)) (Vr ('v':show j)) tnks
value2term i (VClosure env (Abs x t)) = do
tnk <- newEvaluatedThunk (VGen i [])
v <- eval ((x,tnk):env) t []
t <- value2term (i+1) v
return (Abs ('v':show i) t)
normalForm gr t =
case runEvalM gr (eval [] t [] >>= value2term 0) of
[t] -> t
ts -> FV ts
```
# Meta Variables

View File

@@ -0,0 +1,20 @@
# The Hacker's Guide to GF
This is the hacker's guide to GF, for the guide to the galaxy, see the full edition [here](https://en.wikipedia.org/wiki/The_Hitchhiker%27s_Guide_to_the_Galaxy).
Here we will limit outselves to the vastly narrower domain of the [GF](https://www.grammaticalframework.org) runtime. This means that we will not meet
any [Vogons](https://en.wikipedia.org/wiki/Vogon), but we will touch upon topics like memory management, databases, transactions, compilers,
functional programming, theorem proving and sometimes even languages. Subjects that no doubt would interest any curious hacker.
So, **Don't Panic!** and keep reading. This is a live document and will develop together with the runtime itself.
**TABLE OF CONTENTS**
1. Compilation
1. [Overview](CompilationOverview.md)
1. [Lambda Calculus](LambdaCalculus.md)
2. [Parallel Multiple Context-Free Grammars](PMCFG.md)
2. Runtime
1. [Desiderata](DESIDERATA.md)
2. [Memory Model](memory_model.md)
3. [Abstract Expressions](abstract_expressions.md)
4. [Transactions](transactions.md)

View File

@@ -0,0 +1,192 @@
# Data Marshalling Strategies
The runtime is designed to be used from a high-level programming language, which means that there are frequent foreign calls between the host language and C. This also implies that all the data must be frequently marshalled between the binary representations of the two languages. This is usually trivial and well supported for primitive types like numbers and strings but for complex data structures we need to design our own strategy.
The most central data structure in GF is of course the abstract syntax expression. The other two secondary but closely related structures are types and literals. These are complex structures and no high-level programming language will let us to manipulate them directly unless if they are in the format that the runtime of the language understands. There are three main strategies to deal with complex data accross a language boundry:
1. Keep the data in the C world and provide only an opaque handle to the host language. This means that all operations over the data must be done in C via foreign calls.
2. Design a native host-language representation. For each foreign call the data is copied from the host language to the C representation and vice versa. Copying is obviously bad, but not too bad if the data is small. The added benefit is that now both languages have first-class access to the data. As a bonus, the garbage collector of the host language now understands the data and can immediately release it if part of it becomes unreachable.
3. Keep the data in the host language. The C code has only an indirect access via opaque handles and calls back to the host language. The program in the host language has first-class access and the garbage collector can work with the data. No copying is needed.
The old C runtime used option 1. Obviously, this means that abstract expressions cannot be manipulated directly, but this is not the only problem. When the application constructs abstract expressions from different pieces, a whole a lot of overhead is added. First, the design was such that data in C must always be allocated from a memory pool. This means that even if we want to make a simple function application, we first must allocate a pool which adds memory overhead. In addition, the host language must allocate an object which wraps arround the C structure. The net effect is that while the plain abstract function application requires the allocation of only two pointers, the actually allocated data may be several times bigger if the application builds the expression piece by piece. The situation is better if the expression is entirely created from the runtime and the application just needs to keep a reference to it.
Another problem is that when the runtime has to create a whole bunch of expressions, for instance as a result from parsing or random and exhaustive generation, then all the expressions are allocated in the same memory pool. The application gets separate handles to each of the produced expressions, but the memory pool is released only after all of the handles become unreachable. Obviously the problem here is that different expressions share the same pool. Unfortunately this is hard to avoid since although the expressions are different, they usually share common subexpression. Identifying the shared parts would be expensive and at the end it might mean that each expression node must be allocated in its own pool.
The path taken in the new runtime is a combination of strategies 2 and 3. The abstract expressions are stored in the heap of the host language and use a native for that language representation.
# Abstract Expressions in Different Languages
In Haskell, abstract expressions are represented with an algebraic data type:
```Haskell
data Expr =
EAbs BindType Var Expr
| EApp Expr Expr
| ELit Literal
| EMeta MetaId
| EFun Fun
| EVar Int
| ETyped Expr Type
| EImplArg Expr
```
while in Python and all other object-oriented languages an expression is represented with objects of different classes:
```Python
class Expr: pass
class ExprAbs(Expr): pass
class ExprApp(Expr): pass
class ExprLit(Expr): pass
class ExprMeta(Expr): pass
class ExprFun(Expr): pass
class ExprVar(Expr): pass
class ExprTyped(Expr): pass
class ExprImplArg(Expr): pass
```
The runtime needs its own representation as well but only when an expression is stored in a .ngf file. This happens for instance with all types in the abstract syntax of the grammar. Since the type system allows dependent types, some type signature might contain expressions too. Another appearance for abstract expressions is in function definitions, i.e. in the def rules.
Expressions in the runtime are represented with C structures which on the other hand may contain tagged references to other structures. The lowest four bits of each reference encode the type of structure that it points to, while the rest contain the file offsets in the memory mapped file. For example, function application is represented as:
```C++
struct PgfExprApp {
static const uint8_t tag = 1;
PgfExpr fun;
PgfExpr arg;
};
```
Here the constant `tag` says that any reference to a PgfExprApp structure must contain the value 1 in its lowest four bits. The fields `fun` and `arg` refer to the function and the argument for that application. The type PgfExpr is defined as:
```C++
typedef uintptr_t object;
typedef object PgfExpr;
```
In order to dereference an expression, we first neeed to pattern match and then obtain a `ref<>` object:
```C++
switch (ref<PgfExpr>::get_tag(e)) {
...
case PgfExprApp::tag: {
auto eapp = ref<PgfExprApp>::untagged(e);
// do something with eapp->fun and eapp->arg
...
break;
}
...
}
```
The representation in the runtime is internal and should never be exposed to the host language. Moreover, these structures live in the memory mapped file and as we discussed in Section "[Memory Model](memory_model.md)" accessing them requires special care. This also means that occasionally the runtime must make a copy from the native representation to the host representation and vice versa. For example, function:
```Haskell
functionType :: PGF -> Fun -> Maybe Type
```
must look up the type of an abstract syntax function in the .ngf file and return its type. The type, however, is in the native representation and it must first be copied in the host representation. The converse also happens. When the compiler wants to add a new abstract function to the grammar, it creates its type in the Haskell heap, which the runtime later copies to the native representation in the .ngf file. This is not much different from any other database. The database file usually uses a different data representation than what the host language has.
In most other runtime operations, copying is not necessary. The only thing that the runtime needs to know is how to create new expressions in the heap of the host and how to pattern match on them. For that it calls back to code implemented differently for each host language. For example in:
```Haskell
readExpr :: String -> Maybe Expr
```
the runtime knows how to read an abstract syntax expression, while for the construction of the actual value it calls back to Haskell. Similarly:
```Haskell
showExpr :: [Var] -> Expr -> String
```
uses code implemented in Haskell to pattern match on the different algebraic constructors, while the text generation itself happens inside the runtime.
# Marshaller and Unmarshaller
The marshaller and the unmarshaller are the two key data structures which bridge together the different representation realms for abstract expressions and types. The structures have two equivalent definitions, one in C++:
```C++
struct PgfMarshaller {
virtual object match_lit(PgfUnmarshaller *u, PgfLiteral lit)=0;
virtual object match_expr(PgfUnmarshaller *u, PgfExpr expr)=0;
virtual object match_type(PgfUnmarshaller *u, PgfType ty)=0;
};
struct PgfUnmarshaller {
virtual PgfExpr eabs(PgfBindType btype, PgfText *name, PgfExpr body)=0;
virtual PgfExpr eapp(PgfExpr fun, PgfExpr arg)=0;
virtual PgfExpr elit(PgfLiteral lit)=0;
virtual PgfExpr emeta(PgfMetaId meta)=0;
virtual PgfExpr efun(PgfText *name)=0;
virtual PgfExpr evar(int index)=0;
virtual PgfExpr etyped(PgfExpr expr, PgfType typ)=0;
virtual PgfExpr eimplarg(PgfExpr expr)=0;
virtual PgfLiteral lint(size_t size, uintmax_t *v)=0;
virtual PgfLiteral lflt(double v)=0;
virtual PgfLiteral lstr(PgfText *v)=0;
virtual PgfType dtyp(int n_hypos, PgfTypeHypo *hypos,
PgfText *cat,
int n_exprs, PgfExpr *exprs)=0;
virtual void free_ref(object x)=0;
};
```
and one in C:
```C
typedef struct PgfMarshaller PgfMarshaller;
typedef struct PgfMarshallerVtbl PgfMarshallerVtbl;
struct PgfMarshallerVtbl {
object (*match_lit)(PgfUnmarshaller *u, PgfLiteral lit);
object (*match_expr)(PgfUnmarshaller *u, PgfExpr expr);
object (*match_type)(PgfUnmarshaller *u, PgfType ty);
};
struct PgfMarshaller {
PgfMarshallerVtbl *vtbl;
};
typedef struct PgfUnmarshaller PgfUnmarshaller;
typedef struct PgfUnmarshallerVtbl PgfUnmarshallerVtbl;
struct PgfUnmarshallerVtbl {
PgfExpr (*eabs)(PgfUnmarshaller *this, PgfBindType btype, PgfText *name, PgfExpr body);
PgfExpr (*eapp)(PgfUnmarshaller *this, PgfExpr fun, PgfExpr arg);
PgfExpr (*elit)(PgfUnmarshaller *this, PgfLiteral lit);
PgfExpr (*emeta)(PgfUnmarshaller *this, PgfMetaId meta);
PgfExpr (*efun)(PgfUnmarshaller *this, PgfText *name);
PgfExpr (*evar)(PgfUnmarshaller *this, int index);
PgfExpr (*etyped)(PgfUnmarshaller *this, PgfExpr expr, PgfType typ);
PgfExpr (*eimplarg)(PgfUnmarshaller *this, PgfExpr expr);
PgfLiteral (*lint)(PgfUnmarshaller *this, size_t size, uintmax_t *v);
PgfLiteral (*lflt)(PgfUnmarshaller *this, double v);
PgfLiteral (*lstr)(PgfUnmarshaller *this, PgfText *v);
PgfType (*dtyp)(PgfUnmarshaller *this,
int n_hypos, PgfTypeHypo *hypos,
PgfText *cat,
int n_exprs, PgfExpr *exprs);
void (*free_ref)(PgfUnmarshaller *this, object x);
};
struct PgfUnmarshaller {
PgfUnmarshallerVtbl *vtbl;
};
```
Which one you will get, depends on whether you import `pgf/pgf.h` from C or C++.
As we can see, most of the arguments for the different methods are of type `PgfExpr`, `PgfType` or `PgfLiteral`. These are all just type synonyms for the type `object`, which on the other hand is nothing else but a number with enough bits to hold an address if necessary. The interpretation of the number depends on the realm in which the object lives. The following table shows the interpretations for four languages as well as the one used internally in the .ngf files:
| | PgfExpr | PgfLiteral | PgfType |
|----------|----------------|-------------------|----------------|
| Haskell | StablePtr Expr | StablePtr Literal | StablePtr Type |
| Python | ExprObject * | PyObject * | TypeObject * |
| Java | jobject | jobject | jobject |
| .NET | GCHandle | GCHandle | GCHandle |
| internal | file offset | file offset | file offset |
The marshaller is the structure that lets the runtime to pattern match on an expression. When one of the match methods is executed, it checks the kind of expr, literal or type and calls the corresponding method from the unmarshaller which it gets as an argument. The method on the other hand gets as arguments the corresponding sub-expressions and attributes.
Generally the role of an unmarshaller is to construct things. For example, the variable `unmarshaller` in `PGF2.FFI` is an object which can construct new expressions in the Haskell heap from the already created children. Function `readExpr`, for instance, passes that one to the runtime to instruct it that the result must be in the Haskell realm.
Constructing objects is not the only use of an unmarshaller. The implementation of `showExpr` passes to `pgf_print_expr` an abstract expression in Haskell and the `marshaller` defined in PGF2.FFI. That marshaller knows how to pattern match on Haskell expressions and calls the right methods from whatever unmarhaller is given to it. What it will get in that particular case is a special unmarshaller which does not produce new representations of abstract expressions, but generates a string.
# Literals
Finally, we should have a few remarks about how values of the literal types `String`, `Int` and `Float` are represented in the runtime.
`String` is represented as the structure:
```C
typedef struct {
size_t size;
char text[];
} PgfText;
```
Here the first field is the size of the string in number of bytes. The second field is the string itself, encoded in UTF-8. Just like in most modern languages, the string may contain the zero character and that is not an indication for end of string. This means that functions like `strlen` and `strcat` should never be used when working with PgfText. Despite that the text is not zero terminated, the runtime always allocates one more last byte for the text content and sets it to zero. That last byte is not included when calculating the field `size`. The purpose is that with that last zero byte the GDB debugger knows how to show the string properly. Most of the time, this doesn't incur any memory overhead either since `malloc` always allocates memory in size divisible by the size of two machine words. The consequence is that usually there are some byte left unused at the end of every string anyway.
`Int` is like the integers in Haskell and Python and can have arbitrarily many digits. In the runtime, the value is represented as an array of `uintmax_t` values. Each of these values contains as many decimal digits as it is possible to fit in `uintmax_t`. For example on a 64-bit machine,
the maximal value that fits is 18446744073709551616. However, the left-most digit here is at most 1, this means that if we want to represend an arbitrary sequence of digits, the maximal length of the sequence must be at most 19. Similarly on a 32-bit machine each value in the array will store 9 decimal digits. Finally the sign of the number is stored as the sign of the first number in the array which is always threated as `intmax_t`.
Just to have an example, the number `-774763251095801167872` is represented as the array `{-77, 4763251095801167872}`. Note that this representation is not at all suitable for implementing arithmetics with integers, but is very simple to use for us since the runtime only needs to to parse and linearize numbers.
`Float` is trivial and is just represented as the type `double` in C/C++. This can also be seen in the type of the method `lflt` in the unmarshaller.

View File

@@ -0,0 +1,136 @@
# The different storage files
The purpose of the `.ngf` files is to be used as on-disk databases that store grammars. Their format is platform-dependent and they should not be copied from
one platform to another. In contrast the `.pgf` files are platform-independent and can be moved around. The runtime can import a `.pgf` file and create an `.ngf` file.
Conversely a `.pgf` file can be exported from an already existing `.ngf` file.
The internal relation between the two files is more interesting. The runtime uses its own memory allocator which always allocates memory from a memory mapped file.
The file may be explicit or an anonymous one. The `.ngf` is simply a memory image saved in a file. This means that loading the file is always immediate.
You just create a new mapping and the kernel will load memory pages on demand.
On the other hand a `.pgf` file is a version of the grammar serialized in a platform-independent format. This means that loading this type of file is always slower.
Fortunately, you can always create an `.ngf` file from it to speed up later reloads.
The runtime has three ways to load a grammar:
#### 1. Loading a `.pgf`
```Haskell
readPGF :: FilePath -> IO PGF
```
This loads the `.pgf` into an anonymous memory-mapped file. In practice, this means that instead of allocating memory from an explicit file, the runtime will still
use the normal swap file.
#### 2. Loading a `.pgf` and booting a new `.ngf`
```Haskell
bootPGF :: FilePath -> FilePath -> IO PGF
```
The grammar is loaded from a `.pgf` (the first argument) and the memory is mapped to an explicit `.ngf` (second argument). The `.ngf` file is created by the function
and a file with the same name should not exist before the call.
#### 3. Loading an existing memory image
```Haskell
readNGF :: FilePath -> IO PGF
```
Once an `.ngf` file exists, it can be mapped back to memory by using this function. This call is always guaranteed to be fast. The same function can also
create new empty `.ngf` files. If the file does not exist, then a new one will be created which contains an empty grammar. The grammar could then be extended
by dynamically adding functions and categories.
# The content of an `.ngf` file
The `.ngf` file is a memory image but this is not the end of the story. The problem is that there is no way to control at which address the memory image would be
mapped. On Posix systems, `mmap` takes as hint the mapping address but the kernel may choose to ignore it. There is also the flag `MAP_FIXED`, which makes the hint
into a constraint, but then the kernel may fail to satisfy the constraint. For example that address may already be used for something else. Furthermore, if the
same file is mapped from several processes (if they all load the same grammar), it would be difficult to find an address which is free in all of them.
Last but not least using `MAP_FIXED` is considered a security risk.
Since the start address of the mapping can change, using traditional memory pointers withing the mapped area is not possible. The only option is to use offsets
relative to the beginning of the area. In other words, if normally we would have written `p->x`, now we have the offset `o` which we must use like this:
```C++
((A*) (current_base+o))->x
```
Writing the explicit pointer arithmetics and typecasts, each time when we dereference a pointer, is not better than Vogon poetry and it
becomes worse when using a chain of arrow operators. The solution is to use the operator overloading in C++.
There is the type `ref<A>` which wraps around a file offset to a data item of type `A`. The operators `->` and `*`
are overloaded for the type and they do the necessary pointer arithmetics and type casts.
This solves the problem with code readability but creates another problem. How do `->` and `*` know the address of the memory mapped area? Obviously,
`current_base` must be a global variable and there must be a way to initialize it. More specifically it must be thread-local to allow different threads to
work without collisions.
A database (a memory-mapped file) in the runtime is represented by the type `DB`. Before any of the data in the database is accessed, the database must
be brought into scope. Bringing into scope means that `current_base` is initialized to point to the mapping area for that database. After that any dereferencing
of a reference will be done relative to the corresponding database. This is how scopes are defined:
```C++
{
DB_scope scope(db, READER_SCOPE);
...
}
```
Here `DB_scope` is a helper type and `db` is a pointer to the database that you want to bring into scope. The constructor for `DB_scope` saves the old value
for `current_base` and then sets it to point to the area of the given database. Conversely, the destructor restores the previous value.
The use of `DB_scope` is reentrant, i.e. you can do this:
```C++
{
DB_scope scope(db1, READER_SCOPE);
...
{
DB_scope scope(db2, READER_SCOPE);
...
}
...
}
```
What you can't do is to have more than one database in scope simultaneously. Fortunately, that is not needed. All API functions start a scope
and the internals of the runtime always work with the current database in scope.
Note the flag `READER_SCOPE`. You can use either `READER_SCOPE` or `WRITER_SCOPE`. In addition to selecting the database, the `DB_scope` also enforces
the single writer/multiple readers policy. The main problem is that a writer may have to enlarge the current file, which consequently may mean
that the kernel should relocate the mapping area to a new address. If there are readers at the same time, they may break since they expect that the mapped
area is at a particular location.
# Developing writers
There is one important complication when developing procedures modifying the database. Every call to `DB::malloc` may potentially have to enlarge the mapped area
which sometimes leads to changing `current_base`. That would not have been a problem if GCC was not sometimes caching variables in registers. Look at the following code:
```C++
p->r = foo();
```
Here `p` is a reference which is used to access another reference `r`. On the other hand, `foo()` is a procedure which directly or indirectly calls `DB::malloc`.
GCC compiles assignments by first computing the address to modify, and then it evaluates the right hand side. This means that while `foo()` is being evaluated the address computed on the left-hand side is saved in a register or somewhere in the stack. But now, if it happens that the allocation in `foo()` has changed
`current_base`, then the saved address is no longer valid.
That first problem is solved by overloading the assignment operator for `ref<A>`:
```C++
ref<A>& operator= (const ref<A>& r) {
offset = r.offset;
return *this;
}
```
On first sight, nothing special happens here and it looks like the overloading is redundant. However, now the assignments are compiled in a very different way.
The overloaded operator is inlined, so there is no real method call and we don't get any overhead. The real difference is that now, whatever is on the left-hand side of the assignment becomes the value of the `this` pointer, and `this` is always the last thing to be evaluated in a method call. This solves the problem.
`foo()` is evaluated first and if it changes `current_base`, the change will be taken into account when computing the left-hand side of the assignment.
Unfortunately, this is not the only problem. A similar thing happens when the arguments of a function are calls to other functions. See this:
```C++
foo(p->r,bar(),q->r)
```
Where now `bar()` is the function that performs allocation. The compiler is free to keep in a register the value of `current_base` that it needs for the evaluation of
`p->r`, while it evaluates `bar()`. But if `current_base` has changed, then the saved value would be invalid while computing `q->r`. There doesn't seem to be
a work around for this. The only solution is to:
**Never call a function that allocates as an argument to another function**
Instead we call allocating functions on a separate line and we save the result in a temporary variable.
# Thread-local variables
A final remark is the compilation of thread-local variables. When a thread-local variable is compiled in a position-dependent code, i.e. in executables, it is
compiled efficiently by using the `fs` register which points to the thread-local segment. Unfortunately, that is not the case by default for shared
libraries like our runtime. In that case, GCC applies the global-dynamic model which means that access to a thread local variable is internally implemented
with a call to the function `__tls_get_addr`. Since `current_base` is used all the time, this adds overhead.
The solution is to define the variable with the attribute `__attribute__((tls_model("initial-exec")))` which says that it should be treated as if it is defined
in an executable. This removes the overhead, but adds the limitation that the runtime should not be loaded with `dlopen`.

View File

@@ -0,0 +1,137 @@
# Transactions
The `.ngf` files that the runtime creates are actual databases which are used to get quick access to the grammars. Like in any database, we also make it possible to dynamically change the data. In our case this means that we can add and remove functions and categories at any time. Moreover, any changes happen in transactions which ensure that changes are not visible until the transaction is commited. The rest of the document describes how the transactions are implemented.
# Databases and Functional Languages
The database model of the runtime is specifically designed to be friendly towards pure functional languages like Haskell. In a usual database, updates happen constantly and therefore executing one and the same query at different times would yield different results. In our grammar databases, queries correspond to operations like parsing, linearization and generation. This means that if we had used the usual database model, all these operations would have to be bound to the IO monad. Consider this example:
```Haskell
main = do
gr <- readNGF "Example.ngf"
functionType gr "f" >>= print
-- modify the grammar gr
functionType gr "f" >>= print
```
Here we ask for the type of a function before and after an arbitrary update in the grammar `gr`. Obviously if we allow that, then `functionType` would have to be in the IO monad, e.g.:
```Haskell
functionType :: PGF -> Fun -> IO Type
```
Although this is a possible way to go, it would mean that the programmer would have to do all grammar related work in the IO. This is not nice and against the spirit of functional programming. Moreover, all previous implementations of the runtime have assumed that most operations are pure. If we go along that path then this will cause a major breaking change.
Fortunately there is an alternative. Read-only operations remain pure functions, but any update should create a new revision of the database rather than modifying the existing one. Compare this example with the previous:
```Haskell
main = do
gr <- readNGF "Example.ngf"
print (functionType gr "f")
gr2 <- modifyPGF gr $ do
-- do all updates here
print (functionType gr2 "f")
```
Here `modifyPGF` allows us to do updates but the updates are performed on a freshly created clone of the grammar `gr`. The original grammar is never ever modified. After the changes the variable `gr2` is a reference to the new revision. While the transaction is in progress we cannot see the currently changing revision, and therefore all read-only operations can remain pure. Only after the transaction is complete, do we get to use `gr2`, which will not allowed to change anymore.
Note also that above `functionType` is used with its usual pure type:
```Haskell
functionType :: PGF -> Fun -> Type
```
This is safe since the API never exposes database revisions which are not complete. Furthermore, the programmer is free to keep several revisions of the same database simultaneously. In this example:
```Haskell
main = do
gr <- readNGF "Example.ngf"
gr2 <- modifyPGF gr $ do
-- do all updates here
print (functionType gr "f", functionType gr2 "f")
```
The last line prints the type of function `"f"` in both the old and the new revision. Both are still available.
The API as described so far would have been complete if all updates were happening in a single thread. In reality we can expect that there might be several threads or processes modifying the database. The database ensures a multiple readers/single writer exclusion but this doesn't mean that another process/thread cannot modify the database while the current one is reading an old revision. In a parallel setting, `modifyPGF` first merges the revision which the process is using with the latest revision in the database. On top of that the specified updates are performed. The final revision after the updates is returned as a result.
**TODO: Merges are still not implemented.**
The process can also ask for the latest revision by calling `checkoutPGF`, see bellow.
# Databases and Imperative Languages
In imperative languages, the state of the program constantly changes and the considerations in the last section do not apply. All read-only operations always work with the latest revision. Bellow is the previous example translated to Python:
```Python
gr = readNGF("Example.ngf")
print(functionType(gr,"f"))
with gr.transaction() as t:
# do all updates here by using t
print(functionType(gr,"f"))
```
Here the first call to `functionType` returns the old type of "f", while the second call retrives the type after the updates. The transaction itself is initiated by the `with` statement. Inside the with statement `gr` will still refer to the old revision since the new one is not complete yet. If the `with` statement is finished without exceptions then `gr` is updated to point to the new one. If an exception occurs then the new revision is discarded, which corresponds to a transaction rollback. Inside the `with` block, the object `t` of type `Transaction` provides methods for modifying the data.
# Branches
Since the database already supports revisions, it is a simple step to support branches as well. A branch is just a revision with a name. When you open a database with `readNGF`, the runtime looks up and returns the revision (branch) with name `master`. There might be other branches as well. You can retrieve a specific branch by calling:
```Haskell
checkoutPGF :: PGF -> String -> IO (Maybe PGF)
```
Here the string is the branch name. New branches can be created by using:
```Haskell
branchPGF :: PGF -> String -> Transaction a -> IO PGF
```
Here we start with an existing revision, apply a transaction and store the result in a new branch with the given name.
# Implementation
In this section we summarize important design decisions related to the internal implementation.
## API
The low-level API for transactions consists of only four functions:
```C
PgfRevision pgf_clone_revision(PgfDB *db, PgfRevision revision,
PgfText *name,
PgfExn *err);
void pgf_free_revision(PgfDB *pgf, PgfRevision revision);
void pgf_commit_revision(PgfDB *db, PgfRevision revision,
PgfExn *err);
PgfRevision pgf_checkout_revision(PgfDB *db, PgfText *name,
PgfExn *err);
```
Here `pgf_clone_revision` makes a copy of an existing revision and — if `name` is not `NULL` — changes its name. The new revision is transient and exists only until it is released with `pgf_free_revision`. Transient revisions can be updated with the API for adding functions and categories. To make a revision persistent, call `pgf_commit_revision`. After the revision is made persistent it will stay in the database even after you call `pgf_free_revision`. Moreover, it will replace the last persistent revision with the same name. The old revision will then become transient and will exist only until all clients call `pgf_free_revision` for it.
Persistent revisions can never be updated. Instead you clone it to create a new transient revision. That one is updated and finally it replaces the existing persistent revision.
This design for transactions may sound unusual but it is just another way to present the copy-on-write strategy. There instead of transaction logs, each change to the data is written in a new place and the result is made available only after all changes are in place. This is for instance what the [LMDB](http://www.lmdb.tech/doc/) (Lightning Memory-Mapped Database) does and it has also served as an inspiration for us.
## Functional Data Structures
From an imperative point of view, it may sound wasteful that a new copy of the grammar is created for each transaction. Functional programmers on the other hand know that with a functional data structure, you can make a copy which shares as much of the data with the original as possible. Each new version copies only those bits that are different from the old one. For example the main data structure that we use to represent the abstract syntax of a grammar is a size-balanced binary tree as described by:
- Stephen Adams, "Efficient sets: a balancing act", Journal of Functional Programming 3(4):553-562, October 1993, http://www.swiss.ai.mit.edu/~adams/BB/.
- J. Nievergelt and E.M. Reingold, "Binary search trees of bounded balance", SIAM journal of computing 2(1), March 1973.
This is also the same algorithm used by Data.Map in Haskell. There are also other possible implementations (B-Trees for instance), and they may be considered if the current one turns our too inefficient.
## Garbage Collection
We use reference counting to keep track of which objects should be kept alive. For instance, `pgf_free_revision` knows that a transient revision should be removed only when its reference count reaches zero. This means that there is no process or thread using it. The function also checks whether the revision is persistent. Persistent revisions are never removed since they can always be retrieved with `checkoutPGF`.
Clients are supposed to correctly use `pgf_free_revision` to indicate that they don't need a revision any more. Unfortunately, this is not always possible to guarantee. For example many languages with garbage collection call `pgf_free_revision` from a finalizer method. In some languages, however, the finalizer is not guaranteed to be executed if the process terminates before the garbage collection is done. Haskell is one of those languages. Even in languages with reference counting like Python, the process may get killed by the operating system and then the finalizer may still not be executed.
The solution is that we count on the database clients to correctly report when a revision is not needed. In addition, to be on the safe side, on a fresh database restart we explictly clean all leftover transient revisions. This means that even if a client is killed or if it does not correctly release its revisions, the worst that can happen is a memory leak until the next restart. Here by fresh restart we mean a situation where a process opens a database which is not used by anyone else. In order to detect that case we maintain a list of processes who currently have access to the file. While a new process is added, we also remove all processes in the list who are not alive anymore. If at the end the list contains only one element, then this is a fresh restart.
## Inter-process Communication
One and the same database may be opened by several processes. In that case, each process creates a mapping of the database into his own address space. The mapping is shared, which means that if a page from the database gets loaded in memory, it is loaded in a single place in the physical memory. The physical memory is then assigned possibly different virtual addresses in each process. All processes can read the data simultaneously, but if we let them to change it at the same time, all kinds of problems may happen. To avoid that, we store a single-writer/multiple-readers lock in the database file, which the processes use for synchronization.
## Atomicity
The transactions serve two goals. First they make it possible to isolate readers from seeing unfinished changes from writers. Second, they ensure atomicity. A database change should be either completely done or not done at all. The use of transient revisions ensures the isolation but the atomicity is only partly taken care of.
Think about what happens when a writer starts updating a transient revision. All the data is allocated in a memory mapped file. From the point of view of the runtime, all changes happen in memory. When all is done, the runtime calls `msync` which tells the kernel to flush all dirty pages to disk. The problem is that the kernel is also free to flush pages at any time. For instance, if there is not enough memory, it may decide to swap out pages earlier and reuse the released physical space to swap in other virtual pages. This would be fine if the transaction eventually succeeds. However, if this doesn't happen then the image in the file is already changed.
We can avoid the situation by calling [mlock](https://man7.org/linux/man-pages/man2/mlock.2.html) and telling the kernel that certain pages should not be swapped out. The question is which pages to lock. We can lock them all, but this is too much. That would mean that as soon as a page is touched it will never leave the physical memory. Instead, it would have been nice to tell the kernel -- feel free to swap out clean pages but, as soon as they get dirty, keep them in memory until further notice. Unfortunately there is no way to do that directly.
The work around is to first use [mprotect](https://man7.org/linux/man-pages/man2/mprotect.2.html) and keep all pages as read-only. Any attempt to change a page will cause segmentation fault which we can capture. If the change happens during a transaction then we can immediate lock the page and add it to the list of modified pages. When a transaction is successful we sync all modified pages. If an attempt to change a page happens outside of a transaction, then this is either a bug in the runtime or the client is trying to change an address which it should not change. In any case this prevents unintended changes in the data.
**TODO: atomicity is not implemented yet**

View File

@@ -53,26 +53,39 @@ You will probably need to update the `PATH` environment variable to include your
For more information, see [Using GF on Windows](https://www.grammaticalframework.org/~inari/gf-windows.html) (latest updated for Windows 10).
<!--## Installing the latest Hackage release (macOS, Linux, and WSL2 on Windows)
## Installing from Hackage
_Instructions applicable for macOS, Linux, and WSL2 on Windows._
[GF is on Hackage](http://hackage.haskell.org/package/gf), so under
normal circumstances the procedure is fairly simple:
1. Install ghcup https://www.haskell.org/ghcup/
2. `ghcup install ghc 8.10.4`
3. `ghcup set ghc 8.10.4`
4. `cabal update`
5. On Linux: install some C libraries from your Linux distribution (see note below)
6. `cabal install gf-3.11`
You can also download the source code release from [GitHub](https://github.com/GrammaticalFramework/gf-core/releases),
and follow the instructions below under **Installing from the latest developer source code**.
```
cabal update
cabal install gf-3.11
```
### Notes
**GHC version**
The GF source code is known to be compilable with GHC versions 7.10 through to 8.10.
**Obtaining Haskell**
There are various ways of obtaining Haskell, including:
- ghcup
1. Install from https://www.haskell.org/ghcup/
2. `ghcup install ghc 8.10.4`
3. `ghcup set ghc 8.10.4`
- Haskell Platform https://www.haskell.org/platform/
- Stack https://haskellstack.org/
**Installation location**
The above steps installs GF for a single user.
The above steps install 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):
@@ -84,32 +97,34 @@ PATH=$HOME/.cabal/bin:$PATH
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.
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**
## Installing from source code
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
**Obtaining**
If you haven't already, clone the repository with:
To obtain the source code for the **release**,
download it from [GitHub](https://github.com/GrammaticalFramework/gf-core/releases).
Alternatively, to obtain the **latest version** of the source code:
1. 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:
2. If you've already cloned the repository previously, update with:
```
git pull
```
Then install with:
**Installing**
You can then install with:
```
cabal install
```

View File

@@ -8,7 +8,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.4.2/css/all.css" integrity="sha384-/rXc/GQVaYpyDdyxK+ecHPVYJSN9bmVFBvjA/9eOB+pb3F2w2N6fc5qB9Ew5yIns" crossorigin="anonymous">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.15.4/css/all.css" crossorigin="anonymous">
<link rel="alternate" href="https://github.com/GrammaticalFramework/gf-core/" title="GF GitHub repository">
</head>
@@ -57,6 +57,8 @@
<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="https://www.mitpressjournals.org/doi/pdf/10.1162/COLI_a_00378">Scaling Up (Computational Linguistics 2020)</a></li>
<li><a href="https://github.com/GrammaticalFramework/gf-wordnet/blob/master/README.md">GF WordNet</a></li>
<li><a href="https://inariksit.github.io/blog/">GF blog</a></li>
</ul>
<a href="lib/doc/synopsis/index.html" class="btn btn-primary ml-3">
@@ -85,10 +87,27 @@
<div class="col-sm-6 col-md-3 mb-4">
<h3>Contribute</h3>
<ul class="mb-2">
<li><a href="http://groups.google.com/group/gf-dev">Mailing List</a></li>
<li>
<a href="https://web.libera.chat/?channels=#gf">
<i class="fas fa-hashtag"></i>
IRC
</a>
/
<a href="https://discord.gg/EvfUsjzmaz">
<i class="fab fa-discord"></i>
Discord
</a>
</li>
<li>
<a href="https://stackoverflow.com/questions/tagged/gf">
<i class="fab fa-stack-overflow"></i>
Stack Overflow
</a>
</li>
<li><a href="https://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="doc/gf-people.html">Authors</a></li>
<li><a href="//school.grammaticalframework.org/2020/">Summer School</a></li>
<li><a href="doc/gf-people.html">Authors</a></li>
</ul>
<a href="https://github.com/GrammaticalFramework/" class="btn btn-primary ml-3">
<i class="fab fa-github mr-1"></i>
@@ -154,7 +173,7 @@ least one, it may help you to get a first idea of what GF is.
<div class="row">
<div class="col-md-6">
<h2>Applications & Availability</h2>
<h2>Applications & availability</h2>
<p>
GF can be used for building
<a href="//cloud.grammaticalframework.org/translator/">translation systems</a>,
@@ -219,19 +238,28 @@ least one, it may help you to get a first idea of what GF is.
or <a href="https://www.grammaticalframework.org/irc/?C=M;O=D">browse the channel logs</a>.
</p>
<p>
If you have a larger question which the community may benefit from, we recommend you ask it on the <a href="http://groups.google.com/group/gf-dev">mailing list</a>.
There is also a <a href="https://discord.gg/EvfUsjzmaz">GF server on Discord</a>.
</p>
<p>
For bug reports and feature requests, please create an issue in the
<a href="https://github.com/GrammaticalFramework/gf-core/issues">GF Core</a> or
<a href="https://github.com/GrammaticalFramework/gf-rgl/issues">RGL</a> repository.
For programming questions, consider asking them on <a href="https://stackoverflow.com/questions/tagged/gf">Stack Overflow with the <code>gf</code> tag</a>.
If you have a more general question to the community, we recommend you ask it on the <a href="http://groups.google.com/group/gf-dev">mailing list</a>.
</p>
</div>
<div class="col-md-6">
<h2>News</h2>
<dt class="col-sm-3 text-center text-nowrap">2021-07-25</dt>
<dd class="col-sm-9">
<strong>GF 3.11 released.</strong>
<a href="download/release-3.11.html">Release notes</a>
</dd>
<dl class="row">
<dt class="col-sm-3 text-center text-nowrap">2021-07-25</dt>
<dd class="col-sm-9">
<strong>GF 3.11 released.</strong>
<a href="download/release-3.11.html">Release notes</a>
</dd>
<dt class="col-sm-3 text-center text-nowrap">2021-05-05</dt>
<dd class="col-sm-9">
<a href="https://cloud.grammaticalframework.org/wordnet/">GF WordNet</a> now supports languages for which there are no other WordNets. New additions: Afrikaans, German, Korean, Maltese, Polish, Somali, Swahili.
@@ -244,34 +272,6 @@ least one, it may help you to get a first idea of what GF is.
<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>
<dd class="col-sm-9">
<a href="//school.grammaticalframework.org/2018/">Sixth GF Summer School</a> in Stellenbosch (South Africa), 314 December 2018
</dd>
<dt class="col-sm-3 text-center text-nowrap">2018-12-02</dt>
<dd class="col-sm-9">
<strong>GF 3.10 released.</strong>
<a href="download/release-3.10.html">Release notes</a>
</dd>
<dt class="col-sm-3 text-center text-nowrap">2018-07-25</dt>
<dd class="col-sm-9">
The GF repository has been split in two:
<a href="https://github.com/GrammaticalFramework/gf-core">gf-core</a> and
<a href="https://github.com/GrammaticalFramework/gf-rgl">gf-rgl</a>.
The original <a href="https://github.com/GrammaticalFramework/GF">GF</a> repository is now archived.
</dd>
<dt class="col-sm-3 text-center text-nowrap">2017-08-11</dt>
<dd class="col-sm-9">
<strong>GF 3.9 released.</strong>
<a href="download/release-3.9.html">Release notes</a>
</dd>
<dt class="col-sm-3 text-center text-nowrap">2017-06-29</dt>
<dd class="col-sm-9">
GF is moving to <a href="https://github.com/GrammaticalFramework/GF/">GitHub</a>.</dd>
<dt class="col-sm-3 text-center text-nowrap">2017-03-13</dt>
<dd class="col-sm-9">
<a href="//school.grammaticalframework.org/2017/">GF Summer School</a> in Riga (Latvia), 14-25 August 2017
</dd>
</dl>
<h2>Projects</h2>
@@ -341,7 +341,7 @@ least one, it may help you to get a first idea of what GF is.
Libraries are at the heart of modern software engineering. In natural language
applications, libraries are a way to cope with thousands of details involved in
syntax, lexicon, and inflection. The
<a href="lib/doc/synopsis/index.html">GF resource grammar library</a> has
<a href="lib/doc/synopsis/index.html">GF resource grammar library</a> (RGL) has
support for an increasing number of languages, currently including
Afrikaans,
Amharic (partial),

View File

@@ -1,42 +0,0 @@
-- | GF, the Grammatical Framework, as a library
module GF(
-- * Command line interface
module GF.Main,
module GF.Interactive,
module GF.Compiler,
-- * Compiling GF grammars
module GF.Compile,
module GF.CompileInParallel,
-- module PF.Compile.Export, -- haddock does the wrong thing with this
exportPGF,
module GF.CompileOne,
-- * Abstract syntax, parsing, pretty printing and serialisation
module GF.Compile.GetGrammar,
module GF.Grammar.Grammar,
module GF.Grammar.Macros,
module GF.Grammar.Printer,
module GF.Infra.Ident,
-- ** Binary serialisation
module GF.Grammar.Binary,
-- * Canonical GF
module GF.Compile.GrammarToCanonical
) where
import GF.Main
import GF.Compiler
import GF.Interactive
import GF.Compile
import GF.CompileInParallel
import GF.CompileOne
import GF.Compile.Export(exportPGF)
import GF.Compile.GetGrammar
import GF.Grammar.Grammar
import GF.Grammar.Macros
import GF.Grammar.Printer
import GF.Infra.Ident
import GF.Grammar.Binary
import GF.Compile.GrammarToCanonical

View File

@@ -1,64 +0,0 @@
module GF.Command.Importing (importGrammar, importSource) where
import PGF2
import PGF2.Internal(unionPGF)
import GF.Compile
import GF.Compile.Multi (readMulti)
import GF.Compile.GetGrammar (getBNFCRules, getEBNFRules)
import GF.Grammar (SourceGrammar) -- for cc command
import GF.Grammar.BNFC
import GF.Grammar.EBNF
import GF.Grammar.CFG
import GF.Compile.CFGtoPGF
import GF.Infra.UseIO(die,tryIOE)
import GF.Infra.Option
import GF.Data.ErrM
import System.FilePath
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
importGrammar :: Maybe PGF -> Options -> [FilePath] -> IO (Maybe PGF)
importGrammar pgf0 _ [] = return pgf0
importGrammar pgf0 opts files =
case takeExtensions (last files) of
".cf" -> fmap Just $ importCF opts files getBNFCRules bnfc2cf
".ebnf" -> fmap Just $ importCF opts files getEBNFRules ebnf2cf
".gfm" -> do
ascss <- mapM readMulti files
let cs = concatMap snd ascss
importGrammar pgf0 opts cs
s | elem s [".gf",".gfo"] -> do
res <- tryIOE $ compileToPGF opts files
case res of
Ok pgf2 -> ioUnionPGF pgf0 pgf2
Bad msg -> do putStrLn ('\n':'\n':msg)
return pgf0
".pgf" -> do
mapM readPGF files >>= foldM ioUnionPGF pgf0
ext -> die $ "Unknown filename extension: " ++ show ext
ioUnionPGF :: Maybe PGF -> PGF -> IO (Maybe PGF)
ioUnionPGF Nothing two = return (Just two)
ioUnionPGF (Just one) two =
case unionPGF one two of
Nothing -> putStrLn "Abstract changed, previous concretes discarded." >> return (Just two)
Just pgf -> return (Just pgf)
importSource :: Options -> [FilePath] -> IO SourceGrammar
importSource opts files = fmap (snd.snd) (batchCompile opts files)
-- for different cf formats
importCF opts files get convert = impCF
where
impCF = do
rules <- fmap (convert . concat) $ mapM (get opts) files
startCat <- case rules of
(Rule cat _ _ : _) -> return cat
_ -> fail "empty CFG"
probs <- maybe (return Map.empty) readProbabilitiesFromFile (flag optProbsFile opts)
let pgf = cf2pgf opts (last files) (mkCFG startCat Set.empty rules) probs
return pgf

View File

@@ -1,72 +0,0 @@
module GF.Command.Parse(readCommandLine, pCommand) where
import PGF2(pExpr,pIdent)
import GF.Grammar.Parser(runPartial,pTerm)
import GF.Command.Abstract
import Data.Char(isDigit,isSpace)
import Control.Monad(liftM2)
import Text.ParserCombinators.ReadP
readCommandLine :: String -> Maybe CommandLine
readCommandLine s =
case [x | (x,cs) <- readP_to_S pCommandLine s, all isSpace cs] of
[x] -> Just x
_ -> Nothing
pCommandLine =
(skipSpaces >> char '-' >> char '-' >> pTheRest >> return []) -- comment
<++
(sepBy (skipSpaces >> pPipe) (skipSpaces >> char ';'))
pPipe = sepBy1 (skipSpaces >> pCommand) (skipSpaces >> char '|')
pCommand = (do
cmd <- readS_to_P pIdent <++ (char '%' >> fmap ('%':) (readS_to_P pIdent))
skipSpaces
opts <- sepBy pOption skipSpaces
arg <- if getCommandOp cmd == "cc" then pArgTerm else pArgument
return (Command cmd opts arg)
)
<++ (do
char '?'
skipSpaces
c <- pSystemCommand
return (Command "sp" [OFlag "command" (VStr c)] ANoArg)
)
pOption = do
char '-'
flg <- readS_to_P pIdent
option (OOpt flg) (fmap (OFlag flg) (char '=' >> pValue))
pValue = do
fmap VInt (readS_to_P reads)
<++
fmap VStr (readS_to_P reads)
<++
fmap VId pFilename
pFilename = liftM2 (:) (satisfy isFileFirst) (munch (not . isSpace)) where
isFileFirst c = not (isSpace c) && not (isDigit c)
pArgument =
option ANoArg
(fmap AExpr (readS_to_P pExpr)
<++
(skipSpaces >> char '%' >> fmap AMacro (readS_to_P pIdent)))
pArgTerm = ATerm `fmap` readS_to_P sTerm
where
sTerm s = case runPartial pTerm s of
Right (s,t) -> [(t,s)]
_ -> []
pSystemCommand =
(char '"' >> (manyTill (pEsc <++ get) (char '"')))
<++
pTheRest
where
pEsc = char '\\' >> get
pTheRest = munch (const True)

View File

@@ -1,590 +0,0 @@
-- | Functions for computing the values of terms in the concrete syntax, in
-- | preparation for PMCFG generation.
module GF.Compile.Compute.Concrete
(GlobalEnv, GLocation, resourceValues, geLoc, geGrammar,
normalForm,
Value(..), Bind(..), Env, value2term, eval, vapply
) where
import Prelude hiding ((<>)) -- GHC 8.4.1 clash with Text.PrettyPrint
import GF.Grammar hiding (Env, VGen, VApp, VRecType)
import GF.Grammar.Lookup(lookupResDefLoc,allParamValues)
import GF.Grammar.Predef(cPredef,cErrorType,cTok,cStr,cTrace,cPBool)
import GF.Grammar.PatternMatch(matchPattern,measurePatt)
import GF.Grammar.Lockfield(isLockLabel,lockRecType) --unlockRecord,lockLabel
import GF.Compile.Compute.Value hiding (Error)
import GF.Compile.Compute.Predef(predef,predefName,delta)
import GF.Data.Str(Str,glueStr,str2strings,str,sstr,plusStr,strTok)
import GF.Data.Operations(Err,err,errIn,maybeErr,mapPairsM)
import GF.Data.Utilities(mapFst,mapSnd)
import GF.Infra.Option
import Control.Monad(ap,liftM,liftM2) -- ,unless,mplus
import Data.List (findIndex,intersect,nub,elemIndex,(\\)) --,isInfixOf
--import Data.Char (isUpper,toUpper,toLower)
import GF.Text.Pretty
import qualified Data.Map as Map
import Debug.Trace(trace)
-- * Main entry points
normalForm :: GlobalEnv -> L Ident -> Term -> Term
normalForm (GE gr rv opts _) loc = err (bugloc loc) id . nfx (GE gr rv opts loc)
nfx :: GlobalEnv -> Term -> Err Term
nfx env@(GE _ _ _ loc) t = do
v <- eval env [] t
return (value2term loc [] v)
-- Old value2term error message:
-- Left i -> fail ("variable #"++show i++" is out of scope")
eval :: GlobalEnv -> Env -> Term -> Err Value
eval (GE gr rvs opts loc) env t = ($ (map snd env)) # value cenv t
where
cenv = CE gr rvs opts loc (map fst env)
--apply env = apply' env
--------------------------------------------------------------------------------
-- * Environments
type ResourceValues = Map.Map ModuleName (Map.Map Ident (Err Value))
data GlobalEnv = GE Grammar ResourceValues Options GLocation
data CompleteEnv = CE {srcgr::Grammar,rvs::ResourceValues,
opts::Options,
gloc::GLocation,local::LocalScope}
type GLocation = L Ident
type LocalScope = [Ident]
type Stack = [Value]
type OpenValue = Stack->Value
geLoc (GE _ _ _ loc) = loc
geGrammar (GE gr _ _ _) = gr
ext b env = env{local=b:local env}
extend bs env = env{local=bs++local env}
global env = GE (srcgr env) (rvs env) (opts env) (gloc env)
var :: CompleteEnv -> Ident -> Err OpenValue
var env x = maybe unbound pick' (elemIndex x (local env))
where
unbound = fail ("Unknown variable: "++showIdent x)
pick' i = return $ \ vs -> maybe (err i vs) ok (pick i vs)
err i vs = bug $ "Stack problem: "++showIdent x++": "
++unwords (map showIdent (local env))
++" => "++show (i,length vs)
ok v = --trace ("var "++show x++" = "++show v) $
v
pick :: Int -> Stack -> Maybe Value
pick 0 (v:_) = Just v
pick i (_:vs) = pick (i-1) vs
pick i vs = Nothing -- bug $ "pick "++show (i,vs)
resource env (m,c) =
-- err bug id $
if isPredefCat c
then value0 env =<< lockRecType c defLinType -- hmm
else maybe e id $ Map.lookup c =<< Map.lookup m (rvs env)
where e = fail $ "Not found: "++render m++"."++showIdent c
-- | Convert operators once, not every time they are looked up
resourceValues :: Options -> SourceGrammar -> GlobalEnv
resourceValues opts gr = env
where
env = GE gr rvs opts (L NoLoc identW)
rvs = Map.mapWithKey moduleResources (moduleMap gr)
moduleResources m = Map.mapWithKey (moduleResource m) . jments
moduleResource m c _info = do L l t <- lookupResDefLoc gr (m,c)
let loc = L l c
qloc = L l (Q (m,c))
eval (GE gr rvs opts loc) [] (traceRes qloc t)
traceRes = if flag optTrace opts
then traceResource
else const id
-- * Tracing
-- | Insert a call to the trace function under the top-level lambdas
traceResource (L l q) t =
case termFormCnc t of
(abs,body) -> mkAbs abs (mkApp traceQ [args,body])
where
args = R $ tuple2record (K lstr:[Vr x|(bt,x)<-abs,bt==Explicit])
lstr = render (l<>":"<>ppTerm Qualified 0 q)
traceQ = Q (cPredef,cTrace)
-- * Computing values
-- | Computing the value of a top-level term
value0 :: CompleteEnv -> Term -> Err Value
value0 env = eval (global env) []
-- | Computing the value of a term
value :: CompleteEnv -> Term -> Err OpenValue
value env t0 =
-- Each terms is traversed only once by this function, using only statically
-- available information. Notably, the values of lambda bound variables
-- will be unknown during the term traversal phase.
-- The result is an OpenValue, which is a function that may be applied many
-- times to different dynamic values, but without the term traversal overhead
-- and without recomputing other statically known information.
-- For this to work, there should be no recursive calls under lambdas here.
-- Whenever we need to construct the OpenValue function with an explicit
-- lambda, we have to lift the recursive calls outside the lambda.
-- (See e.g. the rules for Let, Prod and Abs)
{-
trace (render $ text "value"<+>sep [ppL (gloc env)<>text ":",
brackets (fsep (map ppIdent (local env))),
ppTerm Unqualified 10 t0]) $
--}
errIn (render t0) $
case t0 of
Vr x -> var env x
Q x@(m,f)
| m == cPredef -> if f==cErrorType -- to be removed
then let p = identS "P"
in const # value0 env (mkProd [(Implicit,p,typeType)] (Vr p) [])
else if f==cPBool
then const # resource env x
else const . flip VApp [] # predef f
| otherwise -> const # resource env x --valueResDef (fst env) x
QC x -> return $ const (VCApp x [])
App e1 e2 -> apply' env e1 . (:[]) =<< value env e2
Let (x,(oty,t)) body -> do vb <- value (ext x env) body
vt <- value env t
return $ \ vs -> vb (vt vs:vs)
Meta i -> return $ \ vs -> VMeta i (zip (local env) vs) []
Prod bt x t1 t2 ->
do vt1 <- value env t1
vt2 <- value (ext x env) t2
return $ \ vs -> VProd bt (vt1 vs) x $ Bind $ \ vx -> vt2 (vx:vs)
Abs bt x t -> do vt <- value (ext x env) t
return $ VAbs bt x . Bind . \ vs vx -> vt (vx:vs)
EInt n -> return $ const (VInt n)
EFloat f -> return $ const (VFloat f)
K s -> return $ const (VString s)
Empty -> return $ const (VString "")
Sort s | s == cTok -> return $ const (VSort cStr) -- to be removed
| otherwise -> return $ const (VSort s)
ImplArg t -> (VImplArg.) # value env t
Table p res -> liftM2 VTblType # value env p <# value env res
RecType rs -> do lovs <- mapPairsM (value env) rs
return $ \vs->VRecType $ mapSnd ($vs) lovs
t@(ExtR t1 t2) -> ((extR t.)# both id) # both (value env) (t1,t2)
FV ts -> ((vfv .) # sequence) # mapM (value env) ts
R as -> do lovs <- mapPairsM (value env.snd) as
return $ \ vs->VRec $ mapSnd ($vs) lovs
T i cs -> valueTable env i cs
V ty ts -> do pvs <- paramValues env ty
((VV ty pvs .) . sequence) # mapM (value env) ts
C t1 t2 -> ((ok2p vconcat.) # both id) # both (value env) (t1,t2)
S t1 t2 -> ((select env.) # both id) # both (value env) (t1,t2)
P t l -> --maybe (bug $ "project "++show l++" from "++show v) id $
do ov <- value env t
return $ \ vs -> let v = ov vs
in maybe (VP v l) id (proj l v)
Alts t tts -> (\v vts -> VAlts # v <# mapM (both id) vts) # value env t <# mapM (both (value env)) tts
Strs ts -> ((VStrs.) # sequence) # mapM (value env) ts
Glue t1 t2 -> ((ok2p (glue env).) # both id) # both (value env) (t1,t2)
ELin c r -> (unlockVRec (gloc env) c.) # value env r
EPatt p -> return $ const (VPatt p) -- hmm
EPattType ty -> do vt <- value env ty
return (VPattType . vt)
Typed t ty -> value env t
t -> fail.render $ "value"<+>ppTerm Unqualified 10 t $$ show t
vconcat vv@(v1,v2) =
case vv of
(VString "",_) -> v2
(_,VString "") -> v1
(VApp NonExist _,_) -> v1
(_,VApp NonExist _) -> v2
_ -> VC v1 v2
proj l v | isLockLabel l = return (VRec [])
---- a workaround 18/2/2005: take this away and find the reason
---- why earlier compilation destroys the lock field
proj l v =
case v of
VFV vs -> liftM vfv (mapM (proj l) vs)
VRec rs -> lookup l rs
-- VExtR v1 v2 -> proj l v2 `mplus` proj l v1 -- hmm
VS (VV pty pvs rs) v2 -> flip VS v2 . VV pty pvs # mapM (proj l) rs
_ -> return (ok1 VP v l)
ok1 f v1@(VError {}) _ = v1
ok1 f v1 v2 = f v1 v2
ok2 f v1@(VError {}) _ = v1
ok2 f _ v2@(VError {}) = v2
ok2 f v1 v2 = f v1 v2
ok2p f (v1@VError {},_) = v1
ok2p f (_,v2@VError {}) = v2
ok2p f vv = f vv
unlockVRec loc c0 v0 = v0
{-
unlockVRec loc c0 v0 = unlockVRec' c0 v0
where
unlockVRec' ::Ident -> Value -> Value
unlockVRec' c v =
case v of
-- VClosure env t -> err bug (VClosure env) (unlockRecord c t)
VAbs bt x (Bind f) -> VAbs bt x (Bind $ \ v -> unlockVRec' c (f v))
VRec rs -> plusVRec rs lock
-- _ -> VExtR v (VRec lock) -- hmm
_ -> {-trace (render $ ppL loc $ "unlock non-record "++show v0)-} v -- hmm
-- _ -> bugloc loc $ "unlock non-record "++show v0
where
lock = [(lockLabel c,VRec [])]
-}
-- suspicious, but backwards compatible
plusVRec rs1 rs2 = VRec ([(l,v)|(l,v)<-rs1,l `notElem` ls2] ++ rs2)
where ls2 = map fst rs2
extR t vv =
case vv of
(VFV vs,v2) -> vfv [extR t (v1,v2)|v1<-vs]
(v1,VFV vs) -> vfv [extR t (v1,v2)|v2<-vs]
(VRecType rs1, VRecType rs2) ->
case intersect (map fst rs1) (map fst rs2) of
[] -> VRecType (rs1 ++ rs2)
ls -> error $ "clash"<+>show ls
(VRec rs1, VRec rs2) -> plusVRec rs1 rs2
(v1 , VRec [(l,_)]) | isLockLabel l -> v1 -- hmm
(VS (VV t pvs vs) s,v2) -> VS (VV t pvs [extR t (v1,v2)|v1<-vs]) s
-- (v1,v2) -> ok2 VExtR v1 v2 -- hmm
(v1,v2) -> error $ "not records" $$ show v1 $$ show v2
where
error explain = ppbug $ "The term" <+> t
<+> "is not reducible" $$ explain
glue env (v1,v2) = glu v1 v2
where
glu v1 v2 =
case (v1,v2) of
(VFV vs,v2) -> vfv [glu v1 v2|v1<-vs]
(v1,VFV vs) -> vfv [glu v1 v2|v2<-vs]
(VString s1,VString s2) -> VString (s1++s2)
(v1,VAlts d vs) -> VAlts (glx d) [(glx v,c) | (v,c) <- vs]
where glx v2 = glu v1 v2
(v1@(VAlts {}),v2) ->
--err (const (ok2 VGlue v1 v2)) id $
err bug id $
do y' <- strsFromValue v2
x' <- strsFromValue v1
return $ vfv [foldr1 VC (map VString (str2strings (glueStr v u))) | v <- x', u <- y']
(VC va vb,v2) -> VC va (glu vb v2)
(v1,VC va vb) -> VC (glu v1 va) vb
(VS (VV ty pvs vs) vb,v2) -> VS (VV ty pvs [glu v v2|v<-vs]) vb
(v1,VS (VV ty pvs vs) vb) -> VS (VV ty pvs [glu v1 v|v<-vs]) vb
(v1@(VApp NonExist _),_) -> v1
(_,v2@(VApp NonExist _)) -> v2
-- (v1,v2) -> ok2 VGlue v1 v2
(v1,v2) -> if flag optPlusAsBind (opts env)
then VC v1 (VC (VApp BIND []) v2)
else let loc = gloc env
vt v = value2term loc (local env) v
-- Old value2term error message:
-- Left i -> Error ('#':show i)
originalMsg = render $ ppL loc (hang "unsupported token gluing" 4
(Glue (vt v1) (vt v2)))
term = render $ pp $ Glue (vt v1) (vt v2)
in error $ unlines
[originalMsg
,""
,"There was a problem in the expression `"++term++"`, either:"
,"1) You are trying to use + on runtime arguments, possibly via an oper."
,"2) One of the arguments in `"++term++"` is a bound variable from pattern matching a string, but the cases are non-exhaustive."
,"For more help see https://github.com/GrammaticalFramework/gf-core/tree/master/doc/errors/gluing.md"
]
-- | to get a string from a value that represents a sequence of terminals
strsFromValue :: Value -> Err [Str]
strsFromValue t = case t of
VString s -> return [str s]
VC s t -> do
s' <- strsFromValue s
t' <- strsFromValue t
return [plusStr x y | x <- s', y <- t']
{-
VGlue s t -> do
s' <- strsFromValue s
t' <- strsFromValue t
return [glueStr x y | x <- s', y <- t']
-}
VAlts d vs -> do
d0 <- strsFromValue d
v0 <- mapM (strsFromValue . fst) vs
c0 <- mapM (strsFromValue . snd) vs
--let vs' = zip v0 c0
return [strTok (str2strings def) vars |
def <- d0,
vars <- [[(str2strings v, map sstr c) | (v,c) <- zip vv c0] |
vv <- sequence v0]
]
VFV ts -> concat # mapM strsFromValue ts
VStrs ts -> concat # mapM strsFromValue ts
_ -> fail ("cannot get Str from value " ++ show t)
vfv vs = case nub vs of
[v] -> v
vs -> VFV vs
select env vv =
case vv of
(v1,VFV vs) -> vfv [select env (v1,v2)|v2<-vs]
(VFV vs,v2) -> vfv [select env (v1,v2)|v1<-vs]
(v1@(VV pty vs rs),v2) ->
err (const (VS v1 v2)) id $
do --ats <- allParamValues (srcgr env) pty
--let vs = map (value0 env) ats
i <- maybeErr "no match" $ findIndex (==v2) vs
return (ix (gloc env) "select" rs i)
(VT _ _ [(PW,Bind b)],_) -> {-trace "eliminate wild card table" $-} b []
(v1@(VT _ _ cs),v2) ->
err (\_->ok2 VS v1 v2) (err bug id . valueMatch env) $
match (gloc env) cs v2
(VS (VV pty pvs rs) v12,v2) -> VS (VV pty pvs [select env (v11,v2)|v11<-rs]) v12
(v1,v2) -> ok2 VS v1 v2
match loc cs v =
err bad return (matchPattern cs (value2term loc [] v))
-- Old value2term error message:
-- Left i -> bad ("variable #"++show i++" is out of scope")
where
bad = fail . ("In pattern matching: "++)
valueMatch :: CompleteEnv -> (Bind Env,Substitution) -> Err Value
valueMatch env (Bind f,env') = f # mapPairsM (value0 env) env'
valueTable :: CompleteEnv -> TInfo -> [Case] -> Err OpenValue
valueTable env i cs =
case i of
TComp ty -> do pvs <- paramValues env ty
((VV ty pvs .) # sequence) # mapM (value env.snd) cs
_ -> do ty <- getTableType i
cs' <- mapM valueCase cs
err (dynamic cs' ty) return (convert cs' ty)
where
dynamic cs' ty _ = cases cs' # value env ty
cases cs' vty vs = err keep ($vs) (convertv cs' (vty vs))
where
keep msg = --trace (msg++"\n"++render (ppTerm Unqualified 0 (T i cs))) $
VT wild (vty vs) (mapSnd ($vs) cs')
wild = case i of TWild _ -> True; _ -> False
convertv cs' vty =
convert' cs' =<< paramValues'' env (value2term (gloc env) [] vty)
-- Old value2term error message: Left i -> fail ("variable #"++show i++" is out of scope")
convert cs' ty = convert' cs' =<< paramValues' env ty
convert' cs' ((pty,vs),pvs) =
do sts <- mapM (matchPattern cs') vs
return $ \ vs -> VV pty pvs $ map (err bug id . valueMatch env)
(mapFst ($vs) sts)
valueCase (p,t) = do p' <- measurePatt # inlinePattMacro p
pvs <- linPattVars p'
vt <- value (extend pvs env) t
return (p',\vs-> Bind $ \bs-> vt (push' p' bs pvs vs))
inlinePattMacro p =
case p of
PM qc -> do r <- resource env qc
case r of
VPatt p' -> inlinePattMacro p'
_ -> ppbug $ hang "Expected pattern macro:" 4
(show r)
_ -> composPattOp inlinePattMacro p
paramValues env ty = snd # paramValues' env ty
paramValues' env ty = paramValues'' env =<< nfx (global env) ty
paramValues'' env pty = do ats <- allParamValues (srcgr env) pty
pvs <- mapM (eval (global env) []) ats
return ((pty,ats),pvs)
push' p bs xs = if length bs/=length xs
then bug $ "push "++show (p,bs,xs)
else push bs xs
push :: Env -> LocalScope -> Stack -> Stack
push bs [] vs = vs
push bs (x:xs) vs = maybe err id (lookup x bs):push bs xs vs
where err = bug $ "Unbound pattern variable "++showIdent x
apply' :: CompleteEnv -> Term -> [OpenValue] -> Err OpenValue
apply' env t [] = value env t
apply' env t vs =
case t of
QC x -> return $ \ svs -> VCApp x (map ($svs) vs)
{-
Q x@(m,f) | m==cPredef -> return $
let constr = --trace ("predef "++show x) .
VApp x
in \ svs -> maybe constr id (Map.lookup f predefs)
$ map ($svs) vs
| otherwise -> do r <- resource env x
return $ \ svs -> vapply (gloc env) r (map ($svs) vs)
-}
App t1 t2 -> apply' env t1 . (:vs) =<< value env t2
_ -> do fv <- value env t
return $ \ svs -> vapply (gloc env) (fv svs) (map ($svs) vs)
vapply :: GLocation -> Value -> [Value] -> Value
vapply loc v [] = v
vapply loc v vs =
case v of
VError {} -> v
-- VClosure env (Abs b x t) -> beta gr env b x t vs
VAbs bt _ (Bind f) -> vbeta loc bt f vs
VApp pre vs1 -> delta' pre (vs1++vs)
where
delta' Trace (v1:v2:vs) = let vr = vapply loc v2 vs
in vtrace loc v1 vr
delta' pre vs = err msg vfv $ mapM (delta pre) (varyList vs)
--msg = const (VApp pre (vs1++vs))
msg = bug . (("Applying Predef."++showIdent (predefName pre)++": ")++)
VS (VV t pvs fs) s -> VS (VV t pvs [vapply loc f vs|f<-fs]) s
VFV fs -> vfv [vapply loc f vs|f<-fs]
VCApp f vs0 -> VCApp f (vs0++vs)
VMeta i env vs0 -> VMeta i env (vs0++vs)
VGen i vs0 -> VGen i (vs0++vs)
v -> bug $ "vapply "++show v++" "++show vs
vbeta loc bt f (v:vs) =
case (bt,v) of
(Implicit,VImplArg v) -> ap v
(Explicit, v) -> ap v
where
ap (VFV avs) = vfv [vapply loc (f v) vs|v<-avs]
ap v = vapply loc (f v) vs
vary (VFV vs) = vs
vary v = [v]
varyList = mapM vary
{-
beta env b x t (v:vs) =
case (b,v) of
(Implicit,VImplArg v) -> apply' (ext (x,v) env) t vs
(Explicit, v) -> apply' (ext (x,v) env) t vs
-}
vtrace loc arg res = trace (render (hang (pv arg) 4 ("->"<+>pv res))) res
where
pv v = case v of
VRec (f:as) -> hang (pf f) 4 (fsep (map pa as))
_ -> ppV v
pf (_,VString n) = pp n
pf (_,v) = ppV v
pa (_,v) = ppV v
ppV v = ppTerm Unqualified 10 (value2term' True loc [] v)
-- Old value2term error message:
-- Left i -> "variable #" <> pp i <+> "is out of scope"
-- | Convert a value back to a term
value2term :: GLocation -> [Ident] -> Value -> Term
value2term = value2term' False
value2term' :: Bool -> p -> [Ident] -> Value -> Term
value2term' stop loc xs v0 =
case v0 of
VApp pre vs -> applyMany (Q (cPredef,predefName pre)) vs
VCApp f vs -> applyMany (QC f) vs
VGen j vs -> applyMany (var j) vs
VMeta j env vs -> applyMany (Meta j) vs
VProd bt v x f -> Prod bt x (v2t v) (v2t' x f)
VAbs bt x f -> Abs bt x (v2t' x f)
VInt n -> EInt n
VFloat f -> EFloat f
VString s -> if null s then Empty else K s
VSort s -> Sort s
VImplArg v -> ImplArg (v2t v)
VTblType p res -> Table (v2t p) (v2t res)
VRecType rs -> RecType [(l, v2t v) | (l,v) <- rs]
VRec as -> R [(l, (Nothing, v2t v)) | (l,v) <- as]
VV t _ vs -> V t (map v2t vs)
VT wild v cs -> T ((if wild then TWild else TTyped) (v2t v)) (map nfcase cs)
VFV vs -> FV (map v2t vs)
VC v1 v2 -> C (v2t v1) (v2t v2)
VS v1 v2 -> S (v2t v1) (v2t v2)
VP v l -> P (v2t v) l
VPatt p -> EPatt p
VPattType v -> EPattType $ v2t v
VAlts v vvs -> Alts (v2t v) [(v2t x, v2t y) | (x,y) <- vvs]
VStrs vs -> Strs (map v2t vs)
-- VGlue v1 v2 -> Glue (v2t v1) (v2t v2)
-- VExtR v1 v2 -> ExtR (v2t v1) (v2t v2)
VError err -> Error err
where
applyMany f vs = foldl App f (map v2t vs)
v2t = v2txs xs
v2txs = value2term' stop loc
v2t' x f = v2txs (x:xs) (bind f (gen xs))
var j
| j<length xs = Vr (reverse xs !! j)
| otherwise = error ("variable #"++show j++" is out of scope")
pushs xs e = foldr push e xs
push x (env,xs) = ((x,gen xs):env,x:xs)
gen xs = VGen (length xs) []
nfcase (p,f) = (,) p (v2txs xs' (bind f env'))
where (env',xs') = pushs (pattVars p) ([],xs)
bind (Bind f) x = if stop
then VSort (identS "...") -- hmm
else f x
linPattVars p =
if null dups
then return pvs
else fail.render $ hang "Pattern is not linear. All variable names on the left-hand side must be distinct." 4 (ppPatt Unqualified 0 p)
where
allpvs = allPattVars p
pvs = nub allpvs
dups = allpvs \\ pvs
pattVars = nub . allPattVars
allPattVars p =
case p of
PV i -> [i]
PAs i p -> i:allPattVars p
_ -> collectPattOp allPattVars p
---
ix loc fn xs i =
if i<n
then xs !! i
else bugloc loc $ "(!!): index too large in "++fn++", "++show i++"<"++show n
where n = length xs
infixl 1 #,<# --,@@
f # x = fmap f x
mf <# mx = ap mf mx
--m1 @@ m2 = (m1 =<<) . m2
both f (x,y) = (,) # f x <# f y
bugloc loc s = ppbug $ ppL loc s
bug msg = ppbug msg
ppbug doc = error $ render $ hang "Internal error in Compute.Concrete:" 4 doc

View File

@@ -1,172 +0,0 @@
-- | Implementations of predefined functions
{-# LANGUAGE TypeSynonymInstances, FlexibleInstances #-}
module GF.Compile.Compute.Predef(predef,predefName,delta) where
import qualified Data.Map as Map
import Data.Array(array,(!))
import Data.List (isInfixOf)
import Data.Char (isUpper,toLower,toUpper)
import Control.Monad(ap)
import GF.Data.Utilities (apBoth) --mapSnd
import GF.Compile.Compute.Value
import GF.Infra.Ident (Ident,showIdent) --,varX
import GF.Data.Operations(Err) -- ,err
import GF.Grammar.Predef
--------------------------------------------------------------------------------
class Predef a where
toValue :: a -> Value
fromValue :: Value -> Err a
instance Predef Int where
toValue = VInt
fromValue (VInt i) = return i
fromValue v = verror "Int" v
instance Predef Bool where
toValue = boolV
fromValue v = case v of
VCApp (mn,i) [] | mn == cPredef && i == cPTrue -> return True
VCApp (mn,i) [] | mn == cPredef && i == cPFalse -> return False
_ -> verror "Bool" v
instance Predef String where
toValue = string
fromValue v = case norm v of
VString s -> return s
_ -> verror "String" v
instance Predef Value where
toValue = id
fromValue = return
instance Predef Predefined where
toValue p = VApp p []
fromValue v = case v of
VApp p _ -> return p
_ -> fail $ "Expected a predefined constant, got something else"
{-
instance (Predef a,Predef b) => Predef (a->b) where
toValue f = VAbs Explicit (varX 0) $ Bind $ err bug (toValue . f) . fromValue
-}
verror t v =
case v of
VError e -> fail e
VGen {} -> fail $ "Expected a static value of type "++t
++", got a dynamic value"
_ -> fail $ "Expected a value of type "++t++", got "++show v
--------------------------------------------------------------------------------
predef f = maybe undef return (Map.lookup f predefs)
where
undef = fail $ "Unimplemented predfined operator: Predef."++showIdent f
predefs :: Map.Map Ident Predefined
predefs = Map.fromList predefList
predefName pre = predefNames ! pre
predefNames = array (minBound,maxBound) (map swap predefList)
predefList =
[(cDrop,Drop),(cTake,Take),(cTk,Tk),(cDp,Dp),(cEqStr,EqStr),
(cOccur,Occur),(cOccurs,Occurs),(cToUpper,ToUpper),(cToLower,ToLower),
(cIsUpper,IsUpper),(cLength,Length),(cPlus,Plus),(cEqInt,EqInt),
(cLessInt,LessInt),
-- cShow, cRead, cMapStr, cEqVal
(cError,Error),(cTrace,Trace),
-- Canonical values:
(cPBool,PBool),(cPFalse,PFalse),(cPTrue,PTrue),(cInt,Int),(cFloat,Float),
(cInts,Ints),(cNonExist,NonExist)
,(cBIND,BIND),(cSOFT_BIND,SOFT_BIND),(cSOFT_SPACE,SOFT_SPACE)
,(cCAPIT,CAPIT),(cALL_CAPIT,ALL_CAPIT)]
--- add more functions!!!
delta f vs =
case f of
Drop -> fromNonExist vs NonExist (ap2 (drop::Int->String->String))
Take -> fromNonExist vs NonExist (ap2 (take::Int->String->String))
Tk -> fromNonExist vs NonExist (ap2 tk)
Dp -> fromNonExist vs NonExist (ap2 dp)
EqStr -> fromNonExist vs PFalse (ap2 ((==)::String->String->Bool))
Occur -> fromNonExist vs PFalse (ap2 occur)
Occurs -> fromNonExist vs PFalse (ap2 occurs)
ToUpper -> fromNonExist vs NonExist (ap1 (map toUpper))
ToLower -> fromNonExist vs NonExist (ap1 (map toLower))
IsUpper -> fromNonExist vs PFalse (ap1 (all' isUpper))
Length -> fromNonExist vs (0::Int) (ap1 (length::String->Int))
Plus -> ap2 ((+)::Int->Int->Int)
EqInt -> ap2 ((==)::Int->Int->Bool)
LessInt -> ap2 ((<)::Int->Int->Bool)
{- -- | Show | Read | ToStr | MapStr | EqVal -}
Error -> ap1 VError
Trace -> ap2 vtrace
-- Canonical values:
PBool -> canonical
Int -> canonical
Float -> canonical
Ints -> canonical
PFalse -> canonical
PTrue -> canonical
NonExist-> canonical
BIND -> canonical
SOFT_BIND->canonical
SOFT_SPACE->canonical
CAPIT -> canonical
ALL_CAPIT->canonical
where
canonical = delay
delay = return (VApp f vs) -- wrong number of arguments
ap1 f = case vs of
[v1] -> (toValue . f) `fmap` fromValue v1
_ -> delay
ap2 f = case vs of
[v1,v2] -> toValue `fmap` (f `fmap` fromValue v1 `ap` fromValue v2)
_ -> delay
fromNonExist vs a b
| null [v | v@(VApp NonExist _) <- vs] = b
| otherwise = return (toValue a)
vtrace :: Value -> Value -> Value
vtrace x y = y -- tracing is implemented elsewhere
-- unimpl id = bug $ "unimplemented predefined function: "++showIdent id
-- problem id vs = bug $ "unexpected arguments: Predef."++showIdent id++" "++show vs
tk i s = take (max 0 (length s - i)) s :: String
dp i s = drop (max 0 (length s - i)) s :: String
occur s t = isInfixOf (s::String) (t::String)
occurs s t = any (`elem` (t::String)) (s::String)
all' = all :: (a->Bool) -> [a] -> Bool
boolV b = VCApp (cPredef,if b then cPTrue else cPFalse) []
norm v =
case v of
VC v1 v2 -> case apBoth norm (v1,v2) of
(VString s1,VString s2) -> VString (s1++" "++s2)
(v1,v2) -> VC v1 v2
_ -> v
{-
strict v = case v of
VError err -> Left err
_ -> Right v
-}
string s = case words s of
[] -> VString ""
ss -> foldr1 VC (map VString ss)
---
swap (x,y) = (y,x)
{-
bug msg = ppbug msg
ppbug doc = error $ render $
hang "Internal error in Compute.Predef:" 4 doc
-}

View File

@@ -1,56 +0,0 @@
module GF.Compile.Compute.Value where
import GF.Grammar.Grammar(Label,Type,MetaId,Patt,QIdent)
import PGF2(BindType)
import GF.Infra.Ident(Ident)
import Text.Show.Functions()
import Data.Ix(Ix)
-- | Self-contained (not quite) representation of values
data Value
= VApp Predefined [Value] -- from Q, always Predef.x, has a built-in value
| VCApp QIdent [Value] -- from QC, constructors
| VGen Int [Value] -- for lambda bound variables, possibly applied
| VMeta MetaId Env [Value]
-- -- | VClosure Env Term -- used in Typecheck.ConcreteNew
| VAbs BindType Ident Binding -- used in Compute.Concrete
| VProd BindType Value Ident Binding -- used in Compute.Concrete
| VInt Int
| VFloat Double
| VString String
| VSort Ident
| VImplArg Value
| VTblType Value Value
| VRecType [(Label,Value)]
| VRec [(Label,Value)]
| VV Type [Value] [Value] -- preserve type for conversion back to Term
| VT Wild Value [(Patt,Bind Env)]
| VC Value Value
| VS Value Value
| VP Value Label
| VPatt Patt
| VPattType Value
| VFV [Value]
| VAlts Value [(Value, Value)]
| VStrs [Value]
-- -- | VGlue Value Value -- hmm
-- -- | VExtR Value Value -- hmm
| VError String
deriving (Eq,Show)
type Wild = Bool
type Binding = Bind Value
data Bind a = Bind (a->Value) deriving Show
instance Eq (Bind a) where x==y = False
type Env = [(Ident,Value)]
-- | Predefined functions
data Predefined = Drop | Take | Tk | Dp | EqStr | Occur | Occurs | ToUpper
| ToLower | IsUpper | Length | Plus | EqInt | LessInt
{- | Show | Read | ToStr | MapStr | EqVal -}
| Error | Trace
-- Canonical values below:
| PBool | PFalse | PTrue | Int | Float | Ints | NonExist
| BIND | SOFT_BIND | SOFT_SPACE | CAPIT | ALL_CAPIT
deriving (Show,Eq,Ord,Ix,Bounded,Enum)

View File

@@ -1,415 +0,0 @@
-- | Translate concrete syntax to Haskell
module GF.Compile.ConcreteToHaskell(concretes2haskell,concrete2haskell) where
import Data.List(isPrefixOf,sort,sortOn)
import qualified Data.Map as M
import qualified Data.Set as S
import GF.Text.Pretty
--import GF.Grammar.Predef(cPredef,cInts)
--import GF.Compile.Compute.Predef(predef)
--import GF.Compile.Compute.Value(Predefined(..))
import GF.Infra.Ident(Ident,identC,identS,identW,prefixIdent,showRawIdent,rawIdentS)
import GF.Infra.Option
import GF.Haskell as H
import GF.Grammar.Canonical as C
import GF.Compile.GrammarToCanonical
import Debug.Trace(trace)
-- | Generate Haskell code for the all concrete syntaxes associated with
-- the named abstract syntax in given the grammar.
concretes2haskell opts absname gr =
[(filename,render80 $ concrete2haskell opts abstr cncmod)
| let Grammar abstr cncs = grammar2canonical opts absname gr,
cncmod<-cncs,
let ModId name = concName cncmod
filename = showRawIdent name ++ ".hs" :: FilePath
]
-- | Generate Haskell code for the given concrete module.
-- The only options that make a difference are
-- @-haskell=noprefix@ and @-haskell=variants@.
concrete2haskell opts
abstr@(Abstract _ _ cats funs)
modinfo@(Concrete cnc absname _ ps lcs lns) =
haskPreamble absname cnc $$
vcat (
nl:Comment "--- Parameter types ---":
map paramDef ps ++
nl:Comment "--- Type signatures for linearization functions ---":
map signature cats ++
nl:Comment "--- Linearization functions for empty categories ---":
emptydefs ++
nl:Comment "--- Linearization types ---":
map lincatDef lcs ++
nl:Comment "--- Linearization functions ---":
lindefs ++
nl:Comment "--- Type classes for projection functions ---":
map labelClass (S.toList labels) ++
nl:Comment "--- Record types ---":
concatMap recordType recs)
where
nl = Comment ""
recs = S.toList (S.difference (records (lcs,lns)) common_records)
labels = S.difference (S.unions (map S.fromList recs)) common_labels
common_records = S.fromList [[label_s]]
common_labels = S.fromList [label_s]
label_s = LabelId (rawIdentS "s")
signature (CatDef c _) = TypeSig lf (Fun abs (pure lin))
where
abs = tcon0 (prefixIdent "A." (gId c))
lin = tcon0 lc
lf = linfunName c
lc = lincatName c
emptydefs = map emptydef (S.toList emptyCats)
emptydef c = Eqn (linfunName c,[WildP]) (Const "undefined")
emptyCats = allcats `S.difference` linfuncats
where
--funcats = S.fromList [c | FunDef f (C.Type _ (TypeApp c _))<-funs]
allcats = S.fromList [c | CatDef c _<-cats]
gId :: ToIdent i => i -> Ident
gId = (if haskellOption opts HaskellNoPrefix then id else prefixIdent "G")
. toIdent
va = haskellOption opts HaskellVariants
pure = if va then ListT else id
haskPreamble :: ModId -> ModId -> Doc
haskPreamble absname cncname =
"{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, LambdaCase #-}" $$
"module" <+> cncname <+> "where" $$
"import Prelude hiding (Ordering(..))" $$
"import Control.Applicative((<$>),(<*>))" $$
"import PGF.Haskell" $$
"import qualified" <+> absname <+> "as A" $$
"" $$
"--- Standard definitions ---" $$
"linString (A.GString s) ="<+>pure "R_s [TK s]" $$
"linInt (A.GInt i) ="<+>pure "R_s [TK (show i)]" $$
"linFloat (A.GFloat x) ="<+>pure "R_s [TK (show x)]" $$
"" $$
"----------------------------------------------------" $$
"-- Automatic translation from GF to Haskell follows" $$
"----------------------------------------------------"
where
pure = if va then brackets else pp
paramDef pd =
case pd of
ParamAliasDef p t -> H.Type (conap0 (gId p)) (convLinType t)
ParamDef p pvs -> Data (conap0 (gId p)) (map paramCon pvs) derive
where
paramCon (Param c cs) = ConAp (gId c) (map (tcon0.gId) cs)
derive = ["Eq","Ord","Show"]
convLinType = ppT
where
ppT t =
case t of
FloatType -> tcon0 (identS "Float")
IntType -> tcon0 (identS "Int")
ParamType (ParamTypeId p) -> tcon0 (gId p)
RecordType rs -> tcon (rcon' ls) (map ppT ts)
where (ls,ts) = unzip $ sortOn fst [(l,t)|RecordRow l t<-rs]
StrType -> tcon0 (identS "Str")
TableType pt lt -> Fun (ppT pt) (ppT lt)
-- TupleType lts ->
lincatDef (LincatDef c t) = tsyn0 (lincatName c) (convLinType t)
linfuncats = S.fromList linfuncatl
(linfuncatl,lindefs) = unzip (linDefs lns)
linDefs = map eqn . sortOn fst . map linDef
where eqn (cat,(f,(ps,rhs))) = (cat,Eqn (f,ps) rhs)
linDef (LinDef f xs rhs0) =
(cat,(linfunName cat,(lhs,rhs)))
where
lhs = [ConP (aId f) (map VarP abs_args)]
aId f = prefixIdent "A." (gId f)
[lincat] = [lincat | LincatDef c lincat<-lcs,c==cat]
[C.Type absctx (TypeApp cat _)] = [t | FunDef f' t<-funs, f'==f]
abs_args = map abs_arg args
abs_arg = prefixIdent "abs_"
args = map (prefixIdent "g" . toIdent) xs
rhs = lets (zipWith letlin args absctx)
(convert vs (coerce env lincat rhs0))
where
vs = [(VarValueId (Unqual x),a)|(VarId x,a)<-zip xs args]
env= [(VarValueId (Unqual x),lc)|(VarId x,lc)<-zip xs (map arglincat absctx)]
letlin a (TypeBinding _ (C.Type _ (TypeApp acat _))) =
(a,Ap (Var (linfunName acat)) (Var (abs_arg a)))
arglincat (TypeBinding _ (C.Type _ (TypeApp acat _))) = lincat
where
[lincat] = [lincat | LincatDef c lincat<-lcs,c==acat]
convert = convert' va
convert' va vs = ppT
where
ppT0 = convert' False vs
ppTv vs' = convert' va vs'
pure = if va then single else id
ppT t =
case t of
TableValue ty cs -> pure (table cs)
Selection t p -> select (ppT t) (ppT p)
ConcatValue t1 t2 -> concat (ppT t1) (ppT t2)
RecordValue r -> aps (rcon ls) (map ppT ts)
where (ls,ts) = unzip $ sortOn fst [(l,t)|RecordRow l t<-r]
PredefValue p -> single (Var (toIdent p)) -- hmm
Projection t l -> ap (proj l) (ppT t)
VariantValue [] -> empty
VariantValue ts@(_:_) -> variants ts
VarValue x -> maybe (Var (gId x)) (pure . Var) $ lookup x vs
PreValue vs t' -> pure (alts t' vs)
ParamConstant (Param c vs) -> aps (Var (pId c)) (map ppT vs)
ErrorValue s -> ap (Const "error") (Const (show s)) -- !!
LiteralValue l -> ppL l
_ -> error ("convert "++show t)
ppL l =
case l of
FloatConstant x -> pure (lit x)
IntConstant n -> pure (lit n)
StrConstant s -> pure (token s)
pId p@(ParamId s) =
if "to_R_" `isPrefixOf` unqual s then toIdent p else gId p -- !! a hack
table cs =
if all (null.patVars) ps
then lets ds (LambdaCase [(ppP p,t')|(p,t')<-zip ps ts'])
else LambdaCase (map ppCase cs)
where
(ds,ts') = dedup ts
(ps,ts) = unzip [(p,t)|TableRow p t<-cs]
ppCase (TableRow p t) = (ppP p,ppTv (patVars p++vs) t)
{-
ppPredef n =
case predef n of
Ok BIND -> single (c "BIND")
Ok SOFT_BIND -> single (c "SOFT_BIND")
Ok SOFT_SPACE -> single (c "SOFT_SPACE")
Ok CAPIT -> single (c "CAPIT")
Ok ALL_CAPIT -> single (c "ALL_CAPIT")
_ -> Var n
-}
ppP p =
case p of
ParamPattern (Param c ps) -> ConP (gId c) (map ppP ps)
RecordPattern r -> ConP (rcon' ls) (map ppP ps)
where (ls,ps) = unzip $ sortOn fst [(l,p)|RecordRow l p<-r]
WildPattern -> WildP
token s = single (c "TK" `Ap` lit s)
alts t' vs = single (c "TP" `Ap` List (map alt vs) `Ap` ppT0 t')
where
alt (s,t) = Pair (List (pre s)) (ppT0 t)
pre s = map lit s
c = Const
lit s = c (show s) -- hmm
concat = if va then concat' else plusplus
where
concat' (List [List ts1]) (List [List ts2]) = List [List (ts1++ts2)]
concat' t1 t2 = Op t1 "+++" t2
pure' = single -- forcing the list monad
select = if va then select' else Ap
select' (List [t]) (List [p]) = Op t "!" p
select' (List [t]) p = Op t "!$" p
select' t p = Op t "!*" p
ap = if va then ap' else Ap
where
ap' (List [f]) x = fmap f x
ap' f x = Op f "<*>" x
fmap f (List [x]) = pure' (Ap f x)
fmap f x = Op f "<$>" x
-- join = if va then join' else id
join' (List [x]) = x
join' x = c "concat" `Ap` x
empty = if va then List [] else c "error" `Ap` c (show "empty variant")
variants = if va then \ ts -> join' (List (map ppT ts))
else \ (t:_) -> ppT t
aps f [] = f
aps f (a:as) = aps (ap f a) as
dedup ts =
if M.null dups
then ([],map ppT ts)
else ([(ev i,ppT t)|(i,t)<-defs],zipWith entry ts is)
where
entry t i = maybe (ppT t) (Var . ev) (M.lookup i dups)
ev i = identS ("e'"++show i)
defs = [(i1,t)|(t,i1:_:_)<-ms]
dups = M.fromList [(i2,i1)|(_,i1:is@(_:_))<-ms,i2<-i1:is]
ms = M.toList m
m = fmap sort (M.fromListWith (++) (zip ts [[i]|i<-is]))
is = [0..]::[Int]
--con = Cn . identS
class Records t where
records :: t -> S.Set [LabelId]
instance Records t => Records [t] where
records = S.unions . map records
instance (Records t1,Records t2) => Records (t1,t2) where
records (t1,t2) = S.union (records t1) (records t2)
instance Records LincatDef where
records (LincatDef _ lt) = records lt
instance Records LinDef where
records (LinDef _ _ lv) = records lv
instance Records LinType where
records t =
case t of
RecordType r -> rowRecords r
TableType pt lt -> records (pt,lt)
TupleType ts -> records ts
_ -> S.empty
rowRecords r = S.insert (sort ls) (records ts)
where (ls,ts) = unzip [(l,t)|RecordRow l t<-r]
instance Records LinValue where
records v =
case v of
ConcatValue v1 v2 -> records (v1,v2)
ParamConstant (Param c vs) -> records vs
RecordValue r -> rowRecords r
TableValue t r -> records (t,r)
TupleValue vs -> records vs
VariantValue vs -> records vs
PreValue alts d -> records (map snd alts,d)
Projection v l -> records v
Selection v1 v2 -> records (v1,v2)
_ -> S.empty
instance Records rhs => Records (TableRow rhs) where
records (TableRow _ v) = records v
-- | Record subtyping is converted into explicit coercions in Haskell
coerce env ty t =
case (ty,t) of
(_,VariantValue ts) -> VariantValue (map (coerce env ty) ts)
(TableType ti tv,TableValue _ cs) ->
TableValue ti [TableRow p (coerce env tv t)|TableRow p t<-cs]
(RecordType rt,RecordValue r) ->
RecordValue [RecordRow l (coerce env ft f) |
RecordRow l f<-r,ft<-[ft | RecordRow l' ft <- rt, l'==l]]
(RecordType rt,VarValue x)->
case lookup x env of
Just ty' | ty'/=ty -> -- better to compare to normal form of ty'
--trace ("coerce "++render ty'++" to "++render ty) $
app (to_rcon rt) [t]
| otherwise -> t -- types match, no coercion needed
_ -> trace (render ("missing type to coerce"<+>x<+>"to"<+>render ty
$$ "in" <+> map fst env))
t
_ -> t
where
app f ts = ParamConstant (Param f ts) -- !! a hack
to_rcon = ParamId . Unqual . rawIdentS . to_rcon' . labels
patVars p = []
labels r = [l | RecordRow l _ <- r]
proj = Var . identS . proj'
proj' (LabelId l) = "proj_" ++ showRawIdent l
rcon = Var . rcon'
rcon' = identS . rcon_name
rcon_name ls = "R"++concat (sort ['_':showRawIdent l | LabelId l <- ls])
to_rcon' = ("to_"++) . rcon_name
recordType ls =
Data lhs [app] ["Eq","Ord","Show"]:
enumAllInstance:
zipWith projection vs ls ++
[Eqn (identS (to_rcon' ls),[VarP r])
(foldl Ap (Var cn) [Var (identS (proj' l)) `Ap` Var r|l<-ls])]
where
r = identS "r"
cn = rcon' ls
-- Not all record labels are syntactically correct as type variables in Haskell
-- app = cn<+>ls
lhs = ConAp cn vs -- don't reuse record labels
app = fmap TId lhs
tapp = foldl TAp (TId cn) (map TId vs)
vs = [identS ('t':show i)|i<-[1..n]]
n = length ls
projection v l = Instance [] (TId name `TAp` tapp `TAp` TId v)
[((prj,[papp]),Var v)]
where
name = identS ("Has_"++render l)
prj = identS (proj' l)
papp = ConP cn (map VarP vs)
enumAllInstance =
Instance ctx (tEnumAll `TAp` tapp)[(lhs0 "enumAll",enumCon cn n)]
where
ctx = [tEnumAll `TAp` TId v|v<-vs]
tEnumAll = TId (identS "EnumAll")
labelClass l =
Class [] (ConAp name [r,a]) [([r],[a])]
[(identS (proj' l),TId r `Fun` TId a)]
where
name = identS ("Has_"++render l)
r = identS "r"
a = identS "a"
enumCon name arity =
if arity==0
then single (Var name)
else foldl ap (single (Var name)) (replicate arity (Const "enumAll"))
where
ap (List [f]) a = Op f "<$>" a
ap f a = Op f "<*>" a
lincatName,linfunName :: CatId -> Ident
lincatName c = prefixIdent "Lin" (toIdent c)
linfunName c = prefixIdent "lin" (toIdent c)
class ToIdent i where toIdent :: i -> Ident
instance ToIdent ParamId where toIdent (ParamId q) = qIdentC q
instance ToIdent PredefId where toIdent (PredefId s) = identC s
instance ToIdent CatId where toIdent (CatId s) = identC s
instance ToIdent C.FunId where toIdent (FunId s) = identC s
instance ToIdent VarValueId where toIdent (VarValueId q) = qIdentC q
qIdentC = identS . unqual
unqual (Qual (ModId m) n) = showRawIdent m++"_"++ showRawIdent n
unqual (Unqual n) = showRawIdent n
instance ToIdent VarId where
toIdent Anonymous = identW
toIdent (VarId s) = identC s

View File

@@ -1,642 +0,0 @@
{-# LANGUAGE BangPatterns, RankNTypes, FlexibleInstances, MultiParamTypeClasses, PatternGuards #-}
----------------------------------------------------------------------
-- |
-- Maintainer : Krasimir Angelov
-- Stability : (stable)
-- Portability : (portable)
--
-- Convert PGF grammar to PMCFG grammar.
--
-----------------------------------------------------------------------------
module GF.Compile.GeneratePMCFG
(generatePMCFG, pgfCncCat, addPMCFG, resourceValues
) where
import qualified PGF2 as PGF2
import qualified PGF2.Internal as PGF2
import PGF2.Internal(Symbol(..),fidVar)
import GF.Infra.Option
import GF.Grammar hiding (Env, mkRecord, mkTable)
import GF.Grammar.Lookup
import GF.Grammar.Predef
import GF.Grammar.Lockfield (isLockLabel)
import GF.Data.BacktrackM
import GF.Data.Operations
import GF.Infra.UseIO (ePutStr,ePutStrLn) -- IOE,
import GF.Data.Utilities (updateNthM) --updateNth
import GF.Compile.Compute.Concrete(normalForm,resourceValues)
import qualified Data.Map as Map
import qualified Data.Set as Set
import qualified Data.List as List
--import qualified Data.IntMap as IntMap
import qualified Data.IntSet as IntSet
import GF.Text.Pretty
import Data.Array.IArray
import Data.Array.Unboxed
--import Data.Maybe
--import Data.Char (isDigit)
import Control.Applicative(Applicative(..))
import Control.Monad
import Control.Monad.Identity
--import Control.Exception
--import Debug.Trace(trace)
import qualified Control.Monad.Fail as Fail
----------------------------------------------------------------------
-- main conversion function
--generatePMCFG :: Options -> SourceGrammar -> Maybe FilePath -> SourceModule -> IOE SourceModule
generatePMCFG opts sgr opath cmo@(cm,cmi) = do
(seqs,js) <- mapAccumWithKeyM (addPMCFG opts gr cenv opath am cm) Map.empty (jments cmi)
when (verbAtLeast opts Verbose) $ ePutStrLn ""
return (cm,cmi{mseqs = Just (mkSetArray seqs), jments = js})
where
cenv = resourceValues opts gr
gr = prependModule sgr cmo
MTConcrete am = mtype cmi
mapAccumWithKeyM :: (Monad m, Ord k) => (a -> k -> b -> m (a,c)) -> a
-> Map.Map k b -> m (a,Map.Map k c)
mapAccumWithKeyM f a m = do let xs = Map.toAscList m
(a,ys) <- mapAccumM f a xs
return (a,Map.fromAscList ys)
where
mapAccumM f a [] = return (a,[])
mapAccumM f a ((k,x):kxs) = do (a,y ) <- f a k x
(a,kys) <- mapAccumM f a kxs
return (a,(k,y):kys)
--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
--when (verbAtLeast opts Verbose) $ ePutStr ("\n+ "++showIdent id++" ...")
let pres = protoFCat gr res val
pargs = [protoFCat gr (snd $ catSkeleton ty) lincat | ((_,_,ty),(_,_,lincat)) <- zip ctxt cont]
pmcfgEnv0 = emptyPMCFGEnv
b <- convert opts gr cenv (floc opath loc id) term (cont,val) pargs
let (seqs1,b1) = addSequencesB seqs b
pmcfgEnv1 = foldBM addRule
pmcfgEnv0
(goB b1 CNil [])
(pres,pargs)
pmcfg = getPMCFG pmcfgEnv1
stats = let PMCFG prods funs = pmcfg
(s,e) = bounds funs
!prods_cnt = length prods
!funs_cnt = e-s+1
in (prods_cnt,funs_cnt)
when (verbAtLeast opts Verbose) $
ePutStr ("\n+ "++showIdent id++" "++show (product (map catFactor pargs)))
seqs1 `seq` stats `seq` return ()
when (verbAtLeast opts Verbose) $ ePutStr (" "++show stats)
return (seqs1,CncFun mty mlin mprn (Just pmcfg))
where
(ctxt,res,_) = err bug typeForm (lookupFunType gr am id)
addRule lins (newCat', newArgs') env0 =
let [newCat] = getFIds newCat'
!fun = mkArray lins
newArgs = map getFIds newArgs'
in addFunction env0 newCat fun newArgs
addPMCFG opts gr cenv opath am cm seqs id (CncCat mty@(Just (L _ lincat))
mdef@(Just (L loc1 def))
mref@(Just (L loc2 ref))
mprn
Nothing) = do
let pcat = protoFCat gr (am,id) lincat
pvar = protoFCat gr (MN identW,cVar) typeStr
pmcfgEnv0 = emptyPMCFGEnv
let lincont = [(Explicit, varStr, typeStr)]
b <- convert opts gr cenv (floc opath loc1 id) def (lincont,lincat) [pvar]
let (seqs1,b1) = addSequencesB seqs b
pmcfgEnv1 = foldBM addLindef
pmcfgEnv0
(goB b1 CNil [])
(pcat,[pvar])
let lincont = [(Explicit, varStr, lincat)]
b <- convert opts gr cenv (floc opath loc2 id) ref (lincont,typeStr) [pcat]
let (seqs2,b2) = addSequencesB seqs1 b
pmcfgEnv2 = foldBM addLinref
pmcfgEnv1
(goB b2 CNil [])
(pvar,[pcat])
let pmcfg = getPMCFG pmcfgEnv2
when (verbAtLeast opts Verbose) $ ePutStr ("\n+ "++showIdent id++" "++show (catFactor pcat))
seqs2 `seq` pmcfg `seq` return (seqs2,CncCat mty mdef mref mprn (Just pmcfg))
where
addLindef lins (newCat', newArgs') env0 =
let [newCat] = getFIds newCat'
!fun = mkArray lins
in addFunction env0 newCat fun [[fidVar]]
addLinref lins (newCat', [newArg']) env0 =
let newArg = getFIds newArg'
!fun = mkArray lins
in addFunction env0 fidVar fun [newArg]
addPMCFG opts gr cenv opath am cm seqs id info = return (seqs, info)
floc opath loc id = maybe (L loc id) (\path->L (External path loc) id) opath
convert opts gr cenv loc term ty@(_,val) pargs =
case normalForm cenv loc (etaExpand ty term) of
Error s -> fail $ render $ ppL loc ("Predef.error: "++s)
term -> return $ runCnvMonad gr (convertTerm opts CNil val term) (pargs,[])
where
etaExpand (context,val) = mkAbs pars . flip mkApp args
where pars = [(Explicit,v) | v <- vars]
args = map Vr vars
vars = map (\(bt,x,t) -> x) context
pgfCncCat :: SourceGrammar -> PGF2.Cat -> Type -> Int -> (PGF2.Cat,Int,Int,[String])
pgfCncCat gr id lincat index =
let ((_,size),schema) = computeCatRange gr lincat
in ( id
, index
, index+size-1
, map (renderStyle style{mode=OneLineMode} . ppPath)
(getStrPaths schema)
)
where
getStrPaths :: Schema Identity s c -> [Path]
getStrPaths = collect CNil []
where
collect path paths (CRec rs) = foldr (\(lbl,Identity t) paths -> collect (CProj lbl path) paths t) paths rs
collect path paths (CTbl _ cs) = foldr (\(trm,Identity t) paths -> collect (CSel trm path) paths t) paths cs
collect path paths (CStr _) = reversePath path : paths
collect path paths (CPar _) = paths
----------------------------------------------------------------------
-- CnvMonad monad
--
-- The branching monad provides backtracking together with
-- recording of the choices made. We have two cases
-- when we have alternative choices:
--
-- * when we have parameter type, then
-- we have to try all possible values
-- * when we have variants we have to try all alternatives
--
-- The conversion monad keeps track of the choices and they are
-- returned as 'Branch' data type.
data Branch a
= Case Int Path [(Term,Branch a)]
| Variant [Branch a]
| Return a
newtype CnvMonad a = CM {unCM :: SourceGrammar
-> forall b . (a -> ([ProtoFCat],[Symbol]) -> Branch b)
-> ([ProtoFCat],[Symbol])
-> Branch b}
instance Fail.MonadFail CnvMonad where
fail = bug
instance Applicative CnvMonad where
pure = return
(<*>) = ap
instance Monad CnvMonad where
return a = CM (\gr c s -> c a s)
CM m >>= k = CM (\gr c s -> m gr (\a s -> unCM (k a) gr c s) s)
instance MonadState ([ProtoFCat],[Symbol]) CnvMonad where
get = CM (\gr c s -> c s s)
put s = CM (\gr c _ -> c () s)
instance Functor CnvMonad where
fmap f (CM m) = CM (\gr c s -> m gr (c . f) s)
runCnvMonad :: SourceGrammar -> CnvMonad a -> ([ProtoFCat],[Symbol]) -> Branch a
runCnvMonad gr (CM m) s = m gr (\v s -> Return v) s
-- | backtracking for all variants
variants :: [a] -> CnvMonad a
variants xs = CM (\gr c s -> Variant [c x s | x <- xs])
-- | backtracking for all parameter values that a variable could take
choices :: Int -> Path -> CnvMonad Term
choices nr path = do (args,_) <- get
let PFCat _ _ schema = args !! nr
descend schema path CNil
where
descend (CRec rs) (CProj lbl path) rpath = case lookup lbl rs of
Just (Identity t) -> descend t path (CProj lbl rpath)
descend (CRec rs) CNil rpath = do rs <- mapM (\(lbl,Identity t) -> fmap (assign lbl) (descend t CNil (CProj lbl rpath))) rs
return (R rs)
descend (CTbl pt cs) (CSel trm path) rpath = case lookup trm cs of
Just (Identity t) -> descend t path (CSel trm rpath)
descend (CTbl pt cs) CNil rpath = do cs <- mapM (\(trm,Identity t) -> descend t CNil (CSel trm rpath)) cs
return (V pt cs)
descend (CPar (m,vs)) CNil rpath = case vs of
[(value,index)] -> return value
values -> let path = reversePath rpath
in CM (\gr c s -> Case nr path [(value, updateEnv path value gr c s)
| (value,index) <- values])
descend schema path rpath = bug $ "descend "++show (schema,path,rpath)
updateEnv path value gr c (args,seq) =
case updateNthM (restrictProtoFCat path value) nr args of
Just args -> c value (args,seq)
Nothing -> bug "conflict in updateEnv"
-- | the argument should be a parameter type and then
-- the function returns all possible values.
getAllParamValues :: Type -> CnvMonad [Term]
getAllParamValues ty = CM (\gr c -> c (err bug id (allParamValues gr ty)))
mkRecord :: [(Label,CnvMonad (Schema Branch s c))] -> CnvMonad (Schema Branch s c)
mkRecord xs = CM (\gr c -> foldl (\c (lbl,CM m) bs s -> c ((lbl,m gr (\v s -> Return v) s) : bs) s) (c . CRec) xs [])
mkTable :: Type -> [(Term ,CnvMonad (Schema Branch s c))] -> CnvMonad (Schema Branch s c)
mkTable pt xs = CM (\gr c -> foldl (\c (trm,CM m) bs s -> c ((trm,m gr (\v s -> Return v) s) : bs) s) (c . CTbl pt) xs [])
----------------------------------------------------------------------
-- Term Schema
--
-- The term schema is a term-like structure, with records, tables,
-- strings and parameters values, but in addition we could add
-- annotations of arbitrary types
-- | Term schema
data Schema b s c
= CRec [(Label,b (Schema b s c))]
| CTbl Type [(Term, b (Schema b s c))]
| CStr s
| CPar c
--deriving Show -- doesn't work
instance Show s => Show (Schema b s c) where
showsPrec _ sch =
case sch of
CRec r -> showString "CRec " . shows (map fst r)
CTbl t _ -> showString "CTbl " . showsPrec 10 t . showString " _"
CStr s -> showString "CStr " . showsPrec 10 s
CPar c -> showString "CPar{}"
-- | Path into a term or term schema
data Path
= CProj Label Path
| CSel Term Path
| CNil
deriving (Eq,Show)
-- | The ProtoFCat represents a linearization type as term schema.
-- The annotations are as follows: the strings are annotated with
-- their index in the PMCFG tuple, the parameters are annotated
-- with their value both as term and as index.
data ProtoFCat = PFCat Ident Int (Schema Identity Int (Int,[(Term,Int)]))
type Env = (ProtoFCat, [ProtoFCat])
protoFCat :: SourceGrammar -> Cat -> Type -> ProtoFCat
protoFCat gr cat lincat =
case computeCatRange gr lincat of
((_,f),schema) -> PFCat (snd cat) f schema
getFIds :: ProtoFCat -> [FId]
getFIds (PFCat _ _ schema) =
reverse (solutions (variants schema) ())
where
variants (CRec rs) = fmap sum $ mapM (\(lbl,Identity t) -> variants t) rs
variants (CTbl _ cs) = fmap sum $ mapM (\(trm,Identity t) -> variants t) cs
variants (CStr _) = return 0
variants (CPar (m,values)) = do (value,index) <- member values
return (m*index)
catFactor :: ProtoFCat -> Int
catFactor (PFCat _ f _) = f
computeCatRange gr lincat = compute (0,1) lincat
where
compute st (RecType rs) = let (st',rs') = List.mapAccumL (\st (lbl,t) -> case lbl of
LVar _ -> let (st',t') = compute st t
in (st ,(lbl,Identity t'))
_ -> let (st',t') = compute st t
in (st',(lbl,Identity t'))) st rs
in (st',CRec rs')
compute st (Table pt vt) = let vs = err bug id (allParamValues gr pt)
(st',cs') = List.mapAccumL (\st v -> let (st',vt') = compute st vt
in (st',(v,Identity vt'))) st vs
in (st',CTbl pt cs')
compute st (Sort s)
| s == cStr = let (index,m) = st
in ((index+1,m),CStr index)
compute st t = let vs = err bug id (allParamValues gr t)
(index,m) = st
in ((index,m*length vs),CPar (m,zip vs [0..]))
ppPath (CProj lbl path) = lbl <+> ppPath path
ppPath (CSel trm path) = ppU 5 trm <+> ppPath path
ppPath CNil = empty
reversePath path = rev CNil path
where
rev path0 CNil = path0
rev path0 (CProj lbl path) = rev (CProj lbl path0) path
rev path0 (CSel trm path) = rev (CSel trm path0) path
----------------------------------------------------------------------
-- term conversion
type Value a = Schema Branch a Term
convertTerm :: Options -> Path -> Type -> Term -> CnvMonad (Value [Symbol])
convertTerm opts sel ctype (Vr x) = convertArg opts ctype (getVarIndex x) (reversePath sel)
convertTerm opts sel ctype (Abs _ _ t) = convertTerm opts sel ctype t -- there are only top-level abstractions and we ignore them !!!
convertTerm opts sel ctype (R record) = convertRec opts sel ctype record
convertTerm opts sel ctype (P term l) = convertTerm opts (CProj l sel) ctype term
convertTerm opts sel ctype (V pt ts) = convertTbl opts sel ctype pt ts
convertTerm opts sel ctype (S term p) = do v <- evalTerm CNil p
convertTerm opts (CSel v sel) ctype term
convertTerm opts sel ctype (FV vars) = do term <- variants vars
convertTerm opts sel ctype term
convertTerm opts sel ctype (C t1 t2) = do v1 <- convertTerm opts sel ctype t1
v2 <- convertTerm opts sel ctype t2
return (CStr (concat [s | CStr s <- [v1,v2]]))
convertTerm opts sel ctype (K t) = return (CStr [SymKS t])
convertTerm opts sel ctype Empty = return (CStr [])
convertTerm opts sel ctype (Alts s alts)= do CStr s <- convertTerm opts CNil ctype s
alts <- forM alts $ \(u,alt) -> do
CStr u <- convertTerm opts CNil ctype u
Strs ps <- unPatt alt
ps <- mapM (convertTerm opts CNil ctype) ps
return (u,map unSym ps)
return (CStr [SymKP s alts])
where
unSym (CStr []) = ""
unSym (CStr [SymKS t]) = t
unSym _ = ppbug $ hang ("invalid prefix in pre expression:") 4 (Alts s alts)
unPatt (EPatt p) = fmap Strs (getPatts p)
unPatt u = return u
getPatts p = case p of
PAlt a b -> liftM2 (++) (getPatts a) (getPatts b)
PString s -> return [K s]
PSeq a b -> do
as <- getPatts a
bs <- getPatts b
return [K (s ++ t) | K s <- as, K t <- bs]
_ -> fail (render ("not valid pattern in pre expression" <+> ppPatt Unqualified 0 p))
convertTerm opts sel ctype (Q (m,f))
| m == cPredef &&
f == cBIND = return (CStr [SymBIND])
| m == cPredef &&
f == cSOFT_BIND = return (CStr [SymSOFT_BIND])
| m == cPredef &&
f == cSOFT_SPACE = return (CStr [SymSOFT_SPACE])
| m == cPredef &&
f == cCAPIT = return (CStr [SymCAPIT])
| m == cPredef &&
f == cALL_CAPIT = return (CStr [SymALL_CAPIT])
| m == cPredef &&
f == cNonExist = return (CStr [SymNE])
{-
convertTerm opts sel@(CProj l _) ctype (ExtR t1 t2@(R rs2))
| l `elem` map fst rs2 = convertTerm opts sel ctype t2
| otherwise = convertTerm opts sel ctype t1
convertTerm opts sel@(CProj l _) ctype (ExtR t1@(R rs1) t2)
| l `elem` map fst rs1 = convertTerm opts sel ctype t1
| otherwise = convertTerm opts sel ctype t2
-}
convertTerm opts CNil ctype t = do v <- evalTerm CNil t
return (CPar v)
convertTerm _ sel _ t = ppbug ("convertTerm" <+> sep [parens (show sel),ppU 10 t])
convertArg :: Options -> Term -> Int -> Path -> CnvMonad (Value [Symbol])
convertArg opts (RecType rs) nr path =
mkRecord (map (\(lbl,ctype) -> (lbl,convertArg opts ctype nr (CProj lbl path))) rs)
convertArg opts (Table pt vt) nr path = do
vs <- getAllParamValues pt
mkTable pt (map (\v -> (v,convertArg opts vt nr (CSel v path))) vs)
convertArg opts (Sort _) nr path = do
(args,_) <- get
let PFCat cat _ schema = args !! nr
l = index (reversePath path) schema
sym | CProj (LVar i) CNil <- path = SymVar nr i
| isLiteralCat opts cat = SymLit nr l
| otherwise = SymCat nr l
return (CStr [sym])
where
index (CProj lbl path) (CRec rs) = case lookup lbl rs of
Just (Identity t) -> index path t
index (CSel trm path) (CTbl _ rs) = case lookup trm rs of
Just (Identity t) -> index path t
index CNil (CStr idx) = idx
convertArg opts ty nr path = do
value <- choices nr (reversePath path)
return (CPar value)
convertRec opts CNil (RecType rs) record =
mkRecord [(lbl,convertTerm opts CNil ctype (proj lbl))|(lbl,ctype)<-rs]
where proj lbl = if isLockLabel lbl then R [] else projectRec lbl record
convertRec opts (CProj lbl path) ctype record =
convertTerm opts path ctype (projectRec lbl record)
convertRec opts _ ctype _ = bug ("convertRec: "++show ctype)
convertTbl opts CNil (Table _ vt) pt ts = do
vs <- getAllParamValues pt
mkTable pt (zipWith (\v t -> (v,convertTerm opts CNil vt t)) vs ts)
convertTbl opts (CSel v sub_sel) ctype pt ts = do
vs <- getAllParamValues pt
case lookup v (zip vs ts) of
Just t -> convertTerm opts sub_sel ctype t
Nothing -> ppbug ( "convertTbl:" <+> ("missing value" <+> v $$
"among" <+> vcat vs))
convertTbl opts _ ctype _ _ = bug ("convertTbl: "++show ctype)
goB :: Branch (Value SeqId) -> Path -> [SeqId] -> BacktrackM Env [SeqId]
goB (Case nr path bs) rpath ss = do (value,b) <- member bs
restrictArg nr path value
goB b rpath ss
goB (Variant bs) rpath ss = do b <- member bs
goB b rpath ss
goB (Return v) rpath ss = goV v rpath ss
goV :: Value SeqId -> Path -> [SeqId] -> BacktrackM Env [SeqId]
goV (CRec xs) rpath ss = foldM (\ss (lbl,b) -> goB b (CProj lbl rpath) ss) ss (reverse xs)
goV (CTbl _ xs) rpath ss = foldM (\ss (trm,b) -> goB b (CSel trm rpath) ss) ss (reverse xs)
goV (CStr seqid) rpath ss = return (seqid : ss)
goV (CPar t) rpath ss = restrictHead (reversePath rpath) t >> return ss
----------------------------------------------------------------------
-- SeqSet
type SeqSet = Map.Map [Symbol] 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
in (seqs',(trm,b'))) seqs bs
in (seqs1,Case nr path bs1)
addSequencesB seqs (Variant bs) = let !(seqs1,bs1) = mapAccumL' addSequencesB seqs bs
in (seqs1,Variant bs1)
addSequencesB seqs (Return v) = let !(seqs1,v1) = addSequencesV seqs v
in (seqs1,Return v1)
addSequencesV :: SeqSet -> Value [Symbol] -> (SeqSet, Value SeqId)
addSequencesV seqs (CRec vs) = let !(seqs1,vs1) = mapAccumL' (\seqs (lbl,b) -> let !(seqs',b') = addSequencesB seqs b
in (seqs',(lbl,b'))) seqs vs
in (seqs1,CRec vs1)
addSequencesV seqs (CTbl pt vs)=let !(seqs1,vs1) = mapAccumL' (\seqs (trm,b) -> let !(seqs',b') = addSequencesB seqs b
in (seqs',(trm,b'))) seqs vs
in (seqs1,CTbl pt vs1)
addSequencesV seqs (CStr lin) = let !(seqs1,seqid) = addSequence seqs lin
in (seqs1,CStr seqid)
addSequencesV seqs (CPar i) = (seqs,CPar i)
-- a strict version of Data.List.mapAccumL
mapAccumL' f s [] = (s,[])
mapAccumL' f s (x:xs) = (s'',y:ys)
where !(s', y ) = f s x
!(s'',ys) = mapAccumL' f s' xs
addSequence :: SeqSet -> [Symbol] -> (SeqSet,SeqId)
addSequence seqs seq =
case Map.lookup seq seqs of
Just id -> (seqs,id)
Nothing -> let !last_seq = Map.size seqs
in (Map.insert seq last_seq seqs, last_seq)
------------------------------------------------------------
-- eval a term to ground terms
evalTerm :: Path -> Term -> CnvMonad Term
evalTerm CNil (QC f) = return (QC f)
evalTerm CNil (App x y) = do x <- evalTerm CNil x
y <- evalTerm CNil y
return (App x y)
evalTerm path (Vr x) = choices (getVarIndex x) path
evalTerm path (R rs) =
case path of
CProj lbl path -> evalTerm path (projectRec lbl rs)
CNil -> R `fmap` mapM (\(lbl,(_,t)) -> assign lbl `fmap` evalTerm path t) rs
evalTerm path (P term lbl) = evalTerm (CProj lbl path) term
evalTerm path (V pt ts) =
case path of
CNil -> V pt `fmap` mapM (evalTerm path) ts
CSel trm path ->
do vs <- getAllParamValues pt
case lookup trm (zip vs ts) of
Just t -> evalTerm path t
Nothing -> ppbug $ "evalTerm: missing value:"<+>trm
$$ "among:" <+>fsep (map (ppU 10) vs)
evalTerm path (S term sel) = do v <- evalTerm CNil sel
evalTerm (CSel v path) term
evalTerm path (FV terms) = variants terms >>= evalTerm path
evalTerm path (EInt n) = return (EInt n)
evalTerm path t = ppbug ("evalTerm" <+> parens t)
--evalTerm path t = ppbug (text "evalTerm" <+> sep [parens (text (show path)),parens (text (show t))])
getVarIndex x = maybe err id $ getArgIndex x
where err = bug ("getVarIndex "++show x)
----------------------------------------------------------------------
-- GrammarEnv
data PMCFGEnv = PMCFGEnv !ProdSet !FunSet
type ProdSet = Set.Set Production
type FunSet = Map.Map (UArray LIndex SeqId) FunId
emptyPMCFGEnv =
PMCFGEnv Set.empty Map.empty
addFunction :: PMCFGEnv -> FId -> UArray LIndex SeqId -> [[FId]] -> PMCFGEnv
addFunction (PMCFGEnv prodSet funSet) !fid fun args =
case Map.lookup fun funSet of
Just !funid -> PMCFGEnv (Set.insert (Production fid funid args) prodSet)
funSet
Nothing -> let !funid = Map.size funSet
in PMCFGEnv (Set.insert (Production fid funid args) prodSet)
(Map.insert fun funid funSet)
getPMCFG :: PMCFGEnv -> PMCFG
getPMCFG (PMCFGEnv prodSet funSet) =
PMCFG (optimize prodSet) (mkSetArray funSet)
where
optimize ps = Map.foldrWithKey ff [] (Map.fromListWith (++) [((fid,funid),[args]) | (Production fid funid args) <- Set.toList ps])
where
ff :: (FId,FunId) -> [[[FId]]] -> [Production] -> [Production]
ff (fid,funid) xs prods
| product (map IntSet.size ys) == count
= (Production fid funid (map IntSet.toList ys)) : prods
| otherwise = map (Production fid funid) xs ++ prods
where
count = sum (map (product . map length) xs)
ys = foldl (zipWith (foldr IntSet.insert)) (repeat IntSet.empty) xs
------------------------------------------------------------
-- updating the MCF rule
restrictArg :: LIndex -> Path -> Term -> BacktrackM Env ()
restrictArg nr path index = do
(head, args) <- get
args <- updateNthM (restrictProtoFCat path index) nr args
put (head, args)
restrictHead :: Path -> Term -> BacktrackM Env ()
restrictHead path term = do
(head, args) <- get
head <- restrictProtoFCat path term head
put (head, args)
restrictProtoFCat :: (Functor m, MonadPlus m) => Path -> Term -> ProtoFCat -> m ProtoFCat
restrictProtoFCat path v (PFCat cat f schema) = do
schema <- addConstraint path v schema
return (PFCat cat f schema)
where
addConstraint (CProj lbl path) v (CRec rs) = fmap CRec $ update lbl (addConstraint path v) rs
addConstraint (CSel trm path) v (CTbl pt cs) = fmap (CTbl pt) $ update trm (addConstraint path v) cs
addConstraint CNil v (CPar (m,vs)) = case lookup v vs of
Just index -> return (CPar (m,[(v,index)]))
Nothing -> mzero
addConstraint CNil v (CStr _) = bug "restrictProtoFCat: string path"
update k0 f [] = return []
update k0 f (x@(k,Identity v):xs)
| k0 == k = do v <- f v
return ((k,Identity v):xs)
| otherwise = do xs <- update k0 f xs
return (x:xs)
mkArray lst = listArray (0,length lst-1) lst
mkSetArray map = array (0,Map.size map-1) [(v,k) | (k,v) <- Map.toList map]
bug msg = ppbug 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

View File

@@ -1,439 +0,0 @@
-- | Translate grammars to Canonical form
-- (a common intermediate representation to simplify export to other formats)
module GF.Compile.GrammarToCanonical(
grammar2canonical,abstract2canonical,concretes2canonical,
projection,selection
) where
import Data.List(nub,partition)
import qualified Data.Map as M
import Data.Maybe(fromMaybe)
import qualified Data.Set as S
import GF.Data.ErrM
import GF.Text.Pretty
import GF.Grammar.Grammar as G
import GF.Grammar.Lookup(lookupOrigInfo,allOrigInfos,allParamValues)
import GF.Grammar.Macros(typeForm,collectOp,collectPattOp,composSafeOp,mkAbs,mkApp,term2patt,sortRec)
import GF.Grammar.Lockfield(isLockLabel)
import GF.Grammar.Predef(cPredef,cInts)
import GF.Compile.Compute.Predef(predef)
import GF.Compile.Compute.Value(Predefined(..))
import GF.Infra.Ident(ModuleName(..),Ident,ident2raw,rawIdentS,showIdent,isWildIdent)
import GF.Infra.Option(Options,optionsPGF)
import PGF2.Internal(Literal(..))
import GF.Compile.Compute.Concrete(GlobalEnv,normalForm,resourceValues)
import GF.Grammar.Canonical as C
import System.FilePath ((</>), (<.>))
import qualified Debug.Trace as T
-- | Generate Canonical code for the named abstract syntax and all associated
-- concrete syntaxes
grammar2canonical :: Options -> ModuleName -> G.Grammar -> C.Grammar
grammar2canonical opts absname gr =
Grammar (abstract2canonical absname gr)
(map snd (concretes2canonical opts absname gr))
-- | Generate Canonical code for the named abstract syntax
abstract2canonical :: ModuleName -> G.Grammar -> Abstract
abstract2canonical absname gr =
Abstract (modId absname) (convFlags gr absname) cats funs
where
cats = [CatDef (gId c) (convCtx ctx) | ((_,c),AbsCat ctx) <- adefs]
funs = [FunDef (gId f) (convType ty) |
((_,f),AbsFun (Just (L _ ty)) ma mdef _) <- adefs]
adefs = allOrigInfos gr absname
convCtx = maybe [] (map convHypo . unLoc)
convHypo (bt,name,t) =
case typeForm t of
([],(_,cat),[]) -> gId cat -- !!
tf -> error $ "abstract2canonical convHypo: " ++ show tf
convType t =
case typeForm t of
(hyps,(_,cat),args) -> Type bs (TypeApp (gId cat) as)
where
bs = map convHypo' hyps
as = map convType args
convHypo' (bt,name,t) = TypeBinding (gId name) (convType t)
-- | Generate Canonical code for the all concrete syntaxes associated with
-- the named abstract syntax in given the grammar.
concretes2canonical :: Options -> ModuleName -> G.Grammar -> [(FilePath, Concrete)]
concretes2canonical opts absname gr =
[(cncname,concrete2canonical gr cenv absname cnc cncmod)
| let cenv = resourceValues opts gr,
cnc<-allConcretes gr absname,
let cncname = "canonical" </> render cnc <.> "gf"
Ok cncmod = lookupModule gr cnc
]
-- | Generate Canonical GF for the given concrete module.
concrete2canonical :: G.Grammar -> GlobalEnv -> ModuleName -> ModuleName -> ModuleInfo -> Concrete
concrete2canonical gr cenv absname cnc modinfo =
Concrete (modId cnc) (modId absname) (convFlags gr cnc)
(neededParamTypes S.empty (params defs))
[lincat | (_,Left lincat) <- defs]
[lin | (_,Right lin) <- defs]
where
defs = concatMap (toCanonical gr absname cenv) .
M.toList $
jments modinfo
params = S.toList . S.unions . map fst
neededParamTypes have [] = []
neededParamTypes have (q:qs) =
if q `S.member` have
then neededParamTypes have qs
else let ((got,need),def) = paramType gr q
in def++neededParamTypes (S.union got have) (S.toList need++qs)
-- toCanonical :: G.Grammar -> ModuleName -> GlobalEnv -> (Ident, Info) -> [(S.Set QIdent, Either LincatDef LinDef)]
toCanonical gr absname cenv (name,jment) =
case jment of
CncCat (Just (L loc typ)) _ _ pprn _ ->
[(pts,Left (LincatDef (gId name) (convType ntyp)))]
where
pts = paramTypes gr ntyp
ntyp = nf loc typ
CncFun (Just r@(cat,ctx,lincat)) (Just (L loc def)) pprn _ ->
[(tts,Right (LinDef (gId name) (map gId args) (convert gr e')))]
where
tts = tableTypes gr [e']
e' = cleanupRecordFields lincat $
unAbs (length params) $
nf loc (mkAbs params (mkApp def (map Vr args)))
params = [(b,x)|(b,x,_)<-ctx]
args = map snd params
AnyInd _ m -> case lookupOrigInfo gr (m,name) of
Ok (m,jment) -> toCanonical gr absname cenv (name,jment)
_ -> []
_ -> []
where
nf loc = normalForm cenv (L loc name)
unAbs 0 t = t
unAbs n (Abs _ _ t) = unAbs (n-1) t
unAbs _ t = t
tableTypes :: G.Grammar -> [Term] -> S.Set QIdent
tableTypes gr ts = S.unions (map tabtys ts)
where
tabtys t =
case t of
V t cc -> S.union (paramTypes gr t) (tableTypes gr cc)
T (TTyped t) cs -> S.union (paramTypes gr t) (tableTypes gr (map snd cs))
_ -> collectOp tabtys t
paramTypes :: G.Grammar -> G.Type -> S.Set QIdent
paramTypes gr t =
case t of
RecType fs -> S.unions (map (paramTypes gr.snd) fs)
Table t1 t2 -> S.union (paramTypes gr t1) (paramTypes gr t2)
App tf ta -> S.union (paramTypes gr tf) (paramTypes gr ta)
Sort _ -> S.empty
EInt _ -> S.empty
Q q -> lookup q
QC q -> lookup q
FV ts -> S.unions (map (paramTypes gr) ts)
_ -> ignore
where
lookup q = case lookupOrigInfo gr q of
Ok (_,ResOper _ (Just (L _ t))) ->
S.insert q (paramTypes gr t)
Ok (_,ResParam {}) -> S.singleton q
_ -> ignore
ignore = T.trace ("Ignore: " ++ show t) S.empty
-- | Filter out record fields from definitions which don't appear in lincat.
cleanupRecordFields :: G.Type -> Term -> Term
cleanupRecordFields (RecType ls) (R as) =
let defnFields = M.fromList ls
in R
[ (lbl, (mty, t'))
| (lbl, (mty, t)) <- as
, M.member lbl defnFields
, let Just ty = M.lookup lbl defnFields
, let t' = cleanupRecordFields ty t
]
cleanupRecordFields ty t@(FV _) = composSafeOp (cleanupRecordFields ty) t
cleanupRecordFields _ t = t
convert :: G.Grammar -> Term -> LinValue
convert gr = convert' gr []
convert' :: G.Grammar -> [Ident] -> Term -> LinValue
convert' gr vs = ppT
where
ppT0 = convert' gr vs
ppTv vs' = convert' gr vs'
ppT t =
case t of
-- Abs b x t -> ...
-- V ty ts -> VTableValue (convType ty) (map ppT ts)
V ty ts -> TableValue (convType ty) [TableRow (ppP p) (ppT t)|(p,t)<-zip ps ts]
where
Ok pts = allParamValues gr ty
Ok ps = mapM term2patt pts
T (TTyped ty) cs -> TableValue (convType ty) (map ppCase cs)
S t p -> selection (ppT t) (ppT p)
C t1 t2 -> concatValue (ppT t1) (ppT t2)
App f a -> ap (ppT f) (ppT a)
R r -> RecordValue (fields (sortRec r))
P t l -> projection (ppT t) (lblId l)
Vr x -> VarValue (gId x)
Cn x -> VarValue (gId x) -- hmm
Con c -> ParamConstant (Param (gId c) [])
Sort k -> VarValue (gId k)
EInt n -> LiteralValue (IntConstant n)
Q (m,n) -> if m==cPredef then ppPredef n else VarValue (gQId m n)
QC (m,n) -> ParamConstant (Param (gQId m n) [])
K s -> LiteralValue (StrConstant s)
Empty -> LiteralValue (StrConstant "")
FV ts -> VariantValue (map ppT ts)
Alts t' vs -> alts vs (ppT t')
_ -> error $ "convert' ppT: " ++ show t
ppCase (p,t) = TableRow (ppP p) (ppTv (patVars p++vs) t)
ppPredef n =
case predef n of
Ok BIND -> p "BIND"
Ok SOFT_BIND -> p "SOFT_BIND"
Ok SOFT_SPACE -> p "SOFT_SPACE"
Ok CAPIT -> p "CAPIT"
Ok ALL_CAPIT -> p "ALL_CAPIT"
_ -> VarValue (gQId cPredef n) -- hmm
where
p = PredefValue . PredefId . rawIdentS
ppP p =
case p of
PC c ps -> ParamPattern (Param (gId c) (map ppP ps))
PP (m,c) ps -> ParamPattern (Param (gQId m c) (map ppP ps))
PR r -> RecordPattern (fields r) {-
PW -> WildPattern
PV x -> VarP x
PString s -> Lit (show s) -- !!
PInt i -> Lit (show i)
PFloat x -> Lit (show x)
PT _ p -> ppP p
PAs x p -> AsP x (ppP p) -}
_ -> error $ "convert' ppP: " ++ show p
where
fields = map field . filter (not.isLockLabel.fst)
field (l,p) = RecordRow (lblId l) (ppP p)
-- patToParam p = case ppP p of ParamPattern pv -> pv
-- token s = single (c "TK" `Ap` lit s)
alts vs = PreValue (map alt vs)
where
alt (t,p) = (pre p,ppT0 t)
pre (K s) = [s]
pre Empty = [""] -- Empty == K ""
pre (Strs ts) = concatMap pre ts
pre (EPatt p) = pat p
pre t = error $ "convert' alts pre: " ++ show t
pat (PString s) = [s]
pat (PAlt p1 p2) = pat p1++pat p2
pat (PSeq p1 p2) = [s1++s2 | s1<-pat p1, s2<-pat p2]
pat p = error $ "convert' alts pat: "++show p
fields = map field . filter (not.isLockLabel.fst)
field (l,(_,t)) = RecordRow (lblId l) (ppT t)
--c = Const
--c = VarValue . VarValueId
--lit s = c (show s) -- hmm
ap f a = case f of
ParamConstant (Param p ps) ->
ParamConstant (Param p (ps++[a]))
_ -> error $ "convert' ap: "++render (ppA f <+> ppA a)
concatValue :: LinValue -> LinValue -> LinValue
concatValue v1 v2 =
case (v1,v2) of
(LiteralValue (StrConstant ""),_) -> v2
(_,LiteralValue (StrConstant "")) -> v1
_ -> ConcatValue v1 v2
-- | Smart constructor for projections
projection :: LinValue -> LabelId -> LinValue
projection r l = fromMaybe (Projection r l) (proj r l)
proj :: LinValue -> LabelId -> Maybe LinValue
proj r l =
case r of
RecordValue r -> case [v | RecordRow l' v <- r, l'==l] of
[v] -> Just v
_ -> Nothing
_ -> Nothing
-- | Smart constructor for selections
selection :: LinValue -> LinValue -> LinValue
selection t v =
-- Note: impossible cases can become possible after grammar transformation
case t of
TableValue tt r ->
case nub [rv | TableRow _ rv <- keep] of
[rv] -> rv
_ -> Selection (TableValue tt r') v
where
-- Don't introduce wildcard patterns, true to the canonical format,
-- annotate (or eliminate) rhs in impossible rows
r' = map trunc r
trunc r@(TableRow p e) = if mightMatchRow v r
then r
else TableRow p (impossible e)
{-
-- Creates smaller tables, but introduces wildcard patterns
r' = if null discard
then r
else keep++[TableRow WildPattern impossible]
-}
(keep,discard) = partition (mightMatchRow v) r
_ -> Selection t v
impossible :: LinValue -> LinValue
impossible = CommentedValue "impossible"
mightMatchRow :: LinValue -> TableRow rhs -> Bool
mightMatchRow v (TableRow p _) =
case p of
WildPattern -> True
_ -> mightMatch v p
mightMatch :: LinValue -> LinPattern -> Bool
mightMatch v p =
case v of
ConcatValue _ _ -> False
ParamConstant (Param c1 pvs) ->
case p of
ParamPattern (Param c2 pps) -> c1==c2 && length pvs==length pps &&
and [mightMatch v p|(v,p)<-zip pvs pps]
_ -> False
RecordValue rv ->
case p of
RecordPattern rp ->
and [maybe False (`mightMatch` p) (proj v l) | RecordRow l p<-rp]
_ -> False
_ -> True
patVars :: Patt -> [Ident]
patVars p =
case p of
PV x -> [x]
PAs x p -> x:patVars p
_ -> collectPattOp patVars p
convType :: Term -> LinType
convType = ppT
where
ppT t =
case t of
Table ti tv -> TableType (ppT ti) (ppT tv)
RecType rt -> RecordType (convFields rt)
-- App tf ta -> TAp (ppT tf) (ppT ta)
-- FV [] -> tcon0 (identS "({-empty variant-})")
Sort k -> convSort k
-- EInt n -> tcon0 (identS ("({-"++show n++"-})")) -- type level numeric literal
FV (t:ts) -> ppT t -- !!
QC (m,n) -> ParamType (ParamTypeId (gQId m n))
Q (m,n) -> ParamType (ParamTypeId (gQId m n))
_ -> error $ "convType ppT: " ++ show t
convFields = map convField . filter (not.isLockLabel.fst)
convField (l,r) = RecordRow (lblId l) (ppT r)
convSort k = case showIdent k of
"Float" -> FloatType
"Int" -> IntType
"Str" -> StrType
_ -> error $ "convType convSort: " ++ show k
toParamType :: Term -> ParamType
toParamType t = case convType t of
ParamType pt -> pt
_ -> error $ "toParamType: " ++ show t
toParamId :: Term -> ParamId
toParamId t = case toParamType t of
ParamTypeId p -> p
paramType :: G.Grammar
-> (ModuleName, Ident)
-> ((S.Set (ModuleName, Ident), S.Set QIdent), [ParamDef])
paramType gr q@(_,n) =
case lookupOrigInfo gr q of
Ok (m,ResParam (Just (L _ ps)) _)
{- - | m/=cPredef && m/=moduleNameS "Prelude"-} ->
((S.singleton (m,n),argTypes ps),
[ParamDef name (map (param m) ps)]
)
where name = gQId m n
Ok (m,ResOper _ (Just (L _ t)))
| m==cPredef && n==cInts ->
((S.empty,S.empty),[]) {-
((S.singleton (m,n),S.empty),
[Type (ConAp ((gQId m n)) [identS "n"]) (TId (identS "Int"))])-}
| otherwise ->
((S.singleton (m,n),paramTypes gr t),
[ParamAliasDef (gQId m n) (convType t)])
_ -> ((S.empty,S.empty),[])
where
param m (n,ctx) = Param (gQId m n) [toParamId t|(_,_,t)<-ctx]
argTypes = S.unions . map argTypes1
argTypes1 (n,ctx) = S.unions [paramTypes gr t|(_,_,t)<-ctx]
lblId :: Label -> C.LabelId
lblId (LIdent ri) = LabelId ri
lblId (LVar i) = LabelId (rawIdentS (show i)) -- hmm
modId :: ModuleName -> C.ModId
modId (MN m) = ModId (ident2raw m)
class FromIdent i where
gId :: Ident -> i
instance FromIdent VarId where
gId i = if isWildIdent i then Anonymous else VarId (ident2raw i)
instance FromIdent C.FunId where gId = C.FunId . ident2raw
instance FromIdent CatId where gId = CatId . ident2raw
instance FromIdent ParamId where gId = ParamId . unqual
instance FromIdent VarValueId where gId = VarValueId . unqual
class FromIdent i => QualIdent i where
gQId :: ModuleName -> Ident -> i
instance QualIdent ParamId where gQId m n = ParamId (qual m n)
instance QualIdent VarValueId where gQId m n = VarValueId (qual m n)
qual :: ModuleName -> Ident -> QualId
qual m n = Qual (modId m) (ident2raw n)
unqual :: Ident -> QualId
unqual n = Unqual (ident2raw n)
convFlags :: G.Grammar -> ModuleName -> Flags
convFlags gr mn =
Flags [(rawIdentS n,convLit v) |
(n,v)<-err (const []) (optionsPGF.mflags) (lookupModule gr mn)]
where
convLit l =
case l of
LStr s -> Str s
LInt i -> C.Int i
LFlt d -> Flt d

View File

@@ -1,232 +0,0 @@
{-# LANGUAGE PatternGuards #-}
----------------------------------------------------------------------
-- |
-- Module : Optimize
-- Maintainer : AR
-- Stability : (stable)
-- Portability : (portable)
--
-- > CVS $Date: 2005/09/16 13:56:13 $
-- > CVS $Author: aarne $
-- > CVS $Revision: 1.18 $
--
-- Top-level partial evaluation for GF source modules.
-----------------------------------------------------------------------------
module GF.Compile.Optimize (optimizeModule) where
import GF.Grammar.Grammar
import GF.Infra.Ident
import GF.Grammar.Printer
import GF.Grammar.Macros
import GF.Grammar.Lookup
import GF.Grammar.Predef
import GF.Compile.Compute.Concrete(GlobalEnv,normalForm,resourceValues)
import GF.Data.Operations
import GF.Infra.Option
import Control.Monad
import qualified Data.Set as Set
import qualified Data.Map as Map
import GF.Text.Pretty
import Debug.Trace
-- | partial evaluation of concrete syntax. AR 6\/2001 -- 16\/5\/2003 -- 5\/2\/2005.
optimizeModule :: Options -> SourceGrammar -> SourceModule -> Err SourceModule
optimizeModule opts sgr m@(name,mi)
| mstatus mi == MSComplete = do
ids <- topoSortJments m
mi <- foldM updateEvalInfo mi ids
return (name,mi)
| otherwise = return m
where
oopts = opts `addOptions` mflags mi
resenv = resourceValues oopts sgr
updateEvalInfo mi (i,info) = do
info <- evalInfo oopts resenv sgr (name,mi) i info
return (mi{jments=Map.insert i info (jments mi)})
evalInfo :: Options -> GlobalEnv -> SourceGrammar -> SourceModule -> Ident -> Info -> Err Info
evalInfo opts resenv sgr m c info = do
(if verbAtLeast opts Verbose then trace (" " ++ showIdent c) else id) return ()
errIn ("optimizing " ++ showIdent c) $ case info of
CncCat ptyp pde pre ppr mpmcfg -> do
pde' <- case (ptyp,pde) of
(Just (L _ typ), Just (L loc de)) -> do
de <- partEval opts gr ([(Explicit, varStr, typeStr)], typ) de
return (Just (L loc (factor param c 0 de)))
(Just (L loc typ), Nothing) -> do
de <- mkLinDefault gr typ
de <- partEval opts gr ([(Explicit, varStr, typeStr)], typ) de
return (Just (L loc (factor param c 0 de)))
_ -> return pde -- indirection
pre' <- case (ptyp,pre) of
(Just (L _ typ), Just (L loc re)) -> do
re <- partEval opts gr ([(Explicit, varStr, typ)], typeStr) re
return (Just (L loc (factor param c 0 re)))
(Just (L loc typ), Nothing) -> do
re <- mkLinReference gr typ
re <- partEval opts gr ([(Explicit, varStr, typ)], typeStr) re
return (Just (L loc (factor param c 0 re)))
_ -> return pre -- indirection
let ppr' = fmap (evalPrintname resenv c) ppr
return (CncCat ptyp pde' pre' ppr' mpmcfg)
CncFun (mt@(Just (_,cont,val))) pde ppr mpmcfg -> --trace (prt c) $
eIn ("linearization in type" <+> mkProd cont val [] $$ "of function") $ do
pde' <- case pde of
Just (L loc de) -> do de <- partEval opts gr (cont,val) de
return (Just (L loc (factor param c 0 de)))
Nothing -> return pde
let ppr' = fmap (evalPrintname resenv c) ppr
return $ CncFun mt pde' ppr' mpmcfg -- only cat in type actually needed
{-
ResOper pty pde
| not new && OptExpand `Set.member` optim -> do
pde' <- case pde of
Just (L loc de) -> do de <- computeConcrete gr de
return (Just (L loc (factor param c 0 de)))
Nothing -> return Nothing
return $ ResOper pty pde'
-}
_ -> return info
where
-- new = flag optNewComp opts -- computations moved to GF.Compile.GeneratePMCFG
gr = prependModule sgr m
optim = flag optOptimizations opts
param = OptParametrize `Set.member` optim
eIn cat = errIn (render ("Error optimizing" <+> cat <+> c <+> ':'))
-- | the main function for compiling linearizations
partEval :: Options -> SourceGrammar -> (Context,Type) -> Term -> Err Term
partEval opts = {-if flag optNewComp opts
then-} partEvalNew opts
{-else partEvalOld opts-}
partEvalNew opts gr (context, val) trm =
errIn (render ("partial evaluation" <+> ppTerm Qualified 0 trm)) $
checkPredefError trm
{-
partEvalOld opts gr (context, val) trm = errIn (render (text "partial evaluation" <+> ppTerm Qualified 0 trm)) $ do
let vars = map (\(bt,x,t) -> x) context
args = map Vr vars
subst = [(v, Vr v) | v <- vars]
trm1 = mkApp trm args
trm2 <- computeTerm gr subst trm1
trm3 <- if rightType trm2
then computeTerm gr subst trm2 -- compute twice??
else recordExpand val trm2 >>= computeTerm gr subst
trm4 <- checkPredefError trm3
return $ mkAbs [(Explicit,v) | v <- vars] trm4
where
-- don't eta expand records of right length (correct by type checking)
rightType (R rs) = case val of
RecType ts -> length rs == length ts
_ -> False
rightType _ = False
-- here we must be careful not to reduce
-- variants {{s = "Auto" ; g = N} ; {s = "Wagen" ; g = M}}
-- {s = variants {"Auto" ; "Wagen"} ; g = variants {N ; M}} ;
recordExpand :: Type -> Term -> Err Term
recordExpand typ trm = case typ of
RecType tys -> case trm of
FV rs -> return $ FV [R [assign lab (P r lab) | (lab,_) <- tys] | r <- rs]
_ -> return $ R [assign lab (P trm lab) | (lab,_) <- tys]
_ -> return trm
-}
-- | auxiliaries for compiling the resource
mkLinDefault :: SourceGrammar -> Type -> Err Term
mkLinDefault gr typ = liftM (Abs Explicit varStr) $ mkDefField typ
where
mkDefField typ = case typ of
Table p t -> do
t' <- mkDefField t
let T _ cs = mkWildCases t'
return $ T (TWild p) cs
Sort s | s == cStr -> return $ Vr varStr
QC p -> do vs <- lookupParamValues gr p
case vs of
v:_ -> return v
_ -> Bad (render ("no parameter values given to type" <+> ppQIdent Qualified p))
RecType r -> do
let (ls,ts) = unzip r
ts <- mapM mkDefField ts
return $ R (zipWith assign ls ts)
_ | Just _ <- isTypeInts typ -> return $ EInt 0 -- exists in all as first val
_ -> Bad (render ("linearization type field cannot be" <+> typ))
mkLinReference :: SourceGrammar -> Type -> Err Term
mkLinReference gr typ =
liftM (Abs Explicit varStr) $
case mkDefField typ (Vr varStr) of
Bad "no string" -> return Empty
x -> x
where
mkDefField ty trm =
case ty of
Table pty ty -> do ps <- allParamValues gr pty
case ps of
[] -> Bad "no string"
(p:ps) -> mkDefField ty (S trm p)
Sort s | s == cStr -> return trm
QC p -> Bad "no string"
RecType [] -> Bad "no string"
RecType rs -> do
msum (map (\(l,ty) -> mkDefField ty (P trm l)) (sortRec rs))
`mplus` Bad "no string"
_ | Just _ <- isTypeInts typ -> Bad "no string"
_ -> Bad (render ("linearization type field cannot be" <+> typ))
evalPrintname :: GlobalEnv -> Ident -> L Term -> L Term
evalPrintname resenv c (L loc pr) = L loc (normalForm resenv (L loc c) pr)
-- do even more: factor parametric branches
factor :: Bool -> Ident -> Int -> Term -> Term
factor param c i t =
case t of
T (TComp ty) cs -> factors ty [(p, factor param c (i+1) v) | (p, v) <- cs]
_ -> composSafeOp (factor param c i) t
where
factors ty pvs0
| not param = V ty (map snd pvs0)
factors ty [] = V ty []
factors ty pvs0@[(p,v)] = V ty [v]
factors ty pvs0@(pv:pvs) =
let t = mkFun pv
ts = map mkFun pvs
in if all (==t) ts
then T (TTyped ty) (mkCases t)
else V ty (map snd pvs0)
--- we hope this will be fresh and don't check... in GFC would be safe
qvar = identS ("q_" ++ showIdent c ++ "__" ++ show i)
mkFun (patt, val) = replace (patt2term patt) (Vr qvar) val
mkCases t = [(PV qvar, t)]
-- we need to replace subterms
replace :: Term -> Term -> Term -> Term
replace old new trm =
case trm of
-- these are the important cases, since they can correspond to patterns
QC _ | trm == old -> new
App _ _ | trm == old -> new
R _ | trm == old -> new
App x y -> App (replace old new x) (replace old new y)
_ -> composSafeOp (replace old new) trm

View File

@@ -1,110 +0,0 @@
module GF.Compile.PGFtoJSON (pgf2json) where
import PGF2
import PGF2.Internal
import Text.JSON
import qualified Data.Map as Map
pgf2json :: PGF -> String
pgf2json pgf =
encode $ makeObj
[ ("abstract", abstract2json pgf)
, ("concretes", makeObj $ map concrete2json
(Map.toList (languages pgf)))
]
abstract2json :: PGF -> JSValue
abstract2json pgf =
makeObj
[ ("name", showJSON (abstractName pgf))
, ("startcat", showJSON (showType [] (startCat pgf)))
, ("funs", makeObj $ map (absdef2json pgf) (functions pgf))
]
absdef2json :: PGF -> Fun -> (String,JSValue)
absdef2json pgf f = (f,sig)
where
Just (hypos,cat,_) = fmap unType (functionType pgf f)
sig = makeObj
[ ("args", showJSON $ map (\(_,_,ty) -> showType [] ty) hypos)
, ("cat", showJSON cat)
]
lit2json :: Literal -> JSValue
lit2json (LStr s) = showJSON s
lit2json (LInt n) = showJSON n
lit2json (LFlt d) = showJSON d
concrete2json :: (ConcName,Concr) -> (String,JSValue)
concrete2json (c,cnc) = (c,obj)
where
obj = makeObj
[ ("flags", makeObj [(k, lit2json v) | (k,v) <- concrFlags cnc])
, ("productions", makeObj [(show fid, showJSON (map frule2json (concrProductions cnc fid))) | (_,start,end,_) <- concrCategories cnc, fid <- [start..end]])
, ("functions", showJSON [ffun2json funid (concrFunction cnc funid) | funid <- [0..concrTotalFuns cnc-1]])
, ("sequences", showJSON [seq2json seqid (concrSequence cnc seqid) | seqid <- [0..concrTotalSeqs cnc-1]])
, ("categories", makeObj $ map cat2json (concrCategories cnc))
, ("totalfids", showJSON (concrTotalCats cnc))
]
cat2json :: (Cat,FId,FId,[String]) -> (String,JSValue)
cat2json (cat,start,end,_) = (cat, ixs)
where
ixs = makeObj
[ ("start", showJSON start)
, ("end", showJSON end)
]
frule2json :: Production -> JSValue
frule2json (PApply fid args) =
makeObj
[ ("type", showJSON "Apply")
, ("fid", showJSON fid)
, ("args", showJSON (map farg2json args))
]
frule2json (PCoerce arg) =
makeObj
[ ("type", showJSON "Coerce")
, ("arg", showJSON arg)
]
farg2json :: PArg -> JSValue
farg2json (PArg hypos fid) =
makeObj
[ ("type", showJSON "PArg")
, ("hypos", JSArray $ map (showJSON . snd) hypos)
, ("fid", showJSON fid)
]
ffun2json :: FunId -> (Fun,[SeqId]) -> JSValue
ffun2json funid (fun,seqids) =
makeObj
[ ("name", showJSON fun)
, ("lins", showJSON seqids)
]
seq2json :: SeqId -> [Symbol] -> JSValue
seq2json seqid seq = showJSON [sym2json sym | sym <- seq]
sym2json :: Symbol -> JSValue
sym2json (SymCat n l) = new "SymCat" [showJSON n, showJSON l]
sym2json (SymLit n l) = new "SymLit" [showJSON n, showJSON l]
sym2json (SymVar n l) = new "SymVar" [showJSON n, showJSON l]
sym2json (SymKS t) = new "SymKS" [showJSON t]
sym2json (SymKP ts alts) = new "SymKP" [JSArray (map sym2json ts), JSArray (map alt2json alts)]
sym2json SymBIND = new "SymKS" [showJSON "&+"]
sym2json SymSOFT_BIND = new "SymKS" [showJSON "&+"]
sym2json SymSOFT_SPACE = new "SymKS" [showJSON "&+"]
sym2json SymCAPIT = new "SymKS" [showJSON "&|"]
sym2json SymALL_CAPIT = new "SymKS" [showJSON "&|"]
sym2json SymNE = new "SymNE" []
alt2json :: ([Symbol],[String]) -> JSValue
alt2json (ps,ts) = new "Alt" [showJSON (map sym2json ps), showJSON ts]
new :: String -> [JSValue] -> JSValue
new f xs =
makeObj
[ ("type", showJSON f)
, ("args", showJSON xs)
]

View File

@@ -1,800 +0,0 @@
{-# LANGUAGE PatternGuards #-}
module GF.Compile.TypeCheck.Concrete( checkLType, inferLType, computeLType, ppType ) where
import Prelude hiding ((<>)) -- GHC 8.4.1 clash with Text.PrettyPrint
import GF.Infra.CheckM
import GF.Data.Operations
import GF.Grammar
import GF.Grammar.Lookup
import GF.Grammar.Predef
import GF.Grammar.PatternMatch
import GF.Grammar.Lockfield (isLockLabel, lockRecType, unlockRecord)
import GF.Compile.TypeCheck.Primitives
import Data.List
import Control.Monad
import GF.Text.Pretty
computeLType :: SourceGrammar -> Context -> Type -> Check Type
computeLType gr g0 t = comp (reverse [(b,x, Vr x) | (b,x,_) <- g0] ++ g0) t
where
comp g ty = case ty of
_ | Just _ <- isTypeInts ty -> return ty ---- shouldn't be needed
| isPredefConstant ty -> return ty ---- shouldn't be needed
Q (m,ident) -> checkIn ("module" <+> m) $ do
ty' <- lookupResDef gr (m,ident)
if ty' == ty then return ty else comp g ty' --- is this necessary to test?
AdHocOverload ts -> do
over <- getOverload gr g (Just typeType) t
case over of
Just (tr,_) -> return tr
_ -> checkError ("unresolved overloading of constants" <+> ppTerm Qualified 0 t)
Vr ident -> checkLookup ident g -- never needed to compute!
App f a -> do
f' <- comp g f
a' <- comp g a
case f' of
Abs b x t -> comp ((b,x,a'):g) t
_ -> return $ App f' a'
Prod bt x a b -> do
a' <- comp g a
b' <- comp ((bt,x,Vr x) : g) b
return $ Prod bt x a' b'
Abs bt x b -> do
b' <- comp ((bt,x,Vr x):g) b
return $ Abs bt x b'
Let (x,(_,a)) b -> comp ((Explicit,x,a):g) b
ExtR r s -> do
r' <- comp g r
s' <- comp g s
case (r',s') of
(RecType rs, RecType ss) -> plusRecType r' s' >>= comp g
_ -> return $ ExtR r' s'
RecType fs -> do
let fs' = sortRec fs
liftM RecType $ mapPairsM (comp g) fs'
ELincat c t -> do
t' <- comp g t
lockRecType c t' ---- locking to be removed AR 20/6/2009
_ | ty == typeTok -> return typeStr
_ -> composOp (comp g) ty
-- the underlying algorithms
inferLType :: SourceGrammar -> Context -> Term -> Check (Term, Type)
inferLType gr g trm = case trm of
Q (m,ident) | isPredef m -> termWith trm $ case typPredefined ident of
Just ty -> return ty
Nothing -> checkError ("unknown in Predef:" <+> ident)
Q ident -> checks [
termWith trm $ lookupResType gr ident >>= computeLType gr g
,
lookupResDef gr ident >>= inferLType gr g
,
checkError ("cannot infer type of constant" <+> ppTerm Unqualified 0 trm)
]
QC (m,ident) | isPredef m -> termWith trm $ case typPredefined ident of
Just ty -> return ty
Nothing -> checkError ("unknown in Predef:" <+> ident)
QC ident -> checks [
termWith trm $ lookupResType gr ident >>= computeLType gr g
,
lookupResDef gr ident >>= inferLType gr g
,
checkError ("cannot infer type of canonical constant" <+> ppTerm Unqualified 0 trm)
]
Vr ident -> termWith trm $ checkLookup ident g
Typed e t -> do
t' <- computeLType gr g t
checkLType gr g e t'
AdHocOverload ts -> do
over <- getOverload gr g Nothing trm
case over of
Just trty -> return trty
_ -> checkError ("unresolved overloading of constants" <+> ppTerm Qualified 0 trm)
App f a -> do
over <- getOverload gr g Nothing trm
case over of
Just trty -> return trty
_ -> do
(f',fty) <- inferLType gr g f
fty' <- computeLType gr g fty
case fty' of
Prod bt z arg val -> do
a' <- justCheck g a arg
ty <- if isWildIdent z
then return val
else substituteLType [(bt,z,a')] val
return (App f' a',ty)
_ ->
let term = ppTerm Unqualified 0 f
funName = pp . head . words .render $ term
in checkError ("A function type is expected for" <+> term <+> "instead of type" <+> ppType fty $$
"\n ** Maybe you gave too many arguments to" <+> funName <+> "\n")
S f x -> do
(f', fty) <- inferLType gr g f
case fty of
Table arg val -> do
x'<- justCheck g x arg
return (S f' x', val)
_ -> checkError ("table lintype expected for the table in" $$ nest 2 (ppTerm Unqualified 0 trm))
P t i -> do
(t',ty) <- inferLType gr g t --- ??
ty' <- computeLType gr g ty
let tr2 = P t' i
termWith tr2 $ case ty' of
RecType ts -> case lookup i ts of
Nothing -> checkError ("unknown label" <+> i <+> "in" $$ nest 2 (ppTerm Unqualified 0 ty'))
Just x -> return x
_ -> checkError ("record type expected for:" <+> ppTerm Unqualified 0 t $$
" instead of the inferred:" <+> ppTerm Unqualified 0 ty')
R r -> do
let (ls,fs) = unzip r
fsts <- mapM inferM fs
let ts = [ty | (Just ty,_) <- fsts]
checkCond ("cannot infer type of record" $$ nest 2 (ppTerm Unqualified 0 trm)) (length ts == length fsts)
return $ (R (zip ls fsts), RecType (zip ls ts))
T (TTyped arg) pts -> do
(_,val) <- checks $ map (inferCase (Just arg)) pts
checkLType gr g trm (Table arg val)
T (TComp arg) pts -> do
(_,val) <- checks $ map (inferCase (Just arg)) pts
checkLType gr g trm (Table arg val)
T ti pts -> do -- tries to guess: good in oper type inference
let pts' = [pt | pt@(p,_) <- pts, isConstPatt p]
case pts' of
[] -> checkError ("cannot infer table type of" <+> ppTerm Unqualified 0 trm)
---- PInt k : _ -> return $ Ints $ max [i | PInt i <- pts']
_ -> do
(arg,val) <- checks $ map (inferCase Nothing) pts'
checkLType gr g trm (Table arg val)
V arg pts -> do
(_,val) <- checks $ map (inferLType gr g) pts
-- return (trm, Table arg val) -- old, caused issue 68
checkLType gr g trm (Table arg val)
K s -> do
if elem ' ' s
then do
let ss = foldr C Empty (map K (words s))
----- removed irritating warning AR 24/5/2008
----- checkWarn ("token \"" ++ s ++
----- "\" converted to token list" ++ prt ss)
return (ss, typeStr)
else return (trm, typeStr)
EInt i -> return (trm, typeInt)
EFloat i -> return (trm, typeFloat)
Empty -> return (trm, typeStr)
C s1 s2 ->
check2 (flip (justCheck g) typeStr) C s1 s2 typeStr
Glue s1 s2 ->
check2 (flip (justCheck g) typeStr) Glue s1 s2 typeStr ---- typeTok
---- hack from Rename.identRenameTerm, to live with files with naming conflicts 18/6/2007
Strs (Cn c : ts) | c == cConflict -> do
checkWarn ("unresolved constant, could be any of" <+> hcat (map (ppTerm Unqualified 0) ts))
inferLType gr g (head ts)
Strs ts -> do
ts' <- mapM (\t -> justCheck g t typeStr) ts
return (Strs ts', typeStrs)
Alts t aa -> do
t' <- justCheck g t typeStr
aa' <- flip mapM aa (\ (c,v) -> do
c' <- justCheck g c typeStr
v' <- checks $ map (justCheck g v) [typeStrs, EPattType typeStr]
return (c',v'))
return (Alts t' aa', typeStr)
RecType r -> do
let (ls,ts) = unzip r
ts' <- mapM (flip (justCheck g) typeType) ts
return (RecType (zip ls ts'), typeType)
ExtR r s -> do
--- over <- getOverload gr g Nothing r
--- let r1 = maybe r fst over
let r1 = r ---
(r',rT) <- inferLType gr g r1
rT' <- computeLType gr g rT
(s',sT) <- inferLType gr g s
sT' <- computeLType gr g sT
let trm' = ExtR r' s'
case (rT', sT') of
(RecType rs, RecType ss) -> do
let rt = RecType ([field | field@(l,_) <- rs, notElem l (map fst ss)] ++ ss) -- select types of later fields
checkLType gr g trm' rt ---- return (trm', rt)
_ | rT' == typeType && sT' == typeType -> do
return (trm', typeType)
_ -> checkError ("records or record types expected in" <+> ppTerm Unqualified 0 trm)
Sort _ ->
termWith trm $ return typeType
Prod bt x a b -> do
a' <- justCheck g a typeType
b' <- justCheck ((bt,x,a'):g) b typeType
return (Prod bt x a' b', typeType)
Table p t -> do
p' <- justCheck g p typeType --- check p partype!
t' <- justCheck g t typeType
return $ (Table p' t', typeType)
FV vs -> do
(_,ty) <- checks $ map (inferLType gr g) vs
--- checkIfComplexVariantType trm ty
checkLType gr g trm ty
EPattType ty -> do
ty' <- justCheck g ty typeType
return (EPattType ty',typeType)
EPatt p -> do
ty <- inferPatt p
return (trm, EPattType ty)
ELin c trm -> do
(trm',ty) <- inferLType gr g trm
ty' <- lockRecType c ty ---- lookup c; remove lock AR 20/6/2009
return $ (ELin c trm', ty')
_ -> checkError ("cannot infer lintype of" <+> ppTerm Unqualified 0 trm)
where
isPredef m = elem m [cPredef,cPredefAbs]
justCheck g ty te = checkLType gr g ty te >>= return . fst
-- for record fields, which may be typed
inferM (mty, t) = do
(t', ty') <- case mty of
Just ty -> checkLType gr g t ty
_ -> inferLType gr g t
return (Just ty',t')
inferCase mty (patt,term) = do
arg <- maybe (inferPatt patt) return mty
cont <- pattContext gr g arg patt
(_,val) <- inferLType gr (reverse cont ++ g) term
return (arg,val)
isConstPatt p = case p of
PC _ ps -> True --- all isConstPatt ps
PP _ ps -> True --- all isConstPatt ps
PR ps -> all (isConstPatt . snd) ps
PT _ p -> isConstPatt p
PString _ -> True
PInt _ -> True
PFloat _ -> True
PChar -> True
PChars _ -> True
PSeq p q -> isConstPatt p && isConstPatt q
PAlt p q -> isConstPatt p && isConstPatt q
PRep p -> isConstPatt p
PNeg p -> isConstPatt p
PAs _ p -> isConstPatt p
_ -> False
inferPatt p = case p of
PP (q,c) ps | q /= cPredef -> liftM valTypeCnc (lookupResType gr (q,c))
PAs _ p -> inferPatt p
PNeg p -> inferPatt p
PAlt p q -> checks [inferPatt p, inferPatt q]
PSeq _ _ -> return $ typeStr
PRep _ -> return $ typeStr
PChar -> return $ typeStr
PChars _ -> return $ typeStr
_ -> inferLType gr g (patt2term p) >>= return . snd
-- type inference: Nothing, type checking: Just t
-- the latter permits matching with value type
getOverload :: SourceGrammar -> Context -> Maybe Type -> Term -> Check (Maybe (Term,Type))
getOverload gr g mt ot = case appForm ot of
(f@(Q c), ts) -> case lookupOverload gr c of
Ok typs -> do
ttys <- mapM (inferLType gr g) ts
v <- matchOverload f typs ttys
return $ Just v
_ -> return Nothing
(AdHocOverload cs@(f:_), ts) -> do --- the function name f is only used in error messages
let typs = concatMap collectOverloads cs
ttys <- mapM (inferLType gr g) ts
v <- matchOverload f typs ttys
return $ Just v
_ -> return Nothing
where
collectOverloads tr@(Q c) = case lookupOverload gr c of
Ok typs -> typs
_ -> case lookupResType gr c of
Ok ty -> let (args,val) = typeFormCnc ty in [(map (\(b,x,t) -> t) args,(val,tr))]
_ -> []
collectOverloads _ = [] --- constructors QC
matchOverload f typs ttys = do
let (tts,tys) = unzip ttys
let vfs = lookupOverloadInstance tys typs
let matches = [vf | vf@((_,v,_),_) <- vfs, matchVal mt v]
let showTypes ty = hsep (map ppType ty)
let (stys,styps) = (showTypes tys, [showTypes ty | (ty,_) <- typs])
-- to avoid strange error msg e.g. in case of unmatch record extension, show whole types if needed AR 28/1/2013
let (stysError,stypsError) = if elem (render stys) (map render styps)
then (hsep (map (ppTerm Unqualified 0) tys), [hsep (map (ppTerm Unqualified 0) ty) | (ty,_) <- typs])
else (stys,styps)
case ([vf | (vf,True) <- matches],[vf | (vf,False) <- matches]) of
([(_,val,fun)],_) -> return (mkApp fun tts, val)
([],[(pre,val,fun)]) -> do
checkWarn $ "ignoring lock fields in resolving" <+> ppTerm Unqualified 0 ot $$
"for" $$
nest 2 (showTypes tys) $$
"using" $$
nest 2 (showTypes pre)
return (mkApp fun tts, val)
([],[]) -> do
checkError $ "no overload instance of" <+> ppTerm Qualified 0 f $$
maybe empty (\x -> "with value type" <+> ppType x) mt $$
"for argument list" $$
nest 2 stysError $$
"among alternatives" $$
nest 2 (vcat stypsError)
(vfs1,vfs2) -> case (noProds vfs1,noProds vfs2) of
([(val,fun)],_) -> do
return (mkApp fun tts, val)
([],[(val,fun)]) -> do
checkWarn ("ignoring lock fields in resolving" <+> ppTerm Unqualified 0 ot)
return (mkApp fun tts, val)
----- unsafely exclude irritating warning AR 24/5/2008
----- checkWarn $ "overloading of" +++ prt f +++
----- "resolved by excluding partial applications:" ++++
----- unlines [prtType env ty | (ty,_) <- vfs', not (noProd ty)]
--- now forgiving ambiguity with a warning AR 1/2/2014
-- This gives ad hoc overloading the same behaviour as the choice of the first match in renaming did before.
-- But it also gives a chance to ambiguous overloadings that were banned before.
(nps1,nps2) -> do
checkWarn $ "ambiguous overloading of" <+> ppTerm Unqualified 0 f <+>
---- "with argument types" <+> hsep (map (ppTerm Qualified 0) tys) $$
"resolved by selecting the first of the alternatives" $$
nest 2 (vcat [ppTerm Qualified 0 fun | (_,ty,fun) <- vfs1 ++ if null vfs1 then vfs2 else []])
case [(mkApp fun tts,val) | (val,fun) <- nps1 ++ nps2] of
[] -> checkError $ "no alternatives left when resolving" <+> ppTerm Unqualified 0 f
h:_ -> return h
matchVal mt v = elem mt [Nothing,Just v,Just (unlocked v)]
unlocked v = case v of
RecType fs -> RecType $ filter (not . isLockLabel . fst) (sortRec fs)
_ -> v
---- TODO: accept subtypes
---- TODO: use a trie
lookupOverloadInstance tys typs =
[((pre,mkFunType rest val, t),isExact) |
let lt = length tys,
(ty,(val,t)) <- typs, length ty >= lt,
let (pre,rest) = splitAt lt ty,
let isExact = pre == tys,
isExact || map unlocked pre == map unlocked tys
]
noProds vfs = [(v,f) | (_,v,f) <- vfs, noProd v]
noProd ty = case ty of
Prod _ _ _ _ -> False
_ -> True
checkLType :: SourceGrammar -> Context -> Term -> Type -> Check (Term, Type)
checkLType gr g trm typ0 = do
typ <- computeLType gr g typ0
case trm of
Abs bt x c -> do
case typ of
Prod bt' z a b -> do
(c',b') <- if isWildIdent z
then checkLType gr ((bt,x,a):g) c b
else do b' <- checkIn (pp "abs") $ substituteLType [(bt',z,Vr x)] b
checkLType gr ((bt,x,a):g) c b'
return $ (Abs bt x c', Prod bt' z a b')
_ -> checkError $ "function type expected instead of" <+> ppType typ $$
"\n ** Double-check that the type signature of the operation" $$
"matches the number of arguments given to it.\n"
App f a -> do
over <- getOverload gr g (Just typ) trm
case over of
Just trty -> return trty
_ -> do
(trm',ty') <- inferLType gr g trm
termWith trm' $ checkEqLType gr g typ ty' trm'
AdHocOverload ts -> do
over <- getOverload gr g Nothing trm
case over of
Just trty -> return trty
_ -> checkError ("unresolved overloading of constants" <+> ppTerm Qualified 0 trm)
Q _ -> do
over <- getOverload gr g (Just typ) trm
case over of
Just trty -> return trty
_ -> do
(trm',ty') <- inferLType gr g trm
termWith trm' $ checkEqLType gr g typ ty' trm'
T _ [] ->
checkError ("found empty table in type" <+> ppTerm Unqualified 0 typ)
T _ cs -> case typ of
Table arg val -> do
case allParamValues gr arg of
Ok vs -> do
let ps0 = map fst cs
ps <- testOvershadow ps0 vs
if null ps
then return ()
else checkWarn ("patterns never reached:" $$
nest 2 (vcat (map (ppPatt Unqualified 0) ps)))
_ -> return () -- happens with variable types
cs' <- mapM (checkCase arg val) cs
return (T (TTyped arg) cs', typ)
_ -> checkError $ "table type expected for table instead of" $$ nest 2 (ppType typ)
V arg0 vs ->
case typ of
Table arg1 val ->
do arg' <- checkEqLType gr g arg0 arg1 trm
vs1 <- allParamValues gr arg1
if length vs1 == length vs
then return ()
else checkError $ "wrong number of values in table" <+> ppTerm Unqualified 0 trm
vs' <- map fst `fmap` sequence [checkLType gr g v val|v<-vs]
return (V arg' vs',typ)
R r -> case typ of --- why needed? because inference may be too difficult
RecType rr -> do
--let (ls,_) = unzip rr -- labels of expected type
fsts <- mapM (checkM r) rr -- check that they are found in the record
return $ (R fsts, typ) -- normalize record
_ -> checkError ("record type expected in type checking instead of" $$ nest 2 (ppTerm Unqualified 0 typ))
ExtR r s -> case typ of
_ | typ == typeType -> do
trm' <- computeLType gr g trm
case trm' of
RecType _ -> termWith trm' $ return typeType
ExtR (Vr _) (RecType _) -> termWith trm' $ return typeType
-- ext t = t ** ...
_ -> checkError ("invalid record type extension" <+> nest 2 (ppTerm Unqualified 0 trm))
RecType rr -> do
ll2 <- case s of
R ss -> return $ map fst ss
_ -> do
(s',typ2) <- inferLType gr g s
case typ2 of
RecType ss -> return $ map fst ss
_ -> checkError ("cannot get labels from" $$ nest 2 (ppTerm Unqualified 0 typ2))
let ll1 = [l | (l,_) <- rr, notElem l ll2]
--- over <- getOverload gr g Nothing r --- this would solve #66 but fail ParadigmsAra. AR 6/7/2020
--- let r1 = maybe r fst over
let r1 = r ---
(r',_) <- checkLType gr g r1 (RecType [field | field@(l,_) <- rr, elem l ll1])
(s',_) <- checkLType gr g s (RecType [field | field@(l,_) <- rr, elem l ll2])
let rec = R ([(l,(Nothing,P r' l)) | l <- ll1] ++ [(l,(Nothing,P s' l)) | l <- ll2])
return (rec, typ)
ExtR ty ex -> do
r' <- justCheck g r ty
s' <- justCheck g s ex
return $ (ExtR r' s', typ) --- is this all? it assumes the same division in trm and typ
_ -> checkError ("record extension not meaningful for" <+> ppTerm Unqualified 0 typ)
FV vs -> do
ttys <- mapM (flip (checkLType gr g) typ) vs
--- checkIfComplexVariantType trm typ
return (FV (map fst ttys), typ) --- typ' ?
S tab arg -> checks [ do
(tab',ty) <- inferLType gr g tab
ty' <- computeLType gr g ty
case ty' of
Table p t -> do
(arg',val) <- checkLType gr g arg p
checkEqLType gr g typ t trm
return (S tab' arg', t)
_ -> checkError ("table type expected for applied table instead of" <+> ppType ty')
, do
(arg',ty) <- inferLType gr g arg
ty' <- computeLType gr g ty
(tab',_) <- checkLType gr g tab (Table ty' typ)
return (S tab' arg', typ)
]
Let (x,(mty,def)) body -> case mty of
Just ty -> do
(ty0,_) <- checkLType gr g ty typeType
(def',ty') <- checkLType gr g def ty0
body' <- justCheck ((Explicit,x,ty'):g) body typ
return (Let (x,(Just ty',def')) body', typ)
_ -> do
(def',ty) <- inferLType gr g def -- tries to infer type of local constant
checkLType gr g (Let (x,(Just ty,def')) body) typ
ELin c tr -> do
tr1 <- unlockRecord c tr
checkLType gr g tr1 typ
_ -> do
(trm',ty') <- inferLType gr g trm
termWith trm' $ checkEqLType gr g typ ty' trm'
where
justCheck g ty te = checkLType gr g ty te >>= return . fst
{-
recParts rr t = (RecType rr1,RecType rr2) where
(rr1,rr2) = partition (flip elem (map fst t) . fst) rr
-}
checkM rms (l,ty) = case lookup l rms of
Just (Just ty0,t) -> do
checkEqLType gr g ty ty0 t
(t',ty') <- checkLType gr g t ty
return (l,(Just ty',t'))
Just (_,t) -> do
(t',ty') <- checkLType gr g t ty
return (l,(Just ty',t'))
_ -> checkError $
if isLockLabel l
then let cat = drop 5 (showIdent (label2ident l))
in ppTerm Unqualified 0 (R rms) <+> "is not in the lincat of" <+> cat <>
"; try wrapping it with lin" <+> cat
else "cannot find value for label" <+> l <+> "in" <+> ppTerm Unqualified 0 (R rms)
checkCase arg val (p,t) = do
cont <- pattContext gr g arg p
t' <- justCheck (reverse cont ++ g) t val
return (p,t')
pattContext :: SourceGrammar -> Context -> Type -> Patt -> Check Context
pattContext env g typ p = case p of
PV x -> return [(Explicit,x,typ)]
PP (q,c) ps | q /= cPredef -> do ---- why this /=? AR 6/1/2006
t <- lookupResType env (q,c)
let (cont,v) = typeFormCnc t
checkCond ("wrong number of arguments for constructor in" <+> ppPatt Unqualified 0 p)
(length cont == length ps)
checkEqLType env g typ v (patt2term p)
mapM (\((_,_,ty),p) -> pattContext env g ty p) (zip cont ps) >>= return . concat
PR r -> do
typ' <- computeLType env g typ
case typ' of
RecType t -> do
let pts = [(ty,tr) | (l,tr) <- r, Just ty <- [lookup l t]]
----- checkWarn $ prt p ++++ show pts ----- debug
mapM (uncurry (pattContext env g)) pts >>= return . concat
_ -> checkError ("record type expected for pattern instead of" <+> ppTerm Unqualified 0 typ')
PT t p' -> do
checkEqLType env g typ t (patt2term p')
pattContext env g typ p'
PAs x p -> do
g' <- pattContext env g typ p
return ((Explicit,x,typ):g')
PAlt p' q -> do
g1 <- pattContext env g typ p'
g2 <- pattContext env g typ q
let pts = nub ([x | pt@(_,x,_) <- g1, notElem pt g2] ++ [x | pt@(_,x,_) <- g2, notElem pt g1])
checkCond
("incompatible bindings of" <+>
fsep pts <+>
"in pattern alterantives" <+> ppPatt Unqualified 0 p) (null pts)
return g1 -- must be g1 == g2
PSeq p q -> do
g1 <- pattContext env g typ p
g2 <- pattContext env g typ q
return $ g1 ++ g2
PRep p' -> noBind typeStr p'
PNeg p' -> noBind typ p'
_ -> return [] ---- check types!
where
noBind typ p' = do
co <- pattContext env g typ p'
if not (null co)
then checkWarn ("no variable bound inside pattern" <+> ppPatt Unqualified 0 p)
>> return []
else return []
checkEqLType :: SourceGrammar -> Context -> Type -> Type -> Term -> Check Type
checkEqLType gr g t u trm = do
(b,t',u',s) <- checkIfEqLType gr g t u trm
case b of
True -> return t'
False ->
let inferredType = ppTerm Qualified 0 u
expectedType = ppTerm Qualified 0 t
term = ppTerm Unqualified 0 trm
funName = pp . head . words .render $ term
helpfulMsg =
case (arrows inferredType, arrows expectedType) of
(0,0) -> pp "" -- None of the types is a function
_ -> "\n **" <+>
if expectedType `isLessApplied` inferredType
then "Maybe you gave too few arguments to" <+> funName
else pp "Double-check that type signature and number of arguments match."
in checkError $ s <+> "type of" <+> term $$
"expected:" <+> expectedType $$ -- ppqType t u $$
"inferred:" <+> inferredType $$ -- ppqType u t
helpfulMsg
where
-- count the number of arrows in the prettyprinted term
arrows :: Doc -> Int
arrows = length . filter (=="->") . words . render
-- If prettyprinted type t has fewer arrows then prettyprinted type u,
-- then t is "less applied", and we can print out more helpful error msg.
isLessApplied :: Doc -> Doc -> Bool
isLessApplied t u = arrows t < arrows u
checkIfEqLType :: SourceGrammar -> Context -> Type -> Type -> Term -> Check (Bool,Type,Type,String)
checkIfEqLType gr g t u trm = do
t' <- computeLType gr g t
u' <- computeLType gr g u
case t' == u' || alpha [] t' u' of
True -> return (True,t',u',[])
-- forgive missing lock fields by only generating a warning.
--- better: use a flag to forgive? (AR 31/1/2006)
_ -> case missingLock [] t' u' of
Ok lo -> do
checkWarn $ "missing lock field" <+> fsep lo
return (True,t',u',[])
Bad s -> return (False,t',u',s)
where
-- check that u is a subtype of t
--- quick hack version of TC.eqVal
alpha g t u = case (t,u) of
-- error (the empty type!) is subtype of any other type
(_,u) | u == typeError -> True
-- contravariance
(Prod _ x a b, Prod _ y c d) -> alpha g c a && alpha ((x,y):g) b d
-- record subtyping
(RecType rs, RecType ts) -> all (\ (l,a) ->
any (\ (k,b) -> l == k && alpha g a b) ts) rs
(ExtR r s, ExtR r' s') -> alpha g r r' && alpha g s s'
(ExtR r s, t) -> alpha g r t || alpha g s t
-- the following say that Ints n is a subset of Int and of Ints m >= n
-- But why does it also allow Int as a subtype of Ints m? /TH 2014-04-04
(t,u) | Just m <- isTypeInts t, Just n <- isTypeInts u -> m >= n
| Just _ <- isTypeInts t, u == typeInt -> True ---- check size!
| t == typeInt, Just _ <- isTypeInts u -> True ---- why this ???? AR 11/12/2005
---- this should be made in Rename
(Q (m,a), Q (n,b)) | a == b -> elem m (allExtendsPlus gr n)
|| elem n (allExtendsPlus gr m)
|| m == n --- for Predef
(QC (m,a), QC (n,b)) | a == b -> elem m (allExtendsPlus gr n)
|| elem n (allExtendsPlus gr m)
(QC (m,a), Q (n,b)) | a == b -> elem m (allExtendsPlus gr n)
|| elem n (allExtendsPlus gr m)
(Q (m,a), QC (n,b)) | a == b -> elem m (allExtendsPlus gr n)
|| elem n (allExtendsPlus gr m)
-- contravariance
(Table a b, Table c d) -> alpha g c a && alpha g b d
(Vr x, Vr y) -> x == y || elem (x,y) g || elem (y,x) g
_ -> t == u
--- the following should be one-way coercions only. AR 4/1/2001
|| elem t sTypes && elem u sTypes
|| (t == typeType && u == typePType)
|| (u == typeType && t == typePType)
missingLock g t u = case (t,u) of
(RecType rs, RecType ts) ->
let
ls = [l | (l,a) <- rs,
not (any (\ (k,b) -> alpha g a b && l == k) ts)]
(locks,others) = partition isLockLabel ls
in case others of
_:_ -> Bad $ render ("missing record fields:" <+> fsep (punctuate ',' (others)))
_ -> return locks
-- contravariance
(Prod _ x a b, Prod _ y c d) -> do
ls1 <- missingLock g c a
ls2 <- missingLock g b d
return $ ls1 ++ ls2
_ -> Bad ""
sTypes = [typeStr, typeTok, typeString]
-- auxiliaries
-- | light-weight substitution for dep. types
substituteLType :: Context -> Type -> Check Type
substituteLType g t = case t of
Vr x -> return $ maybe t id $ lookup x [(x,t) | (_,x,t) <- g]
_ -> composOp (substituteLType g) t
termWith :: Term -> Check Type -> Check (Term, Type)
termWith t ct = do
ty <- ct
return (t,ty)
-- | compositional check\/infer of binary operations
check2 :: (Term -> Check Term) -> (Term -> Term -> Term) ->
Term -> Term -> Type -> Check (Term,Type)
check2 chk con a b t = do
a' <- chk a
b' <- chk b
return (con a' b', t)
-- printing a type with a lock field lock_C as C
ppType :: Type -> Doc
ppType ty =
case ty of
RecType fs -> case filter isLockLabel $ map fst fs of
[lock] -> pp (drop 5 (showIdent (label2ident lock)))
_ -> ppTerm Unqualified 0 ty
Prod _ x a b -> ppType a <+> "->" <+> ppType b
_ -> ppTerm Unqualified 0 ty
{-
ppqType :: Type -> Type -> Doc
ppqType t u = case (ppType t, ppType u) of
(pt,pu) | render pt == render pu -> ppTerm Qualified 0 t
(pt,_) -> pt
-}
checkLookup :: Ident -> Context -> Check Type
checkLookup x g =
case [ty | (b,y,ty) <- g, x == y] of
[] -> checkError ("unknown variable" <+> x)
(ty:_) -> return ty

View File

@@ -1,802 +0,0 @@
{-# LANGUAGE CPP #-}
module GF.Compile.TypeCheck.ConcreteNew( checkLType, inferLType ) where
-- The code here is based on the paper:
-- Simon Peyton Jones, Dimitrios Vytiniotis, Stephanie Weirich.
-- Practical type inference for arbitrary-rank types.
-- 14 September 2011
import GF.Grammar hiding (Env, VGen, VApp, VRecType)
import GF.Grammar.Lookup
import GF.Grammar.Predef
import GF.Grammar.Lockfield
import GF.Compile.Compute.Concrete
import GF.Compile.Compute.Predef(predef,predefName)
import GF.Infra.CheckM
import GF.Data.Operations
import Control.Applicative(Applicative(..))
import Control.Monad(ap,liftM,mplus)
import GF.Text.Pretty
import Data.List (nub, (\\), tails)
import qualified Data.IntMap as IntMap
import Data.Maybe(fromMaybe,isNothing)
import qualified Control.Monad.Fail as Fail
checkLType :: GlobalEnv -> Term -> Type -> Check (Term, Type)
checkLType ge t ty = runTcM $ do
vty <- liftErr (eval ge [] ty)
(t,_) <- tcRho ge [] t (Just vty)
t <- zonkTerm t
return (t,ty)
inferLType :: GlobalEnv -> Term -> Check (Term, Type)
inferLType ge t = runTcM $ do
(t,ty) <- inferSigma ge [] t
t <- zonkTerm t
ty <- zonkTerm =<< tc_value2term (geLoc ge) [] ty
return (t,ty)
inferSigma :: GlobalEnv -> Scope -> Term -> TcM (Term,Sigma)
inferSigma ge scope t = do -- GEN1
(t,ty) <- tcRho ge scope t Nothing
env_tvs <- getMetaVars (geLoc ge) (scopeTypes scope)
res_tvs <- getMetaVars (geLoc ge) [(scope,ty)]
let forall_tvs = res_tvs \\ env_tvs
quantify ge scope t forall_tvs ty
Just vtypeInt = fmap (flip VApp []) (predef cInt)
Just vtypeFloat = fmap (flip VApp []) (predef cFloat)
Just vtypeInts = fmap (\p i -> VApp p [VInt i]) (predef cInts)
vtypeStr = VSort cStr
vtypeStrs = VSort cStrs
vtypeType = VSort cType
vtypePType = VSort cPType
tcRho :: GlobalEnv -> Scope -> Term -> Maybe Rho -> TcM (Term, Rho)
tcRho ge scope t@(EInt i) mb_ty = instSigma ge scope t (vtypeInts i) mb_ty -- INT
tcRho ge scope t@(EFloat _) mb_ty = instSigma ge scope t vtypeFloat mb_ty -- FLOAT
tcRho ge scope t@(K _) mb_ty = instSigma ge scope t vtypeStr mb_ty -- STR
tcRho ge scope t@(Empty) mb_ty = instSigma ge scope t vtypeStr mb_ty
tcRho ge scope t@(Vr v) mb_ty = do -- VAR
case lookup v scope of
Just v_sigma -> instSigma ge scope t v_sigma mb_ty
Nothing -> tcError ("Unknown variable" <+> v)
tcRho ge scope t@(Q id) mb_ty =
runTcA (tcOverloadFailed t) $
tcApp ge scope t `bindTcA` \(t,ty) ->
instSigma ge scope t ty mb_ty
tcRho ge scope t@(QC id) mb_ty =
runTcA (tcOverloadFailed t) $
tcApp ge scope t `bindTcA` \(t,ty) ->
instSigma ge scope t ty mb_ty
tcRho ge scope t@(App fun arg) mb_ty = do
runTcA (tcOverloadFailed t) $
tcApp ge scope t `bindTcA` \(t,ty) ->
instSigma ge scope t ty mb_ty
tcRho ge scope (Abs bt var body) Nothing = do -- ABS1
i <- newMeta scope vtypeType
let arg_ty = VMeta i (scopeEnv scope) []
(body,body_ty) <- tcRho ge ((var,arg_ty):scope) body Nothing
return (Abs bt var body, (VProd bt arg_ty identW (Bind (const body_ty))))
tcRho ge scope t@(Abs Implicit var body) (Just ty) = do -- ABS2
(bt, var_ty, body_ty) <- unifyFun ge scope ty
if bt == Implicit
then return ()
else tcError (ppTerm Unqualified 0 t <+> "is an implicit function, but no implicit function is expected")
(body, body_ty) <- tcRho ge ((var,var_ty):scope) body (Just (body_ty (VGen (length scope) [])))
return (Abs Implicit var body,ty)
tcRho ge scope (Abs Explicit var body) (Just ty) = do -- ABS3
(scope,f,ty') <- skolemise ge scope ty
(_,var_ty,body_ty) <- unifyFun ge scope ty'
(body, body_ty) <- tcRho ge ((var,var_ty):scope) body (Just (body_ty (VGen (length scope) [])))
return (f (Abs Explicit var body),ty)
tcRho ge scope (Let (var, (mb_ann_ty, rhs)) body) mb_ty = do -- LET
(rhs,var_ty) <- case mb_ann_ty of
Nothing -> inferSigma ge scope rhs
Just ann_ty -> do (ann_ty, _) <- tcRho ge scope ann_ty (Just vtypeType)
v_ann_ty <- liftErr (eval ge (scopeEnv scope) ann_ty)
(rhs,_) <- tcRho ge scope rhs (Just v_ann_ty)
return (rhs, v_ann_ty)
(body, body_ty) <- tcRho ge ((var,var_ty):scope) body mb_ty
var_ty <- tc_value2term (geLoc ge) (scopeVars scope) var_ty
return (Let (var, (Just var_ty, rhs)) body, body_ty)
tcRho ge scope (Typed body ann_ty) mb_ty = do -- ANNOT
(ann_ty, _) <- tcRho ge scope ann_ty (Just vtypeType)
v_ann_ty <- liftErr (eval ge (scopeEnv scope) ann_ty)
(body,_) <- tcRho ge scope body (Just v_ann_ty)
instSigma ge scope (Typed body ann_ty) v_ann_ty mb_ty
tcRho ge scope (FV ts) mb_ty = do
case ts of
[] -> do i <- newMeta scope vtypeType
instSigma ge scope (FV []) (VMeta i (scopeEnv scope) []) mb_ty
(t:ts) -> do (t,ty) <- tcRho ge scope t mb_ty
let go [] ty = return ([],ty)
go (t:ts) ty = do (t, ty) <- tcRho ge scope t (Just ty)
(ts,ty) <- go ts ty
return (t:ts,ty)
(ts,ty) <- go ts ty
return (FV (t:ts), ty)
tcRho ge scope t@(Sort s) mb_ty = do
instSigma ge scope t vtypeType mb_ty
tcRho ge scope t@(RecType rs) Nothing = do
(rs,mb_ty) <- tcRecTypeFields ge scope rs Nothing
return (RecType rs,fromMaybe vtypePType mb_ty)
tcRho ge scope t@(RecType rs) (Just ty) = do
(scope,f,ty') <- skolemise ge scope ty
case ty' of
VSort s
| s == cType -> return ()
| s == cPType -> return ()
VMeta i env vs -> case rs of
[] -> unifyVar ge scope i env vs vtypePType
_ -> return ()
ty -> do ty <- zonkTerm =<< tc_value2term (geLoc ge) (scopeVars scope) ty
tcError ("The record type" <+> ppTerm Unqualified 0 t $$
"cannot be of type" <+> ppTerm Unqualified 0 ty)
(rs,mb_ty) <- tcRecTypeFields ge scope rs (Just ty')
return (f (RecType rs),ty)
tcRho ge scope t@(Table p res) mb_ty = do
(p, p_ty) <- tcRho ge scope p (Just vtypePType)
(res,res_ty) <- tcRho ge scope res (Just vtypeType)
instSigma ge scope (Table p res) vtypeType mb_ty
tcRho ge scope (Prod bt x ty1 ty2) mb_ty = do
(ty1,ty1_ty) <- tcRho ge scope ty1 (Just vtypeType)
vty1 <- liftErr (eval ge (scopeEnv scope) ty1)
(ty2,ty2_ty) <- tcRho ge ((x,vty1):scope) ty2 (Just vtypeType)
instSigma ge scope (Prod bt x ty1 ty2) vtypeType mb_ty
tcRho ge scope (S t p) mb_ty = do
p_ty <- fmap (\i -> VMeta i (scopeEnv scope) []) $ newMeta scope vtypePType
res_ty <- case mb_ty of
Nothing -> fmap (\i -> VMeta i (scopeEnv scope) []) $ newMeta scope vtypeType
Just ty -> return ty
let t_ty = VTblType p_ty res_ty
(t,t_ty) <- tcRho ge scope t (Just t_ty)
(p,_) <- tcRho ge scope p (Just p_ty)
return (S t p, res_ty)
tcRho ge scope (T tt ps) Nothing = do -- ABS1/AABS1 for tables
p_ty <- case tt of
TRaw -> fmap (\i -> VMeta i (scopeEnv scope) []) $ newMeta scope vtypePType
TTyped ty -> do (ty, _) <- tcRho ge scope ty (Just vtypeType)
liftErr (eval ge (scopeEnv scope) ty)
(ps,mb_res_ty) <- tcCases ge scope ps p_ty Nothing
res_ty <- case mb_res_ty of
Just res_ty -> return res_ty
Nothing -> fmap (\i -> VMeta i (scopeEnv scope) []) $ newMeta scope vtypeType
p_ty_t <- tc_value2term (geLoc ge) [] p_ty
return (T (TTyped p_ty_t) ps, VTblType p_ty res_ty)
tcRho ge scope (T tt ps) (Just ty) = do -- ABS2/AABS2 for tables
(scope,f,ty') <- skolemise ge scope ty
(p_ty, res_ty) <- unifyTbl ge scope ty'
case tt of
TRaw -> return ()
TTyped ty -> do (ty, _) <- tcRho ge scope ty (Just vtypeType)
return ()--subsCheckRho ge scope -> Term ty res_ty
(ps,Just res_ty) <- tcCases ge scope ps p_ty (Just res_ty)
p_ty_t <- tc_value2term (geLoc ge) [] p_ty
return (f (T (TTyped p_ty_t) ps), VTblType p_ty res_ty)
tcRho ge scope (R rs) Nothing = do
lttys <- inferRecFields ge scope rs
rs <- mapM (\(l,t,ty) -> tc_value2term (geLoc ge) (scopeVars scope) ty >>= \ty -> return (l, (Just ty, t))) lttys
return (R rs,
VRecType [(l, ty) | (l,t,ty) <- lttys]
)
tcRho ge scope (R rs) (Just ty) = do
(scope,f,ty') <- skolemise ge scope ty
case ty' of
(VRecType ltys) -> do lttys <- checkRecFields ge scope rs ltys
rs <- mapM (\(l,t,ty) -> tc_value2term (geLoc ge) (scopeVars scope) ty >>= \ty -> return (l, (Just ty, t))) lttys
return ((f . R) rs,
VRecType [(l, ty) | (l,t,ty) <- lttys]
)
ty -> do lttys <- inferRecFields ge scope rs
t <- liftM (f . R) (mapM (\(l,t,ty) -> tc_value2term (geLoc ge) (scopeVars scope) ty >>= \ty -> return (l, (Just ty, t))) lttys)
let ty' = VRecType [(l, ty) | (l,t,ty) <- lttys]
t <- subsCheckRho ge scope t ty' ty
return (t, ty')
tcRho ge scope (P t l) mb_ty = do
l_ty <- case mb_ty of
Just ty -> return ty
Nothing -> do i <- newMeta scope vtypeType
return (VMeta i (scopeEnv scope) [])
(t,t_ty) <- tcRho ge scope t (Just (VRecType [(l,l_ty)]))
return (P t l,l_ty)
tcRho ge scope (C t1 t2) mb_ty = do
(t1,t1_ty) <- tcRho ge scope t1 (Just vtypeStr)
(t2,t2_ty) <- tcRho ge scope t2 (Just vtypeStr)
instSigma ge scope (C t1 t2) vtypeStr mb_ty
tcRho ge scope (Glue t1 t2) mb_ty = do
(t1,t1_ty) <- tcRho ge scope t1 (Just vtypeStr)
(t2,t2_ty) <- tcRho ge scope t2 (Just vtypeStr)
instSigma ge scope (Glue t1 t2) vtypeStr mb_ty
tcRho ge scope t@(ExtR t1 t2) mb_ty = do
(t1,t1_ty) <- tcRho ge scope t1 Nothing
(t2,t2_ty) <- tcRho ge scope t2 Nothing
case (t1_ty,t2_ty) of
(VSort s1,VSort s2)
| (s1 == cType || s1 == cPType) &&
(s2 == cType || s2 == cPType) -> let sort | s1 == cPType && s2 == cPType = cPType
| otherwise = cType
in instSigma ge scope (ExtR t1 t2) (VSort sort) mb_ty
(VRecType rs1, VRecType rs2) -> instSigma ge scope (ExtR t1 t2) (VRecType (rs2++rs1)) mb_ty
_ -> tcError ("Cannot type check" <+> ppTerm Unqualified 0 t)
tcRho ge scope (ELin cat t) mb_ty = do -- this could be done earlier, i.e. in the parser
tcRho ge scope (ExtR t (R [(lockLabel cat,(Just (RecType []),R []))])) mb_ty
tcRho ge scope (ELincat cat t) mb_ty = do -- this could be done earlier, i.e. in the parser
tcRho ge scope (ExtR t (RecType [(lockLabel cat,RecType [])])) mb_ty
tcRho ge scope (Alts t ss) mb_ty = do
(t,_) <- tcRho ge scope t (Just vtypeStr)
ss <- flip mapM ss $ \(t1,t2) -> do
(t1,_) <- tcRho ge scope t1 (Just vtypeStr)
(t2,_) <- tcRho ge scope t2 (Just vtypeStrs)
return (t1,t2)
instSigma ge scope (Alts t ss) vtypeStr mb_ty
tcRho ge scope (Strs ss) mb_ty = do
ss <- flip mapM ss $ \t -> do
(t,_) <- tcRho ge scope t (Just vtypeStr)
return t
instSigma ge scope (Strs ss) vtypeStrs mb_ty
tcRho ge scope (EPattType ty) mb_ty = do
(ty, _) <- tcRho ge scope ty (Just vtypeType)
instSigma ge scope (EPattType ty) vtypeType mb_ty
tcRho ge scope t@(EPatt p) mb_ty = do
(scope,f,ty) <- case mb_ty of
Nothing -> do i <- newMeta scope vtypeType
return (scope,id,VMeta i (scopeEnv scope) [])
Just ty -> do (scope,f,ty) <- skolemise ge scope ty
case ty of
VPattType ty -> return (scope,f,ty)
_ -> tcError (ppTerm Unqualified 0 t <+> "must be of pattern type but" <+> ppTerm Unqualified 0 t <+> "is expected")
tcPatt ge scope p ty
return (f (EPatt p), ty)
tcRho gr scope t _ = unimplemented ("tcRho "++show t)
tcCases ge scope [] p_ty mb_res_ty = return ([],mb_res_ty)
tcCases ge scope ((p,t):cs) p_ty mb_res_ty = do
scope' <- tcPatt ge scope p p_ty
(t,res_ty) <- tcRho ge scope' t mb_res_ty
(cs,mb_res_ty) <- tcCases ge scope cs p_ty (Just res_ty)
return ((p,t):cs,mb_res_ty)
tcApp ge scope t@(App fun (ImplArg arg)) = do -- APP1
tcApp ge scope fun `bindTcA` \(fun,fun_ty) ->
do (bt, arg_ty, res_ty) <- unifyFun ge scope fun_ty
if (bt == Implicit)
then return ()
else tcError (ppTerm Unqualified 0 t <+> "is an implicit argument application, but no implicit argument is expected")
(arg,_) <- tcRho ge scope arg (Just arg_ty)
varg <- liftErr (eval ge (scopeEnv scope) arg)
return (App fun (ImplArg arg), res_ty varg)
tcApp ge scope (App fun arg) = -- APP2
tcApp ge scope fun `bindTcA` \(fun,fun_ty) ->
do (fun,fun_ty) <- instantiate scope fun fun_ty
(_, arg_ty, res_ty) <- unifyFun ge scope fun_ty
(arg,_) <- tcRho ge scope arg (Just arg_ty)
varg <- liftErr (eval ge (scopeEnv scope) arg)
return (App fun arg, res_ty varg)
tcApp ge scope (Q id) = -- VAR (global)
mkTcA (lookupOverloadTypes (geGrammar ge) id) `bindTcA` \(t,ty) ->
do ty <- liftErr (eval ge [] ty)
return (t,ty)
tcApp ge scope (QC id) = -- VAR (global)
mkTcA (lookupOverloadTypes (geGrammar ge) id) `bindTcA` \(t,ty) ->
do ty <- liftErr (eval ge [] ty)
return (t,ty)
tcApp ge scope t =
singleTcA (tcRho ge scope t Nothing)
tcOverloadFailed t ttys =
tcError ("Overload resolution failed" $$
"of term " <+> pp t $$
"with types" <+> vcat [ppTerm Terse 0 ty | (_,ty) <- ttys])
tcPatt ge scope PW ty0 =
return scope
tcPatt ge scope (PV x) ty0 =
return ((x,ty0):scope)
tcPatt ge scope (PP c ps) ty0 =
case lookupResType (geGrammar ge) c of
Ok ty -> do let go scope ty [] = return (scope,ty)
go scope ty (p:ps) = do (_,arg_ty,res_ty) <- unifyFun ge scope ty
scope <- tcPatt ge scope p arg_ty
go scope (res_ty (VGen (length scope) [])) ps
vty <- liftErr (eval ge [] ty)
(scope,ty) <- go scope vty ps
unify ge scope ty0 ty
return scope
Bad err -> tcError (pp err)
tcPatt ge scope (PInt i) ty0 = do
subsCheckRho ge scope (EInt i) (vtypeInts i) ty0
return scope
tcPatt ge scope (PString s) ty0 = do
unify ge scope ty0 vtypeStr
return scope
tcPatt ge scope PChar ty0 = do
unify ge scope ty0 vtypeStr
return scope
tcPatt ge scope (PSeq p1 p2) ty0 = do
unify ge scope ty0 vtypeStr
scope <- tcPatt ge scope p1 vtypeStr
scope <- tcPatt ge scope p2 vtypeStr
return scope
tcPatt ge scope (PAs x p) ty0 = do
tcPatt ge ((x,ty0):scope) p ty0
tcPatt ge scope (PR rs) ty0 = do
let mk_ltys [] = return []
mk_ltys ((l,p):rs) = do i <- newMeta scope vtypePType
ltys <- mk_ltys rs
return ((l,p,VMeta i (scopeEnv scope) []) : ltys)
go scope [] = return scope
go scope ((l,p,ty):rs) = do scope <- tcPatt ge scope p ty
go scope rs
ltys <- mk_ltys rs
subsCheckRho ge scope (EPatt (PR rs)) (VRecType [(l,ty) | (l,p,ty) <- ltys]) ty0
go scope ltys
tcPatt ge scope (PAlt p1 p2) ty0 = do
tcPatt ge scope p1 ty0
tcPatt ge scope p2 ty0
return scope
tcPatt ge scope (PM q) ty0 = do
case lookupResType (geGrammar ge) q of
Ok (EPattType ty)
-> do vty <- liftErr (eval ge [] ty)
unify ge scope ty0 vty
return scope
Ok ty -> tcError ("Pattern type expected but " <+> pp ty <+> " found.")
Bad err -> tcError (pp err)
tcPatt ge scope p ty = unimplemented ("tcPatt "++show p)
inferRecFields ge scope rs =
mapM (\(l,r) -> tcRecField ge scope l r Nothing) rs
checkRecFields ge scope [] ltys
| null ltys = return []
| otherwise = tcError ("Missing fields:" <+> hsep (map fst ltys))
checkRecFields ge scope ((l,t):lts) ltys =
case takeIt l ltys of
(Just ty,ltys) -> do ltty <- tcRecField ge scope l t (Just ty)
lttys <- checkRecFields ge scope lts ltys
return (ltty : lttys)
(Nothing,ltys) -> do tcWarn ("Discarded field:" <+> l)
ltty <- tcRecField ge scope l t Nothing
lttys <- checkRecFields ge scope lts ltys
return lttys -- ignore the field
where
takeIt l1 [] = (Nothing, [])
takeIt l1 (lty@(l2,ty):ltys)
| l1 == l2 = (Just ty,ltys)
| otherwise = let (mb_ty,ltys') = takeIt l1 ltys
in (mb_ty,lty:ltys')
tcRecField ge scope l (mb_ann_ty,t) mb_ty = do
(t,ty) <- case mb_ann_ty of
Just ann_ty -> do (ann_ty, _) <- tcRho ge scope ann_ty (Just vtypeType)
v_ann_ty <- liftErr (eval ge (scopeEnv scope) ann_ty)
(t,_) <- tcRho ge scope t (Just v_ann_ty)
instSigma ge scope t v_ann_ty mb_ty
Nothing -> tcRho ge scope t mb_ty
return (l,t,ty)
tcRecTypeFields ge scope [] mb_ty = return ([],mb_ty)
tcRecTypeFields ge scope ((l,ty):rs) mb_ty = do
(ty,sort) <- tcRho ge scope ty mb_ty
mb_ty <- case sort of
VSort s
| s == cType -> return (Just sort)
| s == cPType -> return mb_ty
VMeta _ _ _ -> return mb_ty
_ -> do sort <- zonkTerm =<< tc_value2term (geLoc ge) (scopeVars scope) sort
tcError ("The record type field" <+> l <+> ':' <+> ppTerm Unqualified 0 ty $$
"cannot be of type" <+> ppTerm Unqualified 0 sort)
(rs,mb_ty) <- tcRecTypeFields ge scope rs mb_ty
return ((l,ty):rs,mb_ty)
-- | Invariant: if the third argument is (Just rho),
-- then rho is in weak-prenex form
instSigma :: GlobalEnv -> Scope -> Term -> Sigma -> Maybe Rho -> TcM (Term, Rho)
instSigma ge scope t ty1 Nothing = return (t,ty1) -- INST1
instSigma ge scope t ty1 (Just ty2) = do -- INST2
t <- subsCheckRho ge scope t ty1 ty2
return (t,ty2)
-- | Invariant: the second argument is in weak-prenex form
subsCheckRho :: GlobalEnv -> Scope -> Term -> Sigma -> Rho -> TcM Term
subsCheckRho ge scope t ty1@(VMeta i env vs) ty2 = do
mv <- getMeta i
case mv of
Unbound _ _ -> do unify ge scope ty1 ty2
return t
Bound ty1 -> do vty1 <- liftErr (eval ge env ty1)
subsCheckRho ge scope t (vapply (geLoc ge) vty1 vs) ty2
subsCheckRho ge scope t ty1 ty2@(VMeta i env vs) = do
mv <- getMeta i
case mv of
Unbound _ _ -> do unify ge scope ty1 ty2
return t
Bound ty2 -> do vty2 <- liftErr (eval ge env ty2)
subsCheckRho ge scope t ty1 (vapply (geLoc ge) vty2 vs)
subsCheckRho ge scope t (VProd Implicit ty1 x (Bind ty2)) rho2 = do -- Rule SPEC
i <- newMeta scope ty1
subsCheckRho ge scope (App t (ImplArg (Meta i))) (ty2 (VMeta i [] [])) rho2
subsCheckRho ge scope t rho1 (VProd Implicit ty1 x (Bind ty2)) = do -- Rule SKOL
let v = newVar scope
t <- subsCheckRho ge ((v,ty1):scope) t rho1 (ty2 (VGen (length scope) []))
return (Abs Implicit v t)
subsCheckRho ge scope t rho1 (VProd Explicit a2 _ (Bind r2)) = do -- Rule FUN
(_,a1,r1) <- unifyFun ge scope rho1
subsCheckFun ge scope t a1 r1 a2 r2
subsCheckRho ge scope t (VProd Explicit a1 _ (Bind r1)) rho2 = do -- Rule FUN
(bt,a2,r2) <- unifyFun ge scope rho2
subsCheckFun ge scope t a1 r1 a2 r2
subsCheckRho ge scope t rho1 (VTblType p2 r2) = do -- Rule TABLE
(p1,r1) <- unifyTbl ge scope rho1
subsCheckTbl ge scope t p1 r1 p2 r2
subsCheckRho ge scope t (VTblType p1 r1) rho2 = do -- Rule TABLE
(p2,r2) <- unifyTbl ge scope rho2
subsCheckTbl ge scope t p1 r1 p2 r2
subsCheckRho ge scope t (VSort s1) (VSort s2) -- Rule PTYPE
| s1 == cPType && s2 == cType = return t
subsCheckRho ge scope t (VApp p1 _) (VApp p2 _) -- Rule INT1
| predefName p1 == cInts && predefName p2 == cInt = return t
subsCheckRho ge scope t (VApp p1 [VInt i]) (VApp p2 [VInt j]) -- Rule INT2
| predefName p1 == cInts && predefName p2 == cInts =
if i <= j
then return t
else tcError ("Ints" <+> i <+> "is not a subtype of" <+> "Ints" <+> j)
subsCheckRho ge scope t ty1@(VRecType rs1) ty2@(VRecType rs2) = do -- Rule REC
let mkAccess scope t =
case t of
ExtR t1 t2 -> do (scope,mkProj1,mkWrap1) <- mkAccess scope t1
(scope,mkProj2,mkWrap2) <- mkAccess scope t2
return (scope
,\l -> mkProj2 l `mplus` mkProj1 l
,mkWrap1 . mkWrap2
)
R rs -> do sequence_ [tcWarn ("Discarded field:" <+> l) | (l,_) <- rs, isNothing (lookup l rs2)]
return (scope
,\l -> lookup l rs
,id
)
Vr x -> do return (scope
,\l -> do VRecType rs <- lookup x scope
ty <- lookup l rs
return (Nothing,P t l)
,id
)
t -> let x = newVar scope
in return (((x,ty1):scope)
,\l -> return (Nothing,P (Vr x) l)
,Let (x, (Nothing, t))
)
mkField scope l (mb_ty,t) ty1 ty2 = do
t <- subsCheckRho ge scope t ty1 ty2
return (l, (mb_ty,t))
(scope,mkProj,mkWrap) <- mkAccess scope t
let fields = [(l,ty2,lookup l rs1) | (l,ty2) <- rs2]
case [l | (l,_,Nothing) <- fields] of
[] -> return ()
missing -> tcError ("In the term" <+> pp t $$
"there are no values for fields:" <+> hsep missing)
rs <- sequence [mkField scope l t ty1 ty2 | (l,ty2,Just ty1) <- fields, Just t <- [mkProj l]]
return (mkWrap (R rs))
subsCheckRho ge scope t tau1 tau2 = do -- Rule EQ
unify ge scope tau1 tau2 -- Revert to ordinary unification
return t
subsCheckFun :: GlobalEnv -> Scope -> Term -> Sigma -> (Value -> Rho) -> Sigma -> (Value -> Rho) -> TcM Term
subsCheckFun ge scope t a1 r1 a2 r2 = do
let v = newVar scope
vt <- subsCheckRho ge ((v,a2):scope) (Vr v) a2 a1
val1 <- liftErr (eval ge (scopeEnv ((v,vtypeType):scope)) vt)
val2 <- return (VGen (length scope) [])
t <- subsCheckRho ge ((v,vtypeType):scope) (App t vt) (r1 val1) (r2 val2)
return (Abs Explicit v t)
subsCheckTbl :: GlobalEnv -> Scope -> Term -> Sigma -> Rho -> Sigma -> Rho -> TcM Term
subsCheckTbl ge scope t p1 r1 p2 r2 = do
let x = newVar scope
xt <- subsCheckRho ge scope (Vr x) p2 p1
t <- subsCheckRho ge ((x,vtypePType):scope) (S t xt) r1 r2 ;
p2 <- tc_value2term (geLoc ge) (scopeVars scope) p2
return (T (TTyped p2) [(PV x,t)])
-----------------------------------------------------------------------
-- Unification
-----------------------------------------------------------------------
unifyFun :: GlobalEnv -> Scope -> Rho -> TcM (BindType, Sigma, Value -> Rho)
unifyFun ge scope (VProd bt arg x (Bind res)) =
return (bt,arg,res)
unifyFun ge scope tau = do
let mk_val ty = VMeta ty [] []
arg <- fmap mk_val $ newMeta scope vtypeType
res <- fmap mk_val $ newMeta scope vtypeType
let bt = Explicit
unify ge scope tau (VProd bt arg identW (Bind (const res)))
return (bt,arg,const res)
unifyTbl :: GlobalEnv -> Scope -> Rho -> TcM (Sigma, Rho)
unifyTbl ge scope (VTblType arg res) =
return (arg,res)
unifyTbl ge scope tau = do
let mk_val ty = VMeta ty (scopeEnv scope) []
arg <- fmap mk_val $ newMeta scope vtypePType
res <- fmap mk_val $ newMeta scope vtypeType
unify ge scope tau (VTblType arg res)
return (arg,res)
unify ge scope (VApp f1 vs1) (VApp f2 vs2)
| f1 == f2 = sequence_ (zipWith (unify ge scope) vs1 vs2)
unify ge scope (VCApp f1 vs1) (VCApp f2 vs2)
| f1 == f2 = sequence_ (zipWith (unify ge scope) vs1 vs2)
unify ge scope (VSort s1) (VSort s2)
| s1 == s2 = return ()
unify ge scope (VGen i vs1) (VGen j vs2)
| i == j = sequence_ (zipWith (unify ge scope) vs1 vs2)
unify ge scope (VTblType p1 res1) (VTblType p2 res2) = do
unify ge scope p1 p2
unify ge scope res1 res2
unify ge scope (VMeta i env1 vs1) (VMeta j env2 vs2)
| i == j = sequence_ (zipWith (unify ge scope) vs1 vs2)
| otherwise = do mv <- getMeta j
case mv of
Bound t2 -> do v2 <- liftErr (eval ge env2 t2)
unify ge scope (VMeta i env1 vs1) (vapply (geLoc ge) v2 vs2)
Unbound _ _ -> setMeta i (Bound (Meta j))
unify ge scope (VInt i) (VInt j)
| i == j = return ()
unify ge scope (VMeta i env vs) v = unifyVar ge scope i env vs v
unify ge scope v (VMeta i env vs) = unifyVar ge scope i env vs v
unify ge scope v1 v2 = do
t1 <- zonkTerm =<< tc_value2term (geLoc ge) (scopeVars scope) v1
t2 <- zonkTerm =<< tc_value2term (geLoc ge) (scopeVars scope) v2
tcError ("Cannot unify terms:" <+> (ppTerm Unqualified 0 t1 $$
ppTerm Unqualified 0 t2))
-- | Invariant: tv1 is a flexible type variable
unifyVar :: GlobalEnv -> Scope -> MetaId -> Env -> [Value] -> Tau -> TcM ()
unifyVar ge scope i env vs ty2 = do -- Check whether i is bound
mv <- getMeta i
case mv of
Bound ty1 -> do v <- liftErr (eval ge env ty1)
unify ge scope (vapply (geLoc ge) v vs) ty2
Unbound scope' _ -> case value2term (geLoc ge) (scopeVars scope') ty2 of
-- Left i -> let (v,_) = reverse scope !! i
-- in tcError ("Variable" <+> pp v <+> "has escaped")
ty2' -> do ms2 <- getMetaVars (geLoc ge) [(scope,ty2)]
if i `elem` ms2
then tcError ("Occurs check for" <+> ppMeta i <+> "in:" $$
nest 2 (ppTerm Unqualified 0 ty2'))
else setMeta i (Bound ty2')
-----------------------------------------------------------------------
-- Instantiation and quantification
-----------------------------------------------------------------------
-- | Instantiate the topmost implicit arguments with metavariables
instantiate :: Scope -> Term -> Sigma -> TcM (Term,Rho)
instantiate scope t (VProd Implicit ty1 x (Bind ty2)) = do
i <- newMeta scope ty1
instantiate scope (App t (ImplArg (Meta i))) (ty2 (VMeta i [] []))
instantiate scope t ty = do
return (t,ty)
-- | Build fresh lambda abstractions for the topmost implicit arguments
skolemise :: GlobalEnv -> Scope -> Sigma -> TcM (Scope, Term->Term, Rho)
skolemise ge scope ty@(VMeta i env vs) = do
mv <- getMeta i
case mv of
Unbound _ _ -> return (scope,id,ty) -- guarded constant?
Bound ty -> do vty <- liftErr (eval ge env ty)
skolemise ge scope (vapply (geLoc ge) vty vs)
skolemise ge scope (VProd Implicit ty1 x (Bind ty2)) = do
let v = newVar scope
(scope,f,ty2) <- skolemise ge ((v,ty1):scope) (ty2 (VGen (length scope) []))
return (scope,Abs Implicit v . f,ty2)
skolemise ge scope ty = do
return (scope,id,ty)
-- | Quantify over the specified type variables (all flexible)
quantify :: GlobalEnv -> Scope -> Term -> [MetaId] -> Rho -> TcM (Term,Sigma)
quantify ge scope t tvs ty0 = do
ty <- tc_value2term (geLoc ge) (scopeVars scope) ty0
let used_bndrs = nub (bndrs ty) -- Avoid quantified type variables in use
new_bndrs = take (length tvs) (allBinders \\ used_bndrs)
mapM_ bind (tvs `zip` new_bndrs) -- 'bind' is just a cunning way
ty <- zonkTerm ty -- of doing the substitution
vty <- liftErr (eval ge [] (foldr (\v ty -> Prod Implicit v typeType ty) ty new_bndrs))
return (foldr (Abs Implicit) t new_bndrs,vty)
where
bind (i, name) = setMeta i (Bound (Vr name))
bndrs (Prod _ x t1 t2) = [x] ++ bndrs t1 ++ bndrs t2
bndrs _ = []
allBinders :: [Ident] -- a,b,..z, a1, b1,... z1, a2, b2,...
allBinders = [ identS [x] | x <- ['a'..'z'] ] ++
[ identS (x : show i) | i <- [1 :: Integer ..], x <- ['a'..'z']]
-----------------------------------------------------------------------
-- The Monad
-----------------------------------------------------------------------
type Scope = [(Ident,Value)]
type Sigma = Value
type Rho = Value -- No top-level ForAll
type Tau = Value -- No ForAlls anywhere
data MetaValue
= Unbound Scope Sigma
| Bound Term
type MetaStore = IntMap.IntMap MetaValue
data TcResult a
= TcOk a MetaStore [Message]
| TcFail [Message] -- First msg is error, the rest are warnings?
newtype TcM a = TcM {unTcM :: MetaStore -> [Message] -> TcResult a}
instance Monad TcM where
return x = TcM (\ms msgs -> TcOk x ms msgs)
f >>= g = TcM (\ms msgs -> case unTcM f ms msgs of
TcOk x ms msgs -> unTcM (g x) ms 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
instance Applicative TcM where
pure = return
(<*>) = ap
instance Functor TcM where
fmap f g = TcM (\ms msgs -> case unTcM g ms msgs of
TcOk x ms msgs -> TcOk (f x) ms msgs
TcFail msgs -> TcFail msgs)
instance ErrorMonad TcM where
raise = tcError . pp
handle f g = TcM (\ms msgs -> case unTcM f ms msgs of
TcFail (msg:msgs) -> unTcM (g (render msg)) ms msgs
r -> r)
tcError :: Message -> TcM a
tcError msg = TcM (\ms msgs -> TcFail (msg : msgs))
tcWarn :: Message -> TcM ()
tcWarn msg = TcM (\ms msgs -> TcOk () ms (msg : msgs))
unimplemented str = fail ("Unimplemented: "++str)
runTcM :: TcM a -> Check a
runTcM f = case unTcM f IntMap.empty [] of
TcOk x _ msgs -> do checkWarnings msgs; return x
TcFail (msg:msgs) -> do checkWarnings msgs; checkError msg
newMeta :: Scope -> Sigma -> TcM MetaId
newMeta scope ty = TcM (\ms msgs ->
let i = IntMap.size ms
in TcOk i (IntMap.insert i (Unbound scope ty) ms) msgs)
getMeta :: MetaId -> TcM MetaValue
getMeta i = TcM (\ms msgs ->
case IntMap.lookup i ms of
Just mv -> TcOk mv ms msgs
Nothing -> TcFail (("Unknown metavariable" <+> ppMeta i) : msgs))
setMeta :: MetaId -> MetaValue -> TcM ()
setMeta i mv = TcM (\ms msgs -> TcOk () (IntMap.insert i mv ms) msgs)
newVar :: Scope -> Ident
newVar scope = head [x | i <- [1..],
let x = identS ('v':show i),
isFree scope x]
where
isFree [] x = True
isFree ((y,_):scope) x = x /= y && isFree scope x
scopeEnv scope = zipWith (\(x,ty) i -> (x,VGen i [])) (reverse scope) [0..]
scopeVars scope = map fst scope
scopeTypes scope = zipWith (\(_,ty) scope -> (scope,ty)) scope (tails scope)
-- | This function takes account of zonking, and returns a set
-- (no duplicates) of unbound meta-type variables
getMetaVars :: GLocation -> [(Scope,Sigma)] -> TcM [MetaId]
getMetaVars loc sc_tys = do
tys <- mapM (\(scope,ty) -> zonkTerm =<< tc_value2term loc (scopeVars scope) ty) sc_tys
return (foldr go [] tys)
where
-- Get the MetaIds from a term; no duplicates in result
go (Vr tv) acc = acc
go (App x y) acc = go x (go y acc)
go (Meta i) acc
| i `elem` acc = acc
| otherwise = i : acc
go (Q _) acc = acc
go (QC _) acc = acc
go (Sort _) acc = acc
go (Prod _ _ arg res) acc = go arg (go res acc)
go (Table p t) acc = go p (go t acc)
go (RecType rs) acc = foldl (\acc (l,ty) -> go ty acc) acc rs
go t acc = unimplemented ("go "++show t)
-- | This function takes account of zonking, and returns a set
-- (no duplicates) of free type variables
getFreeVars :: GLocation -> [(Scope,Sigma)] -> TcM [Ident]
getFreeVars loc sc_tys = do
tys <- mapM (\(scope,ty) -> zonkTerm =<< tc_value2term loc (scopeVars scope) ty) sc_tys
return (foldr (go []) [] tys)
where
go bound (Vr tv) acc
| tv `elem` bound = acc
| tv `elem` acc = acc
| otherwise = tv : acc
go bound (App x y) acc = go bound x (go bound y acc)
go bound (Meta _) acc = acc
go bound (Q _) acc = acc
go bound (QC _) acc = acc
go bound (Prod _ x arg res) acc = go bound arg (go (x : bound) res acc)
go bound (RecType rs) acc = foldl (\acc (l,ty) -> go bound ty acc) acc rs
go bound (Table p t) acc = go bound p (go bound t acc)
-- | Eliminate any substitutions in a term
zonkTerm :: Term -> TcM Term
zonkTerm (Meta i) = do
mv <- getMeta i
case mv of
Unbound _ _ -> return (Meta i)
Bound t -> do t <- zonkTerm t
setMeta i (Bound t) -- "Short out" multiple hops
return t
zonkTerm t = composOp zonkTerm t
tc_value2term loc xs v =
return $ value2term loc xs v
-- Old value2term error message:
-- Left i -> tcError ("Variable #" <+> pp i <+> "has escaped")
data TcA x a
= TcSingle (MetaStore -> [Message] -> TcResult a)
| TcMany [x] (MetaStore -> [Message] -> [(a,MetaStore,[Message])])
mkTcA :: Err [a] -> TcA a a
mkTcA f = case f of
Bad msg -> TcSingle (\ms msgs -> TcFail (pp msg : msgs))
Ok [x] -> TcSingle (\ms msgs -> TcOk x ms msgs)
Ok xs -> TcMany xs (\ms msgs -> [(x,ms,msgs) | x <- xs])
singleTcA :: TcM a -> TcA x a
singleTcA = TcSingle . unTcM
bindTcA :: TcA x a -> (a -> TcM b) -> TcA x b
bindTcA f g = case f of
TcSingle f -> TcSingle (unTcM (TcM f >>= g))
TcMany xs f -> TcMany xs (\ms msgs -> foldr add [] (f ms msgs))
where
add (y,ms,msgs) rs =
case unTcM (g y) ms msgs of
TcFail _ -> rs
TcOk y ms msgs -> (y,ms,msgs):rs
runTcA :: ([x] -> TcM a) -> TcA x a -> TcM a
runTcA g f = TcM (\ms msgs -> case f of
TcMany xs f -> case f ms msgs of
[(x,ms,msgs)] -> TcOk x ms msgs
rs -> unTcM (g xs) ms msgs
TcSingle f -> f ms msgs)

View File

@@ -1,68 +0,0 @@
module GF.Compile.TypeCheck.Primitives where
import GF.Grammar
import GF.Grammar.Predef
import qualified Data.Map as Map
typPredefined :: Ident -> Maybe Type
typPredefined f = case Map.lookup f primitives of
Just (ResOper (Just (L _ ty)) _) -> Just ty
Just (ResParam _ _) -> Just typePType
Just (ResValue (L _ ty)) -> Just ty
_ -> Nothing
primitives = Map.fromList
[ (cErrorType, ResOper (Just (noLoc typeType)) Nothing)
, (cInt , ResOper (Just (noLoc typePType)) Nothing)
, (cFloat , ResOper (Just (noLoc typePType)) Nothing)
, (cInts , fun [typeInt] typePType)
, (cPBool , ResParam (Just (noLoc [(cPTrue,[]),(cPFalse,[])])) (Just [QC (cPredef,cPTrue), QC (cPredef,cPFalse)]))
, (cPTrue , ResValue (noLoc typePBool))
, (cPFalse , ResValue (noLoc typePBool))
, (cError , fun [typeStr] typeError) -- non-can. of empty set
, (cLength , fun [typeTok] typeInt)
, (cDrop , fun [typeInt,typeTok] typeTok)
, (cTake , fun [typeInt,typeTok] typeTok)
, (cTk , fun [typeInt,typeTok] typeTok)
, (cDp , fun [typeInt,typeTok] typeTok)
, (cEqInt , fun [typeInt,typeInt] typePBool)
, (cLessInt , fun [typeInt,typeInt] typePBool)
, (cPlus , fun [typeInt,typeInt] typeInt)
, (cEqStr , fun [typeTok,typeTok] typePBool)
, (cOccur , fun [typeTok,typeTok] typePBool)
, (cOccurs , fun [typeTok,typeTok] typePBool)
, (cToUpper , fun [typeTok] typeTok)
, (cToLower , fun [typeTok] typeTok)
, (cIsUpper , fun [typeTok] typePBool)
---- "read" ->
, (cRead , ResOper (Just (noLoc (mkProd -- (P : Type) -> Tok -> P
[(Explicit,varP,typePType),(Explicit,identW,typeStr)] (Vr varP) []))) Nothing)
, (cShow , ResOper (Just (noLoc (mkProd -- (P : PType) -> P -> Tok
[(Explicit,varP,typePType),(Explicit,identW,Vr varP)] typeStr []))) Nothing)
, (cEqVal , ResOper (Just (noLoc (mkProd -- (P : PType) -> P -> P -> PBool
[(Explicit,varP,typePType),(Explicit,identW,Vr varP),(Explicit,identW,Vr varP)] typePBool []))) Nothing)
, (cToStr , ResOper (Just (noLoc (mkProd -- (L : Type) -> L -> Str
[(Explicit,varL,typeType),(Explicit,identW,Vr varL)] typeStr []))) Nothing)
, (cMapStr , ResOper (Just (noLoc (mkProd -- (L : Type) -> (Str -> Str) -> L -> L
[(Explicit,varL,typeType),(Explicit,identW,mkFunType [typeStr] typeStr),(Explicit,identW,Vr varL)] (Vr varL) []))) Nothing)
, (cNonExist , ResOper (Just (noLoc (mkProd -- Str
[] typeStr []))) Nothing)
, (cBIND , ResOper (Just (noLoc (mkProd -- Str
[] typeStr []))) Nothing)
, (cSOFT_BIND, ResOper (Just (noLoc (mkProd -- Str
[] typeStr []))) Nothing)
, (cSOFT_SPACE,ResOper (Just (noLoc (mkProd -- Str
[] typeStr []))) Nothing)
, (cCAPIT , ResOper (Just (noLoc (mkProd -- Str
[] typeStr []))) Nothing)
, (cALL_CAPIT, ResOper (Just (noLoc (mkProd -- Str
[] typeStr []))) Nothing)
]
where
fun from to = oper (mkFunType from to)
oper ty = ResOper (Just (noLoc ty)) Nothing
varL = identS "L"
varP = identS "P"

View File

@@ -1,57 +0,0 @@
----------------------------------------------------------------------
-- |
-- Module : XML
--
-- Utilities for creating XML documents.
----------------------------------------------------------------------
module GF.Data.XML (XML(..), Attr, comments, showXMLDoc, showsXMLDoc, showsXML, bottomUpXML) where
import GF.Data.Utilities
data XML = Data String | CData String | Tag String [Attr] [XML] | ETag String [Attr] | Comment String | Empty
deriving (Ord,Eq,Show)
type Attr = (String,String)
comments :: [String] -> [XML]
comments = map Comment
showXMLDoc :: XML -> String
showXMLDoc xml = showsXMLDoc xml ""
showsXMLDoc :: XML -> ShowS
showsXMLDoc xml = showString header . showsXML xml
where header = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"
showsXML :: XML -> ShowS
showsXML = showsX 0 where
showsX i x = ind i . case x of
(Data s) -> showString s
(CData s) -> showString "<![CDATA[" . showString s .showString "]]>"
(ETag t as) -> showChar '<' . showString t . showsAttrs as . showString "/>"
(Tag t as cs) ->
showChar '<' . showString t . showsAttrs as . showChar '>' .
concatS (map (showsX (i+1)) cs) . ind i .
showString "</" . showString t . showChar '>'
(Comment c) -> showString "<!-- " . showString c . showString " -->"
(Empty) -> id
ind i = showString ("\n" ++ replicate (2*i) ' ')
showsAttrs :: [Attr] -> ShowS
showsAttrs = concatS . map (showChar ' ' .) . map showsAttr
showsAttr :: Attr -> ShowS
showsAttr (n,v) = showString n . showString "=\"" . showString (escape v) . showString "\""
escape :: String -> String
escape = concatMap escChar
where
escChar '<' = "&lt;"
escChar '>' = "&gt;"
escChar '&' = "&amp;"
escChar '"' = "&quot;"
escChar c = [c]
bottomUpXML :: (XML -> XML) -> XML -> XML
bottomUpXML f (Tag n attrs cs) = f (Tag n attrs (map (bottomUpXML f) cs))
bottomUpXML f x = f x

View File

@@ -1,313 +0,0 @@
-- |
-- Module : GF.Grammar.Canonical
-- Stability : provisional
--
-- Abstract syntax for canonical GF grammars, i.e. what's left after
-- high-level constructions such as functors and opers have been eliminated
-- by partial evaluation. This is intended as a common intermediate
-- representation to simplify export to other formats.
{-# LANGUAGE DeriveTraversable #-}
module GF.Grammar.Canonical where
import Prelude hiding ((<>))
import GF.Text.Pretty
import GF.Infra.Ident (RawIdent)
-- | A Complete grammar
data Grammar = Grammar Abstract [Concrete] deriving Show
--------------------------------------------------------------------------------
-- ** Abstract Syntax
-- | Abstract Syntax
data Abstract = Abstract ModId Flags [CatDef] [FunDef] deriving Show
abstrName (Abstract mn _ _ _) = mn
data CatDef = CatDef CatId [CatId] deriving Show
data FunDef = FunDef FunId Type deriving Show
data Type = Type [TypeBinding] TypeApp deriving Show
data TypeApp = TypeApp CatId [Type] deriving Show
data TypeBinding = TypeBinding VarId Type deriving Show
--------------------------------------------------------------------------------
-- ** Concreate syntax
-- | Concrete Syntax
data Concrete = Concrete ModId ModId Flags [ParamDef] [LincatDef] [LinDef]
deriving Show
concName (Concrete cnc _ _ _ _ _) = cnc
data ParamDef = ParamDef ParamId [ParamValueDef]
| ParamAliasDef ParamId LinType
deriving Show
data LincatDef = LincatDef CatId LinType deriving Show
data LinDef = LinDef FunId [VarId] LinValue deriving Show
-- | Linearization type, RHS of @lincat@
data LinType = FloatType
| IntType
| ParamType ParamType
| RecordType [RecordRowType]
| StrType
| TableType LinType LinType
| TupleType [LinType]
deriving (Eq,Ord,Show)
newtype ParamType = ParamTypeId ParamId deriving (Eq,Ord,Show)
-- | Linearization value, RHS of @lin@
data LinValue = ConcatValue LinValue LinValue
| LiteralValue LinLiteral
| ErrorValue String
| ParamConstant ParamValue
| PredefValue PredefId
| RecordValue [RecordRowValue]
| TableValue LinType [TableRowValue]
--- | VTableValue LinType [LinValue]
| TupleValue [LinValue]
| VariantValue [LinValue]
| VarValue VarValueId
| PreValue [([String], LinValue)] LinValue
| Projection LinValue LabelId
| Selection LinValue LinValue
| CommentedValue String LinValue
deriving (Eq,Ord,Show)
data LinLiteral = FloatConstant Float
| IntConstant Int
| StrConstant String
deriving (Eq,Ord,Show)
data LinPattern = ParamPattern ParamPattern
| RecordPattern [RecordRow LinPattern]
| TuplePattern [LinPattern]
| WildPattern
deriving (Eq,Ord,Show)
type ParamValue = Param LinValue
type ParamPattern = Param LinPattern
type ParamValueDef = Param ParamId
data Param arg = Param ParamId [arg]
deriving (Eq,Ord,Show,Functor,Foldable,Traversable)
type RecordRowType = RecordRow LinType
type RecordRowValue = RecordRow LinValue
type TableRowValue = TableRow LinValue
data RecordRow rhs = RecordRow LabelId rhs
deriving (Eq,Ord,Show,Functor,Foldable,Traversable)
data TableRow rhs = TableRow LinPattern rhs
deriving (Eq,Ord,Show,Functor,Foldable,Traversable)
-- *** Identifiers in Concrete Syntax
newtype PredefId = PredefId Id deriving (Eq,Ord,Show)
newtype LabelId = LabelId Id deriving (Eq,Ord,Show)
data VarValueId = VarValueId QualId deriving (Eq,Ord,Show)
-- | Name of param type or param value
newtype ParamId = ParamId QualId deriving (Eq,Ord,Show)
--------------------------------------------------------------------------------
-- ** Used in both Abstract and Concrete Syntax
newtype ModId = ModId Id deriving (Eq,Ord,Show)
newtype CatId = CatId Id deriving (Eq,Ord,Show)
newtype FunId = FunId Id deriving (Eq,Show)
data VarId = Anonymous | VarId Id deriving Show
newtype Flags = Flags [(FlagName,FlagValue)] deriving Show
type FlagName = Id
data FlagValue = Str String | Int Int | Flt Double deriving Show
-- *** Identifiers
type Id = RawIdent
data QualId = Qual ModId Id | Unqual Id deriving (Eq,Ord,Show)
--------------------------------------------------------------------------------
-- ** Pretty printing
instance Pretty Grammar where
pp (Grammar abs cncs) = abs $+$ vcat cncs
instance Pretty Abstract where
pp (Abstract m flags cats funs) =
"abstract" <+> m <+> "=" <+> "{" $$
flags $$
"cat" <+> fsep cats $$
"fun" <+> vcat funs $$
"}"
instance Pretty CatDef where
pp (CatDef c cs) = hsep (c:cs)<>";"
instance Pretty FunDef where
pp (FunDef f ty) = f <+> ":" <+> ty <>";"
instance Pretty Type where
pp (Type bs ty) = sep (punctuate " ->" (map pp bs ++ [pp ty]))
instance PPA Type where
ppA (Type [] (TypeApp c [])) = pp c
ppA t = parens t
instance Pretty TypeBinding where
pp (TypeBinding Anonymous (Type [] tapp)) = pp tapp
pp (TypeBinding Anonymous ty) = parens ty
pp (TypeBinding (VarId x) ty) = parens (x<+>":"<+>ty)
instance Pretty TypeApp where
pp (TypeApp c targs) = c<+>hsep (map ppA targs)
instance Pretty VarId where
pp Anonymous = pp "_"
pp (VarId x) = pp x
--------------------------------------------------------------------------------
instance Pretty Concrete where
pp (Concrete cncid absid flags params lincats lins) =
"concrete" <+> cncid <+> "of" <+> absid <+> "=" <+> "{" $$
vcat params $$
section "lincat" lincats $$
section "lin" lins $$
"}"
where
section name [] = empty
section name ds = name <+> vcat (map (<> ";") ds)
instance Pretty ParamDef where
pp (ParamDef p pvs) = hang ("param"<+> p <+> "=") 4 (punctuate " |" pvs)<>";"
pp (ParamAliasDef p t) = hang ("oper"<+> p <+> "=") 4 t<>";"
instance PPA arg => Pretty (Param arg) where
pp (Param p ps) = pp p<+>sep (map ppA ps)
instance PPA arg => PPA (Param arg) where
ppA (Param p []) = pp p
ppA pv = parens pv
instance Pretty LincatDef where
pp (LincatDef c lt) = hang (c <+> "=") 4 lt
instance Pretty LinType where
pp lt = case lt of
FloatType -> pp "Float"
IntType -> pp "Int"
ParamType pt -> pp pt
RecordType rs -> block rs
StrType -> pp "Str"
TableType pt lt -> sep [pt <+> "=>",pp lt]
TupleType lts -> "<"<>punctuate "," lts<>">"
instance RhsSeparator LinType where rhsSep _ = pp ":"
instance Pretty ParamType where
pp (ParamTypeId p) = pp p
instance Pretty LinDef where
pp (LinDef f xs lv) = hang (f<+>hsep xs<+>"=") 4 lv
instance Pretty LinValue where
pp lv = case lv of
ConcatValue v1 v2 -> sep [v1 <+> "++",pp v2]
ErrorValue s -> "Predef.error"<+>doubleQuotes s
ParamConstant pv -> pp pv
Projection lv l -> ppA lv<>"."<>l
Selection tv pv -> ppA tv<>"!"<>ppA pv
VariantValue vs -> "variants"<+>block vs
CommentedValue s v -> "{-" <+> s <+> "-}" $$ v
_ -> ppA lv
instance PPA LinValue where
ppA lv = case lv of
LiteralValue l -> ppA l
ParamConstant pv -> ppA pv
PredefValue p -> ppA p
RecordValue [] -> pp "<>"
RecordValue rvs -> block rvs
PreValue alts def ->
"pre"<+>block (map alt alts++["_"<+>"=>"<+>def])
where
alt (ss,lv) = hang (hcat (punctuate "|" (map doubleQuotes ss)))
2 ("=>"<+>lv)
TableValue _ tvs -> "table"<+>block tvs
-- VTableValue t ts -> "table"<+>t<+>brackets (semiSep ts)
TupleValue lvs -> "<"<>punctuate "," lvs<>">"
VarValue v -> pp v
_ -> parens lv
instance Pretty LinLiteral where pp = ppA
instance PPA LinLiteral where
ppA l = case l of
FloatConstant f -> pp f
IntConstant n -> pp n
StrConstant s -> doubleQuotes s -- hmm
instance RhsSeparator LinValue where rhsSep _ = pp "="
instance Pretty LinPattern where
pp p =
case p of
ParamPattern pv -> pp pv
_ -> ppA p
instance PPA LinPattern where
ppA p =
case p of
ParamPattern pv -> ppA pv
RecordPattern r -> block r
TuplePattern ps -> "<"<>punctuate "," ps<>">"
WildPattern -> pp "_"
instance RhsSeparator LinPattern where rhsSep _ = pp "="
instance RhsSeparator rhs => Pretty (RecordRow rhs) where
pp (RecordRow l v) = hang (l<+>rhsSep v) 2 v
instance Pretty rhs => Pretty (TableRow rhs) where
pp (TableRow l v) = hang (l<+>"=>") 2 v
--------------------------------------------------------------------------------
instance Pretty ModId where pp (ModId s) = pp s
instance Pretty CatId where pp (CatId s) = pp s
instance Pretty FunId where pp (FunId s) = pp s
instance Pretty LabelId where pp (LabelId s) = pp s
instance Pretty PredefId where pp = ppA
instance PPA PredefId where ppA (PredefId s) = "Predef."<>s
instance Pretty ParamId where pp = ppA
instance PPA ParamId where ppA (ParamId s) = pp s
instance Pretty VarValueId where pp (VarValueId s) = pp s
instance Pretty QualId where pp = ppA
instance PPA QualId where
ppA (Qual m n) = m<>"_"<>n -- hmm
ppA (Unqual n) = pp n
instance Pretty Flags where
pp (Flags []) = empty
pp (Flags flags) = "flags" <+> vcat (map ppFlag flags)
where
ppFlag (name,value) = name <+> "=" <+> value <>";"
instance Pretty FlagValue where
pp (Str s) = pp s
pp (Int i) = pp i
pp (Flt d) = pp d
--------------------------------------------------------------------------------
-- | Pretty print atomically (i.e. wrap it in parentheses if necessary)
class Pretty a => PPA a where ppA :: a -> Doc
class Pretty rhs => RhsSeparator rhs where rhsSep :: rhs -> Doc
semiSep xs = punctuate ";" xs
block xs = braces (semiSep xs)

View File

@@ -1,298 +0,0 @@
module GF.Grammar.CanonicalJSON (
encodeJSON
) where
import Text.JSON
import Control.Applicative ((<|>))
import Data.Ratio (denominator, numerator)
import GF.Grammar.Canonical
import Control.Monad (guard)
import GF.Infra.Ident (RawIdent,showRawIdent,rawIdentS)
encodeJSON :: FilePath -> Grammar -> IO ()
encodeJSON fpath g = writeFile fpath (encode g)
-- in general we encode grammars using JSON objects/records,
-- except for newtypes/coercions/direct values
-- the top-level definitions use normal record labels,
-- but recursive types/values/ids use labels staring with a "."
instance JSON Grammar where
showJSON (Grammar abs cncs) = makeObj [("abstract", showJSON abs), ("concretes", showJSON cncs)]
readJSON o = Grammar <$> o!"abstract" <*> o!"concretes"
--------------------------------------------------------------------------------
-- ** Abstract Syntax
instance JSON Abstract where
showJSON (Abstract absid flags cats funs)
= makeObj [("abs", showJSON absid),
("flags", showJSON flags),
("cats", showJSON cats),
("funs", showJSON funs)]
readJSON o = Abstract
<$> o!"abs"
<*>(o!"flags" <|> return (Flags []))
<*> o!"cats"
<*> o!"funs"
instance JSON CatDef where
-- non-dependent categories are encoded as simple strings:
showJSON (CatDef c []) = showJSON c
showJSON (CatDef c cs) = makeObj [("cat", showJSON c), ("args", showJSON cs)]
readJSON o = CatDef <$> readJSON o <*> return []
<|> CatDef <$> o!"cat" <*> o!"args"
instance JSON FunDef where
showJSON (FunDef f ty) = makeObj [("fun", showJSON f), ("type", showJSON ty)]
readJSON o = FunDef <$> o!"fun" <*> o!"type"
instance JSON Type where
showJSON (Type bs ty) = makeObj [(".args", showJSON bs), (".result", showJSON ty)]
readJSON o = Type <$> o!".args" <*> o!".result"
instance JSON TypeApp where
-- non-dependent categories are encoded as simple strings:
showJSON (TypeApp c []) = showJSON c
showJSON (TypeApp c args) = makeObj [(".cat", showJSON c), (".args", showJSON args)]
readJSON o = TypeApp <$> readJSON o <*> return []
<|> TypeApp <$> o!".cat" <*> o!".args"
instance JSON TypeBinding where
-- non-dependent categories are encoded as simple strings:
showJSON (TypeBinding Anonymous (Type [] (TypeApp c []))) = showJSON c
showJSON (TypeBinding x ty) = makeObj [(".var", showJSON x), (".type", showJSON ty)]
readJSON o = do c <- readJSON o
return (TypeBinding Anonymous (Type [] (TypeApp c [])))
<|> TypeBinding <$> o!".var" <*> o!".type"
--------------------------------------------------------------------------------
-- ** Concrete syntax
instance JSON Concrete where
showJSON (Concrete cncid absid flags params lincats lins)
= makeObj [("cnc", showJSON cncid),
("abs", showJSON absid),
("flags", showJSON flags),
("params", showJSON params),
("lincats", showJSON lincats),
("lins", showJSON lins)]
readJSON o = Concrete
<$> o!"cnc"
<*> o!"abs"
<*>(o!"flags" <|> return (Flags []))
<*> o!"params"
<*> o!"lincats"
<*> o!"lins"
instance JSON ParamDef where
showJSON (ParamDef p pvs) = makeObj [("param", showJSON p), ("values", showJSON pvs)]
showJSON (ParamAliasDef p t) = makeObj [("param", showJSON p), ("alias", showJSON t)]
readJSON o = ParamDef <$> o!"param" <*> o!"values"
<|> ParamAliasDef <$> o!"param" <*> o!"alias"
instance JSON LincatDef where
showJSON (LincatDef c lt) = makeObj [("cat", showJSON c), ("lintype", showJSON lt)]
readJSON o = LincatDef <$> o!"cat" <*> o!"lintype"
instance JSON LinDef where
showJSON (LinDef f xs lv) = makeObj [("fun", showJSON f), ("args", showJSON xs), ("lin", showJSON lv)]
readJSON o = LinDef <$> o!"fun" <*> o!"args" <*> o!"lin"
instance JSON LinType where
-- the basic types (Str, Float, Int) are encoded as strings:
showJSON (StrType) = showJSON "Str"
showJSON (FloatType) = showJSON "Float"
showJSON (IntType) = showJSON "Int"
-- parameters are also encoded as strings:
showJSON (ParamType pt) = showJSON pt
-- tables/tuples are encoded as JSON objects:
showJSON (TableType pt lt) = makeObj [(".tblarg", showJSON pt), (".tblval", showJSON lt)]
showJSON (TupleType lts) = makeObj [(".tuple", showJSON lts)]
-- records are encoded as records:
showJSON (RecordType rows) = showJSON rows
readJSON o = StrType <$ parseString "Str" o
<|> FloatType <$ parseString "Float" o
<|> IntType <$ parseString "Int" o
<|> ParamType <$> readJSON o
<|> TableType <$> o!".tblarg" <*> o!".tblval"
<|> TupleType <$> o!".tuple"
<|> RecordType <$> readJSON o
instance JSON LinValue where
showJSON (LiteralValue l ) = showJSON l
-- most values are encoded as JSON objects:
showJSON (ParamConstant pv) = makeObj [(".param", showJSON pv)]
showJSON (PredefValue p ) = makeObj [(".predef", showJSON p)]
showJSON (TableValue t tvs) = makeObj [(".tblarg", showJSON t), (".tblrows", showJSON tvs)]
showJSON (TupleValue lvs) = makeObj [(".tuple", showJSON lvs)]
showJSON (VarValue v ) = makeObj [(".var", showJSON v)]
showJSON (ErrorValue s ) = makeObj [(".error", showJSON s)]
showJSON (Projection lv l ) = makeObj [(".project", showJSON lv), (".label", showJSON l)]
showJSON (Selection tv pv) = makeObj [(".select", showJSON tv), (".key", showJSON pv)]
showJSON (VariantValue vs) = makeObj [(".variants", showJSON vs)]
showJSON (PreValue pre def) = makeObj [(".pre", showJSON pre),(".default", showJSON def)]
-- records are encoded directly as JSON records:
showJSON (RecordValue rows) = showJSON rows
-- concatenation is encoded as a JSON array:
showJSON v@(ConcatValue _ _) = showJSON (flatten v [])
where flatten (ConcatValue v v') = flatten v . flatten v'
flatten v = (v :)
readJSON o = LiteralValue <$> readJSON o
<|> ParamConstant <$> o!".param"
<|> PredefValue <$> o!".predef"
<|> TableValue <$> o!".tblarg" <*> o!".tblrows"
<|> TupleValue <$> o!".tuple"
<|> VarValue <$> o!".var"
<|> ErrorValue <$> o!".error"
<|> Projection <$> o!".project" <*> o!".label"
<|> Selection <$> o!".select" <*> o!".key"
<|> VariantValue <$> o!".variants"
<|> PreValue <$> o!".pre" <*> o!".default"
<|> RecordValue <$> readJSON o
<|> do vs <- readJSON o :: Result [LinValue]
return (foldr1 ConcatValue vs)
instance JSON LinLiteral where
-- basic values (Str, Float, Int) are encoded as JSON strings/numbers:
showJSON (StrConstant s) = showJSON s
showJSON (FloatConstant f) = showJSON f
showJSON (IntConstant n) = showJSON n
readJSON = readBasicJSON StrConstant IntConstant FloatConstant
instance JSON LinPattern where
-- wildcards and patterns without arguments are encoded as strings:
showJSON (WildPattern) = showJSON "_"
showJSON (ParamPattern (Param p [])) = showJSON p
-- complex patterns are encoded as JSON objects:
showJSON (ParamPattern pv) = showJSON pv
-- and records as records:
showJSON (RecordPattern r) = showJSON r
readJSON o = do p <- parseString "_" o; return WildPattern
<|> do p <- readJSON o; return (ParamPattern (Param p []))
<|> ParamPattern <$> readJSON o
<|> RecordPattern <$> readJSON o
instance JSON arg => JSON (Param arg) where
-- parameters without arguments are encoded as strings:
showJSON (Param p []) = showJSON p
showJSON (Param p args) = makeObj [(".paramid", showJSON p), (".args", showJSON args)]
readJSON o = Param <$> readJSON o <*> return []
<|> Param <$> o!".paramid" <*> o!".args"
instance JSON a => JSON (RecordRow a) where
-- record rows and lists of record rows are both encoded as JSON records (i.e., objects)
showJSON row = showJSONs [row]
showJSONs rows = makeObj (map toRow rows)
where toRow (RecordRow (LabelId lbl) val) = (showRawIdent lbl, showJSON val)
readJSON obj = head <$> readJSONs obj
readJSONs obj = mapM fromRow (assocsJSObject obj)
where fromRow (lbl, jsvalue) = do value <- readJSON jsvalue
return (RecordRow (LabelId (rawIdentS lbl)) value)
instance JSON rhs => JSON (TableRow rhs) where
showJSON (TableRow l v) = makeObj [(".pattern", showJSON l), (".value", showJSON v)]
readJSON o = TableRow <$> o!".pattern" <*> o!".value"
-- *** Identifiers in Concrete Syntax
instance JSON PredefId where showJSON (PredefId s) = showJSON s ; readJSON = fmap PredefId . readJSON
instance JSON LabelId where showJSON (LabelId s) = showJSON s ; readJSON = fmap LabelId . readJSON
instance JSON VarValueId where showJSON (VarValueId s) = showJSON s ; readJSON = fmap VarValueId . readJSON
instance JSON ParamId where showJSON (ParamId s) = showJSON s ; readJSON = fmap ParamId . readJSON
instance JSON ParamType where showJSON (ParamTypeId s) = showJSON s ; readJSON = fmap ParamTypeId . readJSON
--------------------------------------------------------------------------------
-- ** Used in both Abstract and Concrete Syntax
instance JSON ModId where showJSON (ModId s) = showJSON s ; readJSON = fmap ModId . readJSON
instance JSON CatId where showJSON (CatId s) = showJSON s ; readJSON = fmap CatId . readJSON
instance JSON FunId where showJSON (FunId s) = showJSON s ; readJSON = fmap FunId . readJSON
instance JSON VarId where
-- the anonymous variable is the underscore:
showJSON Anonymous = showJSON "_"
showJSON (VarId x) = showJSON x
readJSON o = do parseString "_" o; return Anonymous
<|> VarId <$> readJSON o
instance JSON QualId where
showJSON (Qual (ModId m) n) = showJSON (showRawIdent m++"."++showRawIdent n)
showJSON (Unqual n) = showJSON n
readJSON o = do qualid <- readJSON o
let (mod, id) = span (/= '.') qualid
return $ if null mod then Unqual (rawIdentS id) else Qual (ModId (rawIdentS mod)) (rawIdentS id)
instance JSON RawIdent where
showJSON i = showJSON $ showRawIdent i
readJSON o = rawIdentS <$> readJSON o
instance JSON Flags where
-- flags are encoded directly as JSON records (i.e., objects):
showJSON (Flags fs) = makeObj [(showRawIdent f, showJSON v) | (f, v) <- fs]
readJSON obj = Flags <$> mapM fromRow (assocsJSObject obj)
where fromRow (lbl, jsvalue) = do value <- readJSON jsvalue
return (rawIdentS lbl, value)
instance JSON FlagValue where
-- flag values are encoded as basic JSON types:
showJSON (Str s) = showJSON s
showJSON (Int i) = showJSON i
showJSON (Flt f) = showJSON f
readJSON = readBasicJSON Str Int Flt
--------------------------------------------------------------------------------
-- ** Convenience functions
parseString :: String -> JSValue -> Result ()
parseString s o = guard . (== s) =<< readJSON o
(!) :: JSON a => JSValue -> String -> Result a
obj ! key = maybe (fail $ "CanonicalJSON.(!): Could not find key: " ++ show key)
readJSON
(lookup key (assocsJSObject obj))
assocsJSObject :: JSValue -> [(String, JSValue)]
assocsJSObject (JSObject o) = fromJSObject o
assocsJSObject (JSArray _) = fail $ "CanonicalJSON.assocsJSObject: Expected a JSON object, found an Array"
assocsJSObject jsvalue = fail $ "CanonicalJSON.assocsJSObject: Expected a JSON object, found " ++ show jsvalue
readBasicJSON :: (JSON int, Integral int, JSON flt, RealFloat flt) =>
(String -> v) -> (int -> v) -> (flt -> v) -> JSValue -> Result v
readBasicJSON str int flt o
= str <$> readJSON o
<|> int_or_flt <$> readJSON o
where int_or_flt f | f == fromIntegral n = int n
| otherwise = flt f
where n = round f

View File

@@ -1,221 +0,0 @@
----------------------------------------------------------------------
-- |
-- Module : PatternMatch
-- Maintainer : AR
-- Stability : (stable)
-- Portability : (portable)
--
-- > CVS $Date: 2005/10/12 12:38:29 $
-- > CVS $Author: aarne $
-- > CVS $Revision: 1.7 $
--
-- pattern matching for both concrete and abstract syntax. AR -- 16\/6\/2003
-----------------------------------------------------------------------------
module GF.Grammar.PatternMatch (
matchPattern,
testOvershadow,
findMatch,
measurePatt
) where
import GF.Data.Operations
import GF.Grammar.Grammar
import GF.Infra.Ident
import GF.Grammar.Macros
--import GF.Grammar.Printer
--import Data.List
import Control.Monad
import GF.Text.Pretty
--import Debug.Trace
matchPattern :: ErrorMonad m => [(Patt,rhs)] -> Term -> m (rhs, Substitution)
matchPattern pts term =
if not (isInConstantForm term)
then raise (render ("variables occur in" <+> pp term))
else do
term' <- mkK term
errIn (render ("trying patterns" <+> hsep (punctuate ',' (map fst pts)))) $
findMatch [([p],t) | (p,t) <- pts] [term']
where
-- to capture all Str with string pattern matching
mkK s = case s of
C _ _ -> do
s' <- getS s
return (K (unwords s'))
_ -> return s
getS s = case s of
K w -> return [w]
C v w -> liftM2 (++) (getS v) (getS w)
Empty -> return []
_ -> raise (render ("cannot get string from" <+> s))
testOvershadow :: ErrorMonad m => [Patt] -> [Term] -> m [Patt]
testOvershadow pts vs = do
let numpts = zip pts [0..]
let cases = [(p,EInt i) | (p,i) <- numpts]
ts <- mapM (liftM fst . matchPattern cases) vs
return [p | (p,i) <- numpts, notElem i [i | EInt i <- ts] ]
findMatch :: ErrorMonad m => [([Patt],rhs)] -> [Term] -> m (rhs, Substitution)
findMatch cases terms = case cases of
[] -> raise (render ("no applicable case for" <+> hsep (punctuate ',' terms)))
(patts,_):_ | length patts /= length terms ->
raise (render ("wrong number of args for patterns :" <+> hsep patts <+>
"cannot take" <+> hsep terms))
(patts,val):cc -> case mapM tryMatch (zip patts terms) of
Ok substs -> return (val, concat substs)
_ -> findMatch cc terms
tryMatch :: (Patt, Term) -> Err [(Ident, Term)]
tryMatch (p,t) = do
t' <- termForm t
trym p t'
where
trym p t' =
case (p,t') of
-- (_,(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 "" = [""] = []
(PW, _) -> return [] -- optimization with wildcard
(PV x,([],K s,[])) -> return [(x,words2term (words s))]
(PV x, _) -> return [(x,t)]
(PString s, ([],K i,[])) | s==i -> return []
(PInt s, ([],EInt i,[])) | s==i -> return []
(PFloat s,([],EFloat i,[])) | s==i -> return [] --- rounding?
(PC p pp, ([], Con f, tt)) |
p `eqStrIdent` f && length pp == length tt ->
do matches <- mapM tryMatch (zip pp tt)
return (concat matches)
(PP (q,p) pp, ([], QC (r,f), tt)) |
-- q `eqStrIdent` r && --- not for inherited AR 10/10/2005
p `eqStrIdent` f && length pp == length tt ->
do matches <- mapM tryMatch (zip pp tt)
return (concat matches)
---- hack for AppPredef bug
(PP (q,p) pp, ([], Q (r,f), tt)) |
-- q `eqStrIdent` r && ---
p `eqStrIdent` f && length pp == length tt ->
do matches <- mapM tryMatch (zip pp tt)
return (concat matches)
(PR r, ([],R r',[])) |
all (`elem` map fst r') (map fst r) ->
do matches <- mapM tryMatch
[(p,snd a) | (l,p) <- r, let Just a = lookup l r']
return (concat matches)
(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
subst <- trym p' t'
return $ (x,t) : subst
(PAlt p1 p2,_) -> checks [trym p1 t', trym p2 t']
(PNeg p',_) -> case tryMatch (p',t) of
Bad _ -> return []
_ -> raise (render ("no match with negative pattern" <+> p))
(PSeq p1 p2, ([],K s, [])) -> matchPSeq p1 p2 s
(PMSeq mp1 mp2, ([],K s, [])) -> matchPMSeq mp1 mp2 s
(PRep p1, ([],K s, [])) -> checks [
trym (foldr (const (PSeq p1)) (PString "")
[1..n]) t' | n <- [0 .. length s]
] >>
return []
(PChar, ([],K [_], [])) -> return []
(PChars cs, ([],K [c], [])) | elem c cs -> return []
_ -> 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
--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' b1@(min1,max1) p1 b2@(min2,max2) p2 s =
do let n = length s
lo = min1 `max` (n-max2)
hi = (n-min2) `min` max1
cuts = [splitAt i s | i <- [lo..hi]]
matches <- checks [mapM tryMatch [(p1,K s1),(p2,K s2)] | (s1,s2) <- cuts]
return (concat matches)
-- | Estimate the minimal length of the string that a pattern will match
minLength = matchLength 0 id (+) min -- safe underestimate
-- | Estimate the maximal length of the string that a pattern will match
maxLength =
maybe maxBound id . matchLength Nothing Just (liftM2 (+)) (liftM2 max)
-- safe overestimate
matchLength unknown known seq alt = len
where
len p =
case p of
PString s -> known (length s)
PSeq p1 p2 -> seq (len p1) (len p2)
PAlt p1 p2 -> alt (len p1) (len p2)
PChar -> known 1
PChars _ -> known 1
PAs x p' -> len p'
PT t p' -> len p'
_ -> unknown
lengthBounds p = (minLength p,maxLength p)
mPatt p = (lengthBounds p,measurePatt p)
measurePatt p =
case p of
PSeq p1 p2 -> PMSeq (mPatt p1) (mPatt p2)
_ -> composSafePattOp measurePatt p
isInConstantForm :: Term -> Bool
isInConstantForm trm = case trm of
Cn _ -> True
Con _ -> True
Q _ -> True
QC _ -> True
Abs _ _ _ -> True
C c a -> isInConstantForm c && isInConstantForm a
App c a -> isInConstantForm c && isInConstantForm a
R r -> all (isInConstantForm . snd . snd) r
K _ -> True
Empty -> True
EInt _ -> True
V ty ts -> isInConstantForm ty && all isInConstantForm ts -- TH 2013-09-05
-- Typed e t-> isInConstantForm e && isInConstantForm t -- Add this? TH 2013-09-05
_ -> False ---- isInArgVarForm trm
{- -- unused and suspicuous, see contP in GF.Compile.Compute.Concrete instead
varsOfPatt :: Patt -> [Ident]
varsOfPatt p = case p of
PV x -> [x]
PC _ ps -> concat $ map varsOfPatt ps
PP _ ps -> concat $ map varsOfPatt ps
PR r -> concat $ map (varsOfPatt . snd) r
PT _ q -> varsOfPatt q
_ -> []
-- | to search matching parameter combinations in tables
isMatchingForms :: [Patt] -> [Term] -> Bool
isMatchingForms ps ts = all match (zip ps ts') where
match (PC c cs, (Cn d, ds)) = c == d && isMatchingForms cs ds
match _ = True
ts' = map appForm ts
-}

View File

@@ -1,22 +0,0 @@
module GF.Infra.CompactPrint where
import Data.Char
compactPrint = compactPrintCustom keywordGF (const False)
compactPrintGFCC = compactPrintCustom (const False) keywordGFCC
compactPrintCustom pre post = dps . concat . map (spaceIf pre post) . words
dps = dropWhile isSpace
spaceIf pre post w = case w of
_ | pre w -> "\n" ++ w
_ | post w -> w ++ "\n"
c:_ | isAlpha c || isDigit c -> " " ++ w
'_':_ -> " " ++ w
_ -> w
keywordGF w = elem w ["cat","fun","lin","lincat","lindef","oper","param"]
keywordGFCC w =
last w == ';' ||
elem w ["flags","fun","cat","lin","oper","lincat","lindef","printname","param"]

View File

@@ -1,438 +0,0 @@
{-# LANGUAGE CPP, ScopedTypeVariables, FlexibleInstances #-}
-- | GF interactive mode
module GF.Interactive (mainGFI,mainRunGFI,mainServerGFI) where
import Prelude hiding (putStrLn,print)
import qualified Prelude as P(putStrLn)
import GF.Command.Interpreter(CommandEnv(..),mkCommandEnv,interpretCommandLine)
import GF.Command.Commands(HasPGF(..),pgfCommands)
import GF.Command.CommonCommands(commonCommands,extend)
import GF.Command.SourceCommands
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.Grammar hiding (Ident,isPrefixOf)
import GF.Infra.UseIO(ioErrorText,putStrLnE)
import GF.Infra.SIO
import GF.Infra.Option
import qualified System.Console.Haskeline as Haskeline
import PGF2
import Data.Char
import Data.List(isPrefixOf)
import qualified Data.Map as Map
import qualified Text.ParserCombinators.ReadP as RP
import System.Directory({-getCurrentDirectory,-}getAppUserDataDirectory)
import Control.Exception(SomeException,fromException,evaluate,try)
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
shell opts files
shell opts files = flip evalStateT (emptyGFEnv opts) $
do mapStateT runSIO $ importInEnv opts files
modify $ \ gfenv0 -> gfenv0 {history = [unwords ("i":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' . snd
=<< runSIO (runStateT (importInEnv opts files) (emptyGFEnv opts))
where
root = flag optDocumentRoot opts
opts = beQuiet opts0
jobs = join (flag optJobs opts)
execute1' gfenv0 cmd =
do (continue,gfenv) <- runStateT (execute1 cmd) gfenv0
return $ if continue then Just gfenv else Nothing
#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, 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 [] = 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 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 -> 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
return void
_ -> 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 =
do pgf0 <- gets multigrammar
if flag optRetainResource opts
then do src <- lift $ importSource opts files
pgf <- lift . lazySIO $ importPGF pgf0 -- duplicates some work, better to link src
modify $ \ gfenv -> gfenv {retain=True, pgfenv = (src,pgf)}
else do pgf1 <- lift $ importPGF pgf0
modify $ \ gfenv->gfenv { retain=False,
pgfenv = (emptyGrammar,pgf1) }
where
importPGF pgf0 =
do let opts' = addOptions (setOptimization OptCSE False) opts
pgf1 <- importGrammar pgf0 opts' files
if (verbAtLeast opts Normal)
then case pgf1 of
Just pgf -> putStrLnFlush $ unwords $ "\nLanguages:" : Map.keys (languages pgf)
Nothing -> return ()
else return ()
return pgf1
tryGetLine = do
res <- try getLine
case res of
Left (e :: SomeException) -> return "q"
Right l -> return l
prompt env
| retain env = "> "
| otherwise = case multigrammar env of
Just pgf -> abstractName pgf ++ "> "
Nothing -> "> "
type CmdEnv = (Grammar,Maybe PGF)
data GFEnv = GFEnv {
startOpts :: Options,
retain :: Bool, -- grammar was imported with -retain flag
pgfenv :: CmdEnv,
commandenv :: CommandEnv ShellM,
history :: [String]
}
emptyGFEnv opts = GFEnv opts False emptyCmdEnv emptyCommandEnv []
emptyCmdEnv = (emptyGrammar,Nothing)
emptyCommandEnv = mkCommandEnv allCommands
multigrammar = snd . pgfenv
allCommands =
extend pgfCommands (helpCommand allCommands:moreCommands)
`Map.union` sourceCommands
`Map.union` commonCommands
instance HasGrammar ShellM where getGrammar = gets (fst . pgfenv)
instance HasPGF ShellM where getPGF = gets (snd . pgfenv)
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
-> case multigrammar gfenv of
Just pgf -> let langs = languages pgf
optLang opts = case valStrOpts "lang" "" opts of
"" -> case Map.minView langs of
Nothing -> Nothing
Just (concr,_) -> Just concr
lang -> mplus (Map.lookup lang langs)
(Map.lookup (abstractName pgf ++ lang) langs)
optType opts = let readOpt str = case readType str of
Just ty -> case checkType pgf ty of
Left _ -> Nothing
Right ty -> Just ty
Nothing -> Nothing
in maybeStrOpts "cat" (Just (startCat pgf)) readOpt opts
(rprefix,rs) = break isSpace (reverse s0)
s = reverse rs
prefix = reverse rprefix
in case (optLang opts, optType opts) of
(Just lang,Just cat) -> let compls = [t | ParseOk res <- [complete lang cat s prefix], (t,_,_,_) <- res]
in ret (length prefix) (map Haskeline.simpleCompletion compls)
_ -> ret 0 []
Nothing -> ret 0 []
CmplOpt (Just (Command n _ _)) pref
-> 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 multigrammar gfenv of
Just pgf -> ret (length pref) [Haskeline.simpleCompletion name | name <- functions pgf, isPrefixOf pref name]
Nothing -> ret (length pref) []
_ -> ret 0 []
where
cmdEnv = commandenv gfenv
loop ps [] = Just ps
loop ps (t:ts) = case error "nextState ps (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

4
src/compiler/Setup.hs Normal file
View File

@@ -0,0 +1,4 @@
import Distribution.Simple(defaultMain)
main :: IO ()
main = defaultMain

View File

@@ -74,10 +74,16 @@ import qualified Data.ByteString.Internal as S
#endif
#if defined(__GLASGOW_HASKELL__) && !defined(__HADDOCK__)
import GHC.Base(Int(..),uncheckedShiftRL# )
import GHC.Base(Int(..),uncheckedShiftRL#,)
import GHC.Word (Word32(..),Word16(..),Word64(..))
#if WORD_SIZE_IN_BITS < 64 && __GLASGOW_HASKELL__ >= 608
#if MIN_VERSION_base(4,16,0)
import GHC.Exts (wordToWord16#, word16ToWord#, wordToWord32#, word32ToWord#)
#endif
#if WORD_SIZE_IN_BITS < 64 && __GLASGOW_HASKELL__ >= 608
import GHC.Word (uncheckedShiftRL64#)
#endif
#if __GLASGOW_HASKELL__ >= 900
import GHC.Word (uncheckedShiftRL64#)
#endif
#endif
@@ -411,8 +417,14 @@ shiftr_w32 :: Word32 -> Int -> Word32
shiftr_w64 :: Word64 -> Int -> Word64
#if defined(__GLASGOW_HASKELL__) && !defined(__HADDOCK__)
#if MIN_VERSION_base(4,16,0)
shiftr_w16 (W16# w) (I# i) = W16# (wordToWord16# ((word16ToWord# w) `uncheckedShiftRL#` i))
shiftr_w32 (W32# w) (I# i) = W32# (wordToWord32# ((word32ToWord# w) `uncheckedShiftRL#` i))
#else
shiftr_w16 (W16# w) (I# i) = W16# (w `uncheckedShiftRL#` i)
shiftr_w32 (W32# w) (I# i) = W32# (w `uncheckedShiftRL#` i)
#endif
#if WORD_SIZE_IN_BITS < 64
shiftr_w64 (W64# w) (I# i) = W64# (w `uncheckedShiftRL64#` i)
@@ -424,7 +436,11 @@ foreign import ccall unsafe "stg_uncheckedShiftRL64"
#endif
#else
#if __GLASGOW_HASKELL__ <= 810
shiftr_w64 (W64# w) (I# i) = W64# (w `uncheckedShiftRL#` i)
#else
shiftr_w64 (W64# w) (I# i) = W64# (w `uncheckedShiftRL64#` i)
#endif
#endif
#else

View File

@@ -1,4 +1,6 @@
{-# LANGUAGE CPP, MagicHash #-}
-- This module makes profiling a lot slower, so don't add automatic cost centres
{-# OPTIONS_GHC -fno-prof-auto #-}
-- for unboxed shifts
-----------------------------------------------------------------------------
@@ -99,6 +101,12 @@ import Data.STRef
import GHC.Base
import GHC.Word
--import GHC.Int
#if MIN_VERSION_base(4,16,0)
import GHC.Exts (wordToWord16#, word16ToWord#, wordToWord32#, word32ToWord#)
#endif
#if __GLASGOW_HASKELL__ >= 900
import GHC.Word (uncheckedShiftL64#)
#endif
#endif
-- Control.Monad.Fail import will become redundant in GHC 8.8+
@@ -530,8 +538,13 @@ shiftl_w32 :: Word32 -> Int -> Word32
shiftl_w64 :: Word64 -> Int -> Word64
#if defined(__GLASGOW_HASKELL__) && !defined(__HADDOCK__)
#if MIN_VERSION_base(4,16,0)
shiftl_w16 (W16# w) (I# i) = W16# (wordToWord16# ((word16ToWord# w) `uncheckedShiftL#` i))
shiftl_w32 (W32# w) (I# i) = W32# (wordToWord32# ((word32ToWord# w) `uncheckedShiftL#` i))
#else
shiftl_w16 (W16# w) (I# i) = W16# (w `uncheckedShiftL#` i)
shiftl_w32 (W32# w) (I# i) = W32# (w `uncheckedShiftL#` i)
#endif
#if WORD_SIZE_IN_BITS < 64
shiftl_w64 (W64# w) (I# i) = W64# (w `uncheckedShiftL64#` i)
@@ -543,7 +556,12 @@ foreign import ccall unsafe "stg_uncheckedShiftL64"
#endif
#else
#if __GLASGOW_HASKELL__ <= 810
shiftl_w64 (W64# w) (I# i) = W64# (w `uncheckedShiftL#` i)
#else
shiftl_w64 (W64# w) (I# i) = W64# (w `uncheckedShiftL64#` i)
#endif
#endif
#else

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,Literal(..),Term) where
import PGF2(Expr,showExpr)
import PGF2
import GF.Grammar.Grammar(Term)
type Ident = String
@@ -13,15 +13,22 @@ data Command
= Command Ident [Option] Argument
deriving Show
data TransactionCommand
= CreateFun [Option] Fun Type
| CreateCat [Option] Cat [Hypo]
| CreateConcrete [Option] ConcName
| CreateLin [Option] Fun (Maybe Term) Bool
| CreateLincat [Option] Cat (Maybe Term)
| DropFun [Option] Fun
| DropCat [Option] Cat
| DropConcrete [Option] ConcName
| DropLin [Option] Fun
| DropLincat [Option] Cat
deriving Show
data Option
= OOpt Ident
| OFlag Ident Value
deriving (Eq,Ord,Show)
data Value
= VId Ident
| VInt Int
| VStr String
| OFlag Ident Literal
deriving (Eq,Ord,Show)
data Argument
@@ -33,9 +40,19 @@ data Argument
valIntOpts :: String -> Int -> [Option] -> Int
valIntOpts flag def opts =
case [v | OFlag f (VInt v) <- opts, f == flag] of
case [v | OFlag f (LInt v) <- opts, f == flag] of
(v:_) -> fromIntegral v
_ -> def
valFltOpts :: String -> Double -> [Option] -> Double
valFltOpts flag def opts =
case [v | OFlag f v <- opts, v <- toFlt v, f == flag] of
(v:_) -> v
_ -> def
where
toFlt (LInt v) = [fromIntegral v]
toFlt (LFlt f) = [f]
toFlt _ = []
valStrOpts :: String -> String -> [Option] -> String
valStrOpts flag def opts =
@@ -45,8 +62,8 @@ valStrOpts flag def opts =
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
case [v | OFlag f (LInt v) <- opts, f == flag] of
(v:_) -> fn (fromIntegral v)
_ -> def
maybeStrOpts :: String -> a -> (String -> a) -> [Option] -> a
@@ -59,9 +76,9 @@ listFlags flag opts = [v | OFlag f v <- opts, f == flag]
valueString v =
case v of
VStr v -> v
VId v -> v
VInt v -> show v
LInt v -> show v
LFlt v -> show v
LStr v -> v
isOpt :: String -> [Option] -> Bool
isOpt o opts = elem (OOpt o) opts

View File

@@ -1,8 +1,8 @@
module GF.Command.CommandInfo where
import GF.Command.Abstract(Option,Expr,Term)
import GF.Text.Pretty(render)
import GF.Grammar.Grammar(Term(K))
import GF.Grammar.Printer() -- instance Pretty Term
import GF.Grammar.Macros(string2term)
import PGF2(mkStr,unStr,showExpr)
data CommandInfo m = CommandInfo {
@@ -73,8 +73,8 @@ toExprs args =
toTerm args =
case args of
Term t -> t
Strings ss -> string2term $ unwords ss -- hmm
Exprs es -> string2term $ unwords $ map (showExpr [] . fst) es -- hmm
Strings ss -> K $ unwords ss -- hmm
Exprs es -> K $ unwords $ map (showExpr [] . fst) es -- hmm
-- ** Creating documentation

View File

@@ -3,10 +3,10 @@ module GF.Command.Commands (
HasPGF(..),pgfCommands,
options,flags,
) where
import Prelude hiding (putStrLn,(<>))
import Prelude hiding (putStrLn,(<>)) -- GHC 8.4.1 clash with Text.PrettyPrint
import System.Info(os)
import PGF2
import PGF2.Internal(writePGF)
import GF.Compile.Export
import GF.Compile.ToAPI
@@ -32,8 +32,6 @@ import GF.Text.Pretty
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)
@@ -45,7 +43,7 @@ instance (Monad m,HasPGF m,Fail.MonadFail m) => TypeCheckArg m where
(inferExpr pgf e)
Nothing -> fail "Import a grammar before using this command"
pgfCommands :: HasPGF m => Map.Map String (CommandInfo m)
pgfCommands :: (HasPGF m, Fail.MonadFail m) => Map.Map String (CommandInfo m)
pgfCommands = Map.fromList [
("aw", emptyCommandInfo {
longname = "align_words",
@@ -166,29 +164,32 @@ pgfCommands = Map.fromList [
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 ?))"
mkEx "gr (AdjCN ? (UseN ?)) -- fills in the metavariables in the expression"
],
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",
"if the grammar was compiled with option -probs"
"If a tree argument is given, the command fills in",
"the metavariables in the tree with values. The generation is",
"biased by probabilities if the grammar was compiled with",
"option -probs."
],
options = [
("show_probs", "show the probability of each result")
],
flags = [
("cat","generation category"),
("depth","the maximum generation depth, default 4"),
("lang","uses only functions that have linearizations in all these languages"),
("number","number of trees generated")
],
exec = needPGF $ \opts arg pgf -> do
gen <- newStdGen
let ts = case mexp (toExprs arg) of
Just ex -> generateRandomFrom gen pgf ex
Nothing -> generateRandom gen pgf (optType pgf opts)
returnFromExprs (isOpt "show_probs" opts) $ take (optNum opts) ts
let dp = valIntOpts "depth" 4 opts
langs = optLangs pgf opts
es = case mexp (toExprs arg) of
Just ex -> generateRandomFromExt gen pgf ex dp langs
Nothing -> generateRandomExt gen pgf (optType pgf opts) dp langs
returnFromExprs (isOpt "show_probs" opts) $ take (optNum opts) es
}),
("gt", emptyCommandInfo {
@@ -196,26 +197,32 @@ pgfCommands = Map.fromList [
synopsis = "generates a list of trees, by default exhaustive",
explanation = unlines [
"Generates all trees of a given category.",
"If a Tree argument is given, the command completes the Tree with values",
"to all metavariables in the tree."
"If a tree argument is given, the command completes",
"the metavariables in the tree with values.",
"The generated trees are listed in decreasing probability order",
"(increasing negated log-probability)."
],
options = [
("show_probs", "show the probability of each result")
],
flags = [
("cat","the generation category"),
("lang","excludes functions that have no linearization in this language"),
("depth","the maximum generation depth, default 4"),
("lang","uses only functions that have linearizations in all these languages"),
("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",
mkEx "gt -- all trees in the startcat with maximal depth 4",
mkEx "gt -cat=NP -number=16 -- 16 trees in the category NP with maximal depth 4",
mkEx "gt -cat=NP -depth=2 -- all trees in the category NP with up to depth 2",
mkEx "gt (AdjCN ? (UseN ?)) -- trees of form (AdjCN ? (UseN ?))"
],
exec = needPGF $ \opts arg pgf -> do
let es = case mexp (toExprs arg) of
Just ex -> generateAllFrom pgf ex
Nothing -> generateAll pgf (optType pgf opts)
let dp = valIntOpts "depth" 4 opts
langs = optLangs pgf opts
es = case mexp (toExprs arg) of
Just ex -> generateAllFromExt pgf ex dp langs
Nothing -> generateAllExt pgf (optType pgf opts) dp langs
returnFromExprs (isOpt "show_probs" opts) $ takeOptNum opts es
}),
@@ -240,6 +247,7 @@ pgfCommands = Map.fromList [
],
options = [
("retain","retain operations (used for cc command)"),
("resource","the grammar is loaded as a resource to a precompiled PGF"),
("src", "force compilation from source"),
("v", "be verbose - show intermediate status information")
],
@@ -277,31 +285,49 @@ pgfCommands = Map.fromList [
("ma", emptyCommandInfo {
longname = "morpho_analyse",
synopsis = "print the morphological analyses of all words in the string",
synopsis = "print the morphological analyses of words in the string",
explanation = unlines [
"Prints all the analyses of space-separated words in the input string,",
"using the morphological analyser of the actual grammar (see command pg)"
"Prints all the analyses of words in the input string.",
"By default it assumes that the input consists of a single lexical expression,",
"but if one of the options bellow is used then the command tries to",
"separate the text into units. Some of the units may be multi-word expressions,",
"others punctuations, or morphemes not separated by spaces."
],
exec = needPGF $ \opts ts pgf -> do
concr <- optLang pgf opts
case opts of
_ | isOpt "missing" opts ->
return . fromString . unwords .
morphoMissing concr .
concatMap words $ toStrings ts
_ | isOpt "all" opts ->
return . fromString . unlines .
map prCohortAnalysis . concatMap (morphoCohorts id concr) $
toStrings ts
_ | isOpt "longest" opts ->
return . fromString . unlines .
map prCohortAnalysis . concatMap (morphoCohorts filterLongest concr) $
toStrings ts
_ | isOpt "best" opts ->
return . fromString . unlines .
map prCohortAnalysis . concatMap (morphoCohorts filterBest concr) $
toStrings ts
_ | isOpt "known" opts ->
return . fromString . unwords .
morphoKnown concr .
concatMap words $ toStrings ts
concatMap (morphoKnown concr) $
toStrings ts
_ | isOpt "missing" opts ->
return . fromString . unwords .
concatMap (morphoMissing concr) $
toStrings ts
_ -> return . fromString . unlines .
map prMorphoAnalysis . concatMap (morphos pgf opts) .
concatMap words $ toStrings ts,
map prMorphoAnalysis . concatMap (morphos pgf opts) $
toStrings ts,
flags = [
("lang","the languages of analysis (comma-separated, no spaces)")
],
options = [
("known", "return only the known words, in order of appearance"),
("missing","show the list of unknown words, in order of appearance")
("all", "scan the text for all words, not just a single one"),
("longest","scan the text for all words, and apply longest match filtering"),
("best", "scan the text for all words, and apply global best match filtering"),
("known", "list all known words, in order of appearance"),
("missing","list all missing words, in order of appearance")
]
}),
@@ -370,7 +396,7 @@ pgfCommands = Map.fromList [
exec = needPGF $ \opts _ pgf -> prGrammar pgf opts,
flags = [
("file", "set the file name when printing with -pgf option"),
("lang", "select languages for the some options (default all languages)"),
("lang", "select languages for some options (default all languages)"),
("printer","select the printing format (see flag values above)")
],
options = [
@@ -381,7 +407,7 @@ pgfCommands = Map.fromList [
("lexc", "print the lexicon in Xerox LEXC format"),
("missing","show just the names of functions that have no linearization"),
("opt", "optimize the generated pgf"),
("pgf", "write current pgf image in file"),
("pgf", "write the current pgf image in a file"),
("words", "print the list of words")
],
examples = [
@@ -562,12 +588,8 @@ pgfCommands = Map.fromList [
nodeEdgeStyle = valStrOpts "nodeedgestyle" "solid" opts,
leafEdgeStyle = valStrOpts "leafedgestyle" "dashed" opts
}
let depfile = valStrOpts "file" "" opts
concr <- optLang pgf opts
mlab <- case depfile of
"" -> return Nothing
_ -> (Just . getDepLabels) `fmap` restricted (readFile depfile)
let grphs = map (graphvizDependencyTree "dot" False mlab Nothing concr) es
let grphs = map (graphvizParseTree concr gvOptions) es
if isFlag "view" opts || isFlag "format" opts
then do
let view = optViewGraph opts
@@ -624,8 +646,8 @@ pgfCommands = Map.fromList [
mapM_ putStrLn ss
return void
else do
let funs = not (isOpt "nofun" opts)
let cats = not (isOpt "nocat" opts)
let funs = isOpt "nofun" opts
let cats = isOpt "nocat" opts
let grphs = map (graphvizAbstractTree pgf (graphvizDefaults{noFun=funs,noCat=cats})) es
if isFlag "view" opts || isFlag "format" opts
then do
@@ -654,19 +676,19 @@ pgfCommands = Map.fromList [
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.",
"The command has one argument which is either a function, an 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."
"If a whole expression is given, then it prints the expression with refined",
"metavariables as well as the type of the expression."
],
exec = needPGF $ \opts arg pgf -> do
case toExprs arg of
[e] -> case unApp e of
Just (id, []) -> case functionType pgf id of
Just ty -> do putStrLn (showFun pgf id ty)
putStrLn ("Probability: "++show (treeProbability pgf e))
putStrLn ("Probability: "++show (exprProbability pgf e))
return void
Nothing -> case categoryContext pgf id of
Just hypos -> do putStrLn ("cat "++id++if null hypos then "" else ' ':showContext [] hypos)
@@ -679,21 +701,79 @@ pgfCommands = Map.fromList [
Nothing -> do putStrLn ("unknown category of function identifier "++show id)
return void
_ -> case inferExpr pgf e of
Left err -> error err
Left err -> errorWithoutStackTrace err
Right (e,ty) -> do putStrLn ("Expression: "++showExpr [] e)
putStrLn ("Type: "++showType [] ty)
putStrLn ("Probability: "++show (treeProbability pgf e))
putStrLn ("Probability: "++show (exprProbability pgf e))
return void
_ -> do putStrLn "a single identifier or expression is expected from the command"
return void,
needsTypeCheck = False
}),
("c", emptyCommandInfo {
longname = "create",
syntax = "create fun f = ..; create cat c = ..; create concrete l; create lin c = ..; or create lincat c = ..",
synopsis = "Dynamically adds new functions, categories and languages to the current grammar.",
explanation = unlines [
"After the command you can write fun, data, cat, concrete, lin or a lincat definition.",
"The syntax is the same as if the definition was in a module. If you want to use",
"any operations inside lin and lincat, you should import them",
"by using the command `i -resource <file path>`."
],
flags = [
("lang","the language to which to add a lin or a lincat"),
("prob","the probability for a new abstract function")
],
needsTypeCheck = False
}),
("a", emptyCommandInfo {
longname = "alter",
syntax = "alter lin f = ..",
synopsis = "Dynamically updates the linearization of a function in the current grammar.",
explanation = unlines [
"The syntax is the same as if the definition was in a module. If you want to use",
"any operations inside the lin definition, you should import them",
"by using the command `i -resource <file path>`."
],
flags = [
("lang","the language in which to alter the lin")
],
needsTypeCheck = False
}),
("d", emptyCommandInfo {
longname = "drop",
syntax = "drop fun f; drop cat c; drop concrete l; drop lin c; or drop lincat c",
synopsis = "Dynamically removes functions, categories and languages from the current grammar.",
explanation = unlines [
"After the command you must specify whether you want to remove",
"fun, data, cat, concrete, lin or a lincat definition.",
"Note that if you are removing an abstract function or category,",
"then all corresponding linearizations will be dropped as well."
],
flags = [
("lang","the language from which to remove the lin or the lincat")
],
needsTypeCheck = False
}),
("t", emptyCommandInfo {
longname = "transaction",
syntax = "transaction (start|commit|rollback)",
synopsis = "Starts, commits or rollbacks a transaction",
explanation = unlines [
"If there is no active transaction, each create and drop command",
"starts its own transaction. Start it manually",
"if you want to perform several operations in one transaction.",
"This also makes batch operations a lot faster."
],
flags = [],
needsTypeCheck = False
})
]
where
needPGF exec opts ts = do
mb_pgf <- getPGF
case mb_pgf of
Just pgf -> liftSIO $ exec opts ts pgf
Just pgf -> do liftSIO $ exec opts ts pgf
_ -> fail "Import a grammar before using this command"
joinPiped (Piped (es1,ms1)) (Piped (es2,ms2)) = Piped (jA es1 es2,ms1+++-ms2)
@@ -718,13 +798,17 @@ pgfCommands = Map.fromList [
linear :: [Option] -> Concr -> Expr -> [String]
linear opts concr = case opts of
_ | isOpt "all" opts -> concat .
map (map snd) . tabularLinearizeAll concr
_ | isOpt "list" opts -> (:[]) . commaList . concat .
map (map snd) . tabularLinearizeAll concr
_ | isOpt "table" opts -> concat .
map (map (\(p,v) -> p+++":"+++v)) . tabularLinearizeAll concr
_ | isOpt "list" opts &&
isOpt "all" opts -> map (commaList . map snd) . tabularLinearizeAll concr
_ | isOpt "list" opts -> (:[]) . commaList .
map snd . tabularLinearize concr
_ | isOpt "table" opts &&
isOpt "all" opts -> map (\(p,v) -> p+++":"+++v) . concat . tabularLinearizeAll concr
_ | isOpt "table" opts -> map (\(p,v) -> p+++":"+++v) . tabularLinearize concr
_ | isOpt "bracket" opts &&
isOpt "all" opts -> map (unwords . map showBracketedString) . bracketedLinearizeAll concr
_ | isOpt "bracket" opts -> (:[]) . unwords . map showBracketedString . bracketedLinearize concr
_ | isOpt "all" opts -> linearizeAll concr
_ -> (:[]) . linearize concr
-- replace each non-atomic constructor with mkC, where C is the val cat
@@ -750,8 +834,9 @@ pgfCommands = Map.fromList [
optLangsFlag flag pgf opts =
case valStrOpts flag "" opts of
"" -> Map.elems langs
str -> mapMaybe (completeLang pgf) (chunks ',' str)
"no" -> []
"" -> Map.elems langs
str -> mapMaybe (completeLang pgf) (chunks ',' str)
where
langs = languages pgf
@@ -769,11 +854,15 @@ pgfCommands = Map.fromList [
Nothing -> error ("Can't parse '"++str++"' as a type")
in maybeStrOpts "cat" (startCat pgf) readOpt opts
optViewFormat opts = valStrOpts "format" "png" opts
optViewGraph opts = valStrOpts "view" "open" opts
optViewGraph opts = valStrOpts "view" open_cmd opts
optNum opts = valIntOpts "number" 1 opts
optNumInf opts = valIntOpts "number" 1000000000 opts ---- 10^9
takeOptNum opts = take (optNumInf opts)
open_cmd | os == "linux" = "xdg-open"
| os == "mingw32" = "start"
| otherwise = "open"
returnFromExprs show_p es =
return $
case es of
@@ -783,7 +872,7 @@ pgfCommands = Map.fromList [
prGrammar pgf opts
| isOpt "pgf" opts = do
let outfile = valStrOpts "file" (abstractName pgf ++ ".pgf") opts
restricted $ writePGF outfile pgf
restricted $ writePGF outfile pgf (Just (map concreteName (optLangs pgf opts)))
putStrLn $ "wrote file " ++ outfile
return void
| isOpt "cats" opts = return $ fromString $ unwords $ categories pgf
@@ -800,12 +889,23 @@ pgfCommands = Map.fromList [
showFun pgf id ty = kwd++" "++ id ++ " : " ++ showType [] ty
where
kwd | functionIsDataCon pgf id = "data"
| otherwise = "fun"
kwd | functionIsConstructor pgf id = "data"
| otherwise = "fun"
morphos pgf opts s =
[(s,lookupMorpho concr s) | concr <- optLangs pgf opts]
morphoCohorts f concr s = f (lookupCohorts concr s)
morphoKnown = morphoClassify True
morphoMissing = morphoClassify False
morphoClassify k concr s =
[w | (_,w,ans,_) <- lookupCohorts concr s, k /= null ans, notLiteral w]
where
notLiteral w = not (all isDigit w)
optClitics opts = case valStrOpts "clitics" "" opts of
"" -> []
cs -> map reverse $ chunks ',' cs
@@ -816,19 +916,9 @@ pgfCommands = Map.fromList [
-- 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 x
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)
app (OOpt op) | Just (Left f) <- treeOp pgf op = f
app (OFlag op (LStr x)) | Just (Right f) <- treeOp pgf op = f x
app _ = id
treeOpOptions pgf = [(op,expl) | (op,(expl,Left _)) <- allTreeOps pgf]
treeOpFlags pgf = [(op,expl) | (op,(expl,Right _)) <- allTreeOps pgf]
@@ -868,7 +958,10 @@ prAllWords concr =
unwords [w | (w,_) <- fullFormLexicon concr]
prMorphoAnalysis (w,lps) =
unlines (w:[l ++ " : " ++ p ++ show prob | (l,p,prob) <- lps])
unlines (w:[l ++ " : " ++ p ++ " " ++ show prob | (l,p,prob) <- lps])
prCohortAnalysis (i,w,lps,j) =
unlines ((show i++"-"++show j++" "++w):[l ++ " : " ++ p ++ " " ++ show prob | (l,p,prob) <- lps])
viewGraphviz :: String -> String -> String -> [String] -> SIO CommandOutput
viewGraphviz view format name grphs = do

View File

@@ -0,0 +1,95 @@
module GF.Command.Importing (importGrammar, importSource) where
import PGF2
import PGF2.Transactions
import GF.Compile
import GF.Compile.Multi (readMulti)
import GF.Compile.GetGrammar (getBNFCRules, getEBNFRules)
import GF.Grammar (ModuleName,SourceGrammar) -- for cc command
import GF.Grammar.BNFC
import GF.Grammar.EBNF
import GF.Grammar.CFG
import GF.Compile.CFGtoPGF
import GF.Infra.UseIO(die,tryIOE)
import GF.Infra.Option
import GF.Data.ErrM
import System.FilePath
import System.Directory
import qualified Data.Set as Set
import qualified Data.Map as Map
import Control.Monad(foldM)
import Control.Exception(catch,throwIO)
-- import a grammar in an environment where it extends an existing grammar
importGrammar :: (FilePath -> IO PGF) -> Maybe PGF -> Options -> [FilePath] -> IO (Maybe PGF)
importGrammar readNGF pgf0 opts _
| Just name <- flag optBlank opts = do
mb_ngf_file <- if snd (flag optLinkTargets opts)
then do let fname = name <.> ".ngf"
putStr ("(Boot image "++fname++") ")
return (Just fname)
else do return Nothing
pgf <- newNGF name mb_ngf_file 0
return (Just pgf)
importGrammar readNGF pgf0 _ [] = return pgf0
importGrammar readNGF pgf0 opts fs
| all (extensionIs ".cf") fs = fmap Just $ importCF opts fs getBNFCRules bnfc2cf
| all (extensionIs ".ebnf") fs = fmap Just $ importCF opts fs getEBNFRules ebnf2cf
| all (extensionIs ".gfm") fs = do
ascss <- mapM readMulti fs
let cs = concatMap snd ascss
importGrammar readNGF pgf0 opts cs
| all (\f -> extensionIs ".gf" f || extensionIs ".gfo" f) fs = do
res <- tryIOE $ compileToPGF opts pgf0 fs
case res of
Ok pgf -> return (Just pgf)
Bad msg -> do putStrLn ('\n':'\n':msg)
return pgf0
| all (extensionIs ".pgf") fs = foldM (importPGF opts) pgf0 fs
| all (extensionIs ".ngf") fs = do
case fs of
[f] -> fmap Just $ readNGF f
_ -> die $ "Only one .ngf file could be loaded at a time"
| otherwise = die $ "Don't know what to do with these input files: " ++ unwords fs
where
extensionIs ext = (== ext) . takeExtension
importPGF :: Options -> Maybe PGF -> FilePath -> IO (Maybe PGF)
importPGF opts Nothing f
| snd (flag optLinkTargets opts) = do let f' = replaceExtension f ".ngf"
exists <- doesFileExist f'
if exists
then removeFile f'
else return ()
putStr ("(Boot image "++f'++") ")
mb_probs <- case flag optProbsFile opts of
Nothing -> return Nothing
Just file -> fmap Just (readProbabilitiesFromFile file)
fmap Just (bootNGFWithProbs f mb_probs f')
| otherwise = do mb_probs <- case flag optProbsFile opts of
Nothing -> return Nothing
Just file -> fmap Just (readProbabilitiesFromFile file)
fmap Just (readPGFWithProbs f mb_probs)
importPGF opts (Just pgf) f = fmap Just (modifyPGF pgf (mergePGF f) `catch`
(\e@(PGFError loc msg) ->
if msg == "The abstract syntax names doesn't match"
then do putStrLn (msg++", previous concretes discarded.")
readPGF f
else throwIO e))
importSource :: Options -> Maybe PGF -> [FilePath] -> IO (ModuleName,SourceGrammar)
importSource opts mb_pgf files = batchCompile opts mb_pgf files
-- for different cf formats
importCF opts files get convert = impCF
where
impCF = do
rules <- fmap (convert . concat) $ mapM (get opts) files
startCat <- case rules of
(Rule cat _ _ : _) -> return cat
_ -> fail "empty CFG"
probs <- maybe (return Map.empty) readProbabilitiesFromFile (flag optProbsFile opts)
let pgf = cf2pgf opts (last files) (mkCFG startCat Set.empty rules) probs
return pgf

View File

@@ -0,0 +1,154 @@
module GF.Command.Parse(readCommandLine, readTransactionCommand, pCommand) where
import PGF(pExpr,pIdent)
import PGF2(BindType(..),readType,readContext)
import GF.Infra.Ident(identS)
import GF.Grammar.Grammar(Term(Abs))
import GF.Grammar.Parser(runPartial,pTerm)
import GF.Command.Abstract
import Data.Char(isDigit,isSpace)
import Control.Monad(liftM2)
import Text.ParserCombinators.ReadP
readCommandLine :: String -> Maybe CommandLine
readCommandLine s =
case [x | (x,cs) <- readP_to_S pCommandLine s, all isSpace cs] of
[x] -> Just x
_ -> Nothing
pCommandLine =
(skipSpaces >> char '-' >> char '-' >> pTheRest >> return []) -- comment
<++
(sepBy (skipSpaces >> pPipe) (skipSpaces >> char ';'))
pPipe = sepBy1 (skipSpaces >> pCommand) (skipSpaces >> char '|')
pCommand = (do
cmd <- pIdent <++ (char '%' >> fmap ('%':) pIdent)
skipSpaces
opts <- sepBy pOption skipSpaces
arg <- if getCommandOp cmd `elem` ["cc","sd","so"] then pArgTerm else pArgument
return (Command cmd opts arg)
)
<++ (do
char '?'
skipSpaces
c <- pSystemCommand
return (Command "sp" [OFlag "command" (LStr c)] ANoArg)
)
readTransactionCommand :: String -> Maybe TransactionCommand
readTransactionCommand s =
case [x | (x,cs) <- readP_to_S pTransactionCommand s, all isSpace cs] of
[x] -> Just x
_ -> Nothing
pTransactionCommand = do
skipSpaces
cmd <- pIdent
skipSpaces
opts <- sepBy pOption skipSpaces
skipSpaces
kwd <- pIdent
skipSpaces
case kwd of
"fun" | take 1 cmd == "c" -> do
f <- pIdent
skipSpaces
char ':'
skipSpaces
ty <- readS_to_P (\s -> case readType s of
Just ty -> [(ty,"")]
Nothing -> [])
return (CreateFun opts f ty)
| take 1 cmd == "d" -> do
f <- pIdent
return (DropFun opts f)
"cat" | take 1 cmd == "c" -> do
c <- pIdent
skipSpaces
ctxt <- readS_to_P (\s -> case readContext s of
Just ty -> [(ty,"")]
Nothing -> [])
return (CreateCat opts c ctxt)
| take 1 cmd == "d" -> do
c <- pIdent
return (DropCat opts c)
"concrete"
| take 1 cmd == "c" -> do
name <- pIdent
return (CreateConcrete opts name)
| take 1 cmd == "d" -> do
name <- pIdent
return (DropConcrete opts name)
"lin" | elem (take 1 cmd) ["c","a"] -> do
f <- pIdent
body <- option Nothing $ do
skipSpaces
args <- sepBy pIdent skipSpaces
skipSpaces
char '='
skipSpaces
t <- readS_to_P (\s -> case runPartial pTerm s of
Right (s,t) -> [(t,s)]
_ -> [])
return (Just (foldr (Abs Explicit . identS) t args))
return (CreateLin opts f body (take 1 cmd == "a"))
| take 1 cmd == "d" -> do
f <- pIdent
return (DropLin opts f)
"lincat"
| take 1 cmd == "c" -> do
f <- pIdent
body <- option Nothing $ do
skipSpaces
char '='
skipSpaces
t <- readS_to_P (\s -> case runPartial pTerm s of
Right (s,t) -> [(t,s)]
_ -> [])
return (Just t)
return (CreateLincat opts f body)
| take 1 cmd == "d" -> do
f <- pIdent
return (DropLincat opts f)
_ -> pfail
pOption = do
char '-'
flg <- pIdent
option (OOpt flg) (fmap (OFlag flg) (char '=' >> pValue))
pValue = do
fmap LInt (readS_to_P reads)
<++
fmap LFlt (readS_to_P reads)
<++
fmap LStr (readS_to_P reads)
<++
fmap LStr pFilename
pFilename = liftM2 (:) (satisfy isFileFirst) (munch (not . isSpace)) where
isFileFirst c = not (isSpace c) && not (isDigit c)
pArgument =
option ANoArg
(fmap AExpr pExpr
<++
(skipSpaces >> char '%' >> fmap AMacro pIdent))
pArgTerm = ATerm `fmap` readS_to_P sTerm
where
sTerm s = case runPartial pTerm s of
Right (s,t) -> [(t,s)]
_ -> []
pSystemCommand =
(char '"' >> (manyTill (pEsc <++ get) (char '"')))
<++
pTheRest
where
pEsc = char '\\' >> get
pTheRest = munch (const True)

View File

@@ -1,5 +1,6 @@
-- | Commands requiring source grammar in env
module GF.Command.SourceCommands(HasGrammar(..),sourceCommands) where
import Prelude hiding (putStrLn)
import qualified Prelude as P(putStrLn)
import Data.List(nub,isInfixOf,isPrefixOf)
@@ -7,21 +8,19 @@ import qualified Data.ByteString.UTF8 as UTF8(fromString)
import qualified Data.Map as Map
import GF.Infra.SIO(MonadSIO(..),restricted)
import GF.Infra.Option(modifyFlags,optTrace) --,noOptions
import GF.Data.Operations (chunks,err,raise)
import GF.Text.Pretty(render)
import GF.Infra.Dependencies(depGraph)
import GF.Infra.CheckM
import GF.Text.Pretty(render,pp)
import GF.Data.Str(sstr)
import GF.Data.Operations (chunks,err,raise)
import GF.Grammar hiding (Ident,isPrefixOf)
import GF.Grammar.Analyse
import GF.Grammar.Parser (runP, pExp)
import GF.Grammar.ShowTerm
import GF.Grammar.Lookup (allOpers,allOpersTo)
import GF.Compile.Rename(renameSourceTerm)
import GF.Compile.Compute.Concrete(normalForm,resourceValues)
import GF.Compile.TypeCheck.Concrete as TC(inferLType,ppType)
import GF.Infra.Dependencies(depGraph)
import GF.Infra.CheckM(runCheck)
import GF.Compile.Compute.Concrete2(normalForm,normalFlatForm,Globals(..),stdPredef)
import GF.Compile.TypeCheck.Concrete as TC(inferLType)
import GF.Command.Abstract(Option(..),isOpt,listFlags,valueString,valStrOpts)
import GF.Command.CommandInfo
@@ -38,8 +37,8 @@ sourceCommands = Map.fromList [
explanation = unlines [
"Compute TERM by concrete syntax definitions. Uses the topmost",
"module (the last one imported) to resolve constant names.",
"N.B.1 You need the flag -retain when importing the grammar, if you want",
"the definitions to be retained after compilation.",
"N.B.1 You need the flag -retain or -resource when importing the grammar,",
"if you want the definitions to be available after compilation.",
"N.B.2 The resulting term is not a tree in the sense of abstract syntax",
"and hence not a valid input to a Tree-expecting command.",
"This command must be a line of its own, and thus cannot be a part",
@@ -51,10 +50,10 @@ sourceCommands = Map.fromList [
("one","pick the first strings, if there is any, from records and tables"),
("table","show all strings labelled by parameters"),
("unqual","hide qualifying module names"),
("trace","trace computations")
("flat","expand all variants and show a flat list of terms")
],
needsTypeCheck = False, -- why not True?
exec = withStrings compute_concrete
exec = withTerm compute_concrete
}),
("dg", emptyCommandInfo {
longname = "dependency_graph",
@@ -101,7 +100,7 @@ sourceCommands = Map.fromList [
mkEx "sd -size ParadigmsEng.mkV -- show all constants on which mkV depends, together with size"
],
needsTypeCheck = False,
exec = withStrings show_deps
exec = withTerm show_deps
}),
("so", emptyCommandInfo {
@@ -110,8 +109,9 @@ sourceCommands = Map.fromList [
synopsis = "show all operations in scope, possibly restricted to a value type",
explanation = unlines [
"Show the names and type signatures of all operations available in the current resource.",
"This command requires a source grammar to be in scope, imported with 'import -retain'.",
"The operations include the parameter constructors that are in scope.",
"If no grammar is loaded with 'import -retain' or 'import -resource',",
"then only the predefined operations are in scope.",
"The operations include also the parameter constructors that are in scope.",
"The optional TYPE filters according to the value type.",
"The grep STRINGs filter according to other substrings of the type signatures."{-,
"This command must be a line of its own, and thus cannot be a part",
@@ -129,7 +129,7 @@ sourceCommands = Map.fromList [
mkEx "so | wf -file=/tmp/opers -- write the list of opers to a file"
],
needsTypeCheck = False,
exec = withStrings show_operations
exec = withTerm show_operations
}),
("ss", emptyCommandInfo {
@@ -162,15 +162,15 @@ sourceCommands = Map.fromList [
do sgr <- getGrammar
liftSIO (exec opts (toStrings ts) sgr)
compute_concrete opts ws sgr =
case runP pExp (UTF8.fromString s) of
Left (_,msg) -> return $ pipeMessage msg
Right t -> return $ err pipeMessage
(fromString . showTerm sgr style q)
$ checkComputeTerm opts sgr t
withTerm exec opts ts =
do sgr <- getGrammar
liftSIO (exec opts (toTerm ts) sgr)
compute_concrete opts t sgr = fmap fst $ runCheck $ do
ts <- checkComputeTerm opts sgr t
return (fromStrings (map (showTerm sgr style q) ts))
where
(style,q) = pOpts TermPrintDefault Qualified opts
s = unwords ws
pOpts style q [] = (style,q)
pOpts style q (o:os) =
@@ -184,12 +184,8 @@ sourceCommands = Map.fromList [
OOpt "qual" -> pOpts style Qualified os
_ -> pOpts style q os
show_deps os xs sgr = do
ops <- case xs of
_:_ -> do
let ts = [t | Right t <- map (runP pExp . UTF8.fromString) xs]
err error (return . nub . concat) $ mapM (constantDepsTerm sgr) ts
_ -> error "expected one or more qualified constants as argument"
show_deps os t sgr = do
ops <- err error (return . nub) $ constantDepsTerm sgr t
let prTerm = showTerm sgr TermPrintDefault Qualified
let size = sizeConstant sgr
let printed
@@ -200,24 +196,15 @@ sourceCommands = Map.fromList [
| otherwise = unwords $ map prTerm ops
return $ fromString printed
show_operations os ts sgr =
case greatestResource sgr of
Nothing -> return $ fromString "no source grammar in scope; did you import with -retain?"
Just mo -> do
let greps = map valueString (listFlags "grep" os)
let isRaw = isOpt "raw" os
ops <- case ts of
_:_ -> do
let Right t = runP pExp (UTF8.fromString (unwords ts))
ty <- err error return $ checkComputeTerm os sgr t
return $ allOpersTo sgr ty
_ -> return $ allOpers sgr
let sigs = [(op,ty) | ((mo,op),ty,pos) <- ops]
let printer = if isRaw
then showTerm sgr TermPrintDefault Qualified
else (render . TC.ppType)
let printed = [unwords [showIdent op, ":", printer ty] | (op,ty) <- sigs]
return . fromString $ unlines [l | l <- printed, all (`isInfixOf` l) greps]
show_operations os t sgr = fmap fst $ runCheck $ do
let greps = map valueString (listFlags "grep" os)
ops <- do tys <- checkComputeTerm os sgr t
return $ concatMap (allOpersTo sgr) tys
let sigs = [(op,ty) | ((mo,op),ty,pos) <- ops]
printer = showTerm sgr TermPrintDefault
(if isOpt "raw" os then Qualified else Unqualified)
printed = [unwords [showIdent op, ":", printer ty] | (op,ty) <- sigs]
return . fromString $ unlines [l | l <- printed, all (`isInfixOf` l) greps]
show_source os ts sgr = do
let strip = if isOpt "strip" os then stripSourceGrammar else id
@@ -254,16 +241,20 @@ sourceCommands = Map.fromList [
return void
checkComputeTerm os sgr t =
do mo <- maybe (raise "no source grammar in scope") return $
greatestResource sgr
((t,_),_) <- runCheck $ do t <- renameSourceTerm sgr mo t
inferLType sgr [] t
let opts = modifyFlags (\fs->fs{optTrace=isOpt "trace" os})
t1 = normalForm (resourceValues opts sgr) (L NoLoc identW) t
t2 = evalStr t1
checkPredefError t2
do mo <- case greatestResource sgr of
Nothing -> checkError (pp "No source grammar in scope")
Just mo -> return mo
t <- renameSourceTerm sgr mo t
(t,_) <- inferLType g t
if isOpt "flat" os
then fmap (map evalStr) (normalFlatForm g t)
else fmap (singleton . evalStr) (normalForm g t)
where
-- ** Try to compute pre{...} tokens in token sequences
singleton x = [x]
g = Gl sgr (stdPredef g)
evalStr t =
case t of
C t1 t2 -> foldr1 C (evalC [t])

View File

@@ -1,42 +1,50 @@
module GF.Compile (compileToPGF, link, batchCompile, srcAbsName) where
import GF.Compile.GeneratePMCFG(generatePMCFG)
import GF.Compile.GrammarToPGF(grammar2PGF)
import GF.Compile.ReadFiles(ModEnv,getOptionsFromFile,getAllFiles,
importsOfModule)
import GF.CompileOne(compileOne)
import GF.Grammar.Grammar(Grammar,emptyGrammar,
abstractOfConcrete,prependModule)--,msrc,modules
import GF.Grammar.Grammar(Grammar,emptyGrammar,modules,mGrammar,
abstractOfConcrete,prependModule,ModuleInfo(..))
import GF.Infra.CheckM
import GF.Infra.Ident(ModuleName,moduleNameS)--,showIdent
import GF.Infra.Option
import GF.Infra.UseIO(IOE,FullPath,liftIO,getLibraryDirectory,putIfVerb,
justModuleName,extendPathEnv,putStrE,putPointE)
justModuleName,extendPathEnv,putStrE,putPointE,warnOut)
import GF.Data.Operations(raise,(+++),err)
import Control.Monad(foldM,when,(<=<))
import GF.System.Directory(doesFileExist,getModificationTime)
import GF.System.Directory(getCurrentDirectory,doesFileExist,getModificationTime)
import System.FilePath((</>),isRelative,dropFileName)
import qualified Data.Map as Map(empty,insert,elems) --lookup
import qualified Data.Map as Map(empty,singleton,insert,elems)
import Data.List(nub)
import Data.Time(UTCTime)
import GF.Text.Pretty(render,($$),(<+>),nest)
import PGF2(PGF,readProbabilitiesFromFile)
import PGF2(PGF,abstractName,pgfFilePath,readProbabilitiesFromFile)
-- | Compiles a number of source files and builds a 'PGF' structure for them.
-- This is a composition of 'link' and 'batchCompile'.
compileToPGF :: Options -> [FilePath] -> IOE PGF
compileToPGF opts fs = link opts . snd =<< batchCompile opts fs
compileToPGF :: Options -> Maybe PGF -> [FilePath] -> IOE PGF
compileToPGF opts mb_pgf fs = link opts mb_pgf =<< batchCompile opts mb_pgf fs
-- | Link a grammar into a 'PGF' that can be used to 'PGF.linearize' and
-- 'PGF.parse' with the "PGF" run-time system.
link :: Options -> (ModuleName,Grammar) -> IOE PGF
link opts (cnc,gr) =
link :: Options -> Maybe PGF -> (ModuleName,Grammar) -> IOE PGF
link opts mb_pgf (cnc,gr) =
putPointE Normal opts "linking ... " $ do
let abs = srcAbsName gr cnc
-- if a module was compiled with no-pmcfg then we generate now
cwd <- getCurrentDirectory
(gr',warnings) <- runCheck' opts (fmap mGrammar $ mapM (generatePMCFG opts cwd gr) (modules gr))
warnOut opts warnings
probs <- liftIO (maybe (return Map.empty) readProbabilitiesFromFile (flag optProbsFile opts))
pgf <- grammar2PGF opts gr abs probs
pgf <- grammar2PGF opts mb_pgf gr' abs probs
when (verbAtLeast opts Normal) $ putStrE "OK"
return pgf
@@ -48,28 +56,17 @@ srcAbsName gr cnc = err (const cnc) id $ abstractOfConcrete gr cnc
-- used, in which case tags files are produced instead).
-- Existing @.gfo@ files are reused if they are up-to-date
-- (unless the option @-src@ aka @-force-recomp@ is used).
batchCompile :: Options -> [FilePath] -> IOE (UTCTime,(ModuleName,Grammar))
batchCompile opts files = do
(gr,menv) <- foldM (compileModule opts) emptyCompileEnv files
batchCompile :: Options -> Maybe PGF -> [FilePath] -> IOE (ModuleName,Grammar)
batchCompile opts mb_pgf files = do
menv <- emptyCompileEnv mb_pgf
(gr,menv) <- foldM (compileModule opts) menv files
let cnc = moduleNameS (justModuleName (last files))
t = maximum . map fst $ Map.elems menv
return (t,(cnc,gr))
{-
-- to compile a set of modules, e.g. an old GF or a .cf file
compileSourceGrammar :: Options -> Grammar -> IOE Grammar
compileSourceGrammar opts gr = do
cwd <- getCurrentDirectory
(_,gr',_) <- foldM (\env -> compileSourceModule opts cwd env Nothing)
emptyCompileEnv
(modules gr)
return gr'
-}
return (cnc,gr)
-- | compile with one module as starting point
-- command-line options override options (marked by --#) in the file
-- As for path: if it is read from file, the file path is prepended to each name.
-- If from command line, it is used as it is.
compileModule :: Options -- ^ Options from program command line and shell command.
-> CompileEnv -> FilePath -> IOE CompileEnv
compileModule opts1 env@(_,rfs) file =
@@ -108,14 +105,25 @@ compileOne' opts env@(gr,_) = extendCompileEnv env <=< compileOne opts gr
-- | The environment
type CompileEnv = (Grammar,ModEnv)
emptyCompileEnv :: CompileEnv
emptyCompileEnv = (emptyGrammar,Map.empty)
emptyCompileEnv :: Maybe PGF -> IOE CompileEnv
emptyCompileEnv mb_pgf = do
case mb_pgf of
Just pgf -> do let abs_name = abstractName pgf
env <- case pgfFilePath pgf of
Just fpath -> do t <- getModificationTime fpath
return (Map.singleton abs_name (fpath,t,[]))
Nothing -> return Map.empty
return ( prependModule emptyGrammar (moduleNameS abs_name, ModPGF pgf)
, env
)
Nothing -> return (emptyGrammar,Map.empty)
extendCompileEnv (gr,menv) (mfile,mo) =
do menv2 <- case mfile of
Just file ->
do let (mod,imps) = importsOfModule mo
t <- getModificationTime file
return $ Map.insert mod (t,imps) menv
return $ Map.insert mod (file,t,imps) menv
_ -> return menv
return (prependModule gr mo,menv2)

View File

@@ -7,7 +7,6 @@ import GF.Infra.Option
import GF.Compile.OptimizePGF
import PGF2
import PGF2.Internal
import qualified Data.Set as Set
import qualified Data.Map as Map
@@ -21,7 +20,7 @@ import Data.Maybe(fromMaybe)
--------------------------
cf2pgf :: Options -> FilePath -> ParamCFG -> Map.Map Fun Double -> PGF
cf2pgf opts fpath cf probs =
cf2pgf opts fpath cf probs = error "TODO: cf2pgf" {-
build (let abstr = cf2abstr cf probs
in newPGF [] aname abstr [(cname, cf2concr opts abstr cf)])
where
@@ -134,3 +133,4 @@ mkRuleName rule =
case ruleName rule of
CFObj n _ -> n
_ -> "_"
-}

View File

@@ -27,9 +27,8 @@ import GF.Infra.Ident
import GF.Infra.Option
import GF.Compile.TypeCheck.Abstract
import GF.Compile.TypeCheck.Concrete(computeLType,checkLType,inferLType,ppType)
import qualified GF.Compile.TypeCheck.ConcreteNew as CN(checkLType,inferLType)
import qualified GF.Compile.Compute.Concrete as CN(normalForm,resourceValues)
import GF.Compile.TypeCheck.Concrete(checkLType,inferLType)
import GF.Compile.Compute.Concrete2(normalForm,Globals(..),stdPredef)
import GF.Grammar
import GF.Grammar.Lexer
@@ -54,11 +53,7 @@ checkModule opts cwd sgr mo@(m,mi) = do
checkCompleteGrammar opts cwd gr (a,abs) mo
_ -> return mo
infoss <- checkInModule cwd mi NoLoc empty $ topoSortJments2 mo
foldM updateCheckInfos mo infoss
where
updateCheckInfos mo = fmap (foldl update mo) . parallelCheck . map check
where check (i,info) = fmap ((,) i) (checkInfo opts cwd sgr mo i info)
update mo@(m,mi) (i,info) = (m,mi{jments=Map.insert i info (jments mi)})
foldM (foldM (checkInfo opts cwd sgr)) mo infoss
-- check if restricted inheritance modules are still coherent
-- i.e. that the defs of remaining names don't depend on omitted names
@@ -69,7 +64,7 @@ checkRestrictedInheritance cwd sgr (name,mo) = checkInModule cwd mo NoLoc empty
-- the restr. modules themself, with restr. infos
mapM_ checkRem mrs
where
mos = modules sgr
mos = [mo | mo@(_,ModInfo{}) <- modules sgr]
checkRem ((i,m),mi) = do
let (incl,excl) = partition (isInherited mi) (Map.keys (jments m))
let incld c = Set.member c (Set.fromList incl)
@@ -120,8 +115,7 @@ checkCompleteGrammar opts cwd gr (am,abs) (cm,cnc) = checkInModule cwd cnc NoLoc
return js
_ -> do
case mb_def of
Ok def -> do (cont,val) <- linTypeOfType gr cm ty
let linty = (snd (valCat ty),cont,val)
Ok def -> do linty <- linTypeOfType gr cm (L loc ty)
return $ Map.insert c (CncFun (Just linty) (Just (L NoLoc def)) Nothing Nothing) js
Bad _ -> do noLinOf c
return js
@@ -140,9 +134,8 @@ checkCompleteGrammar opts cwd gr (am,abs) (cm,cnc) = checkInModule cwd cnc NoLoc
checkCnc js (c,info) =
case info of
CncFun _ d mn mf -> case lookupOrigInfo gr (am,c) of
Ok (_,AbsFun (Just (L _ ty)) _ _ _) ->
do (cont,val) <- linTypeOfType gr cm ty
let linty = (snd (valCat ty),cont,val)
Ok (_,AbsFun (Just (L loc ty)) _ _ _) ->
do linty <- linTypeOfType gr cm (L loc ty)
return $ Map.insert c (CncFun (Just linty) d mn mf) js
_ -> do checkWarn ("function" <+> c <+> "is not in abstract")
return js
@@ -158,130 +151,125 @@ checkCompleteGrammar opts cwd gr (am,abs) (cm,cnc) = checkInModule cwd cnc NoLoc
_ -> return $ Map.insert c info js
-- | General Principle: only Just-values are checked.
-- A May-value has always been checked in its origin module.
checkInfo :: Options -> FilePath -> SourceGrammar -> SourceModule -> Ident -> Info -> Check Info
checkInfo opts cwd sgr (m,mo) c info = checkInModule cwd mo NoLoc empty $ do
checkInfo :: Options -> FilePath -> SourceGrammar -> SourceModule -> (Ident,Info) -> Check SourceModule
checkInfo opts cwd sgr sm (c,info) = checkInModule cwd (snd sm) NoLoc empty $ do
checkReservedId c
case info of
AbsCat (Just (L loc cont)) ->
mkCheck loc "the category" $
checkContext gr cont
AbsFun (Just (L loc typ0)) ma md moper -> do
typ <- compAbsTyp [] typ0 -- to calculate let definitions
AbsFun (Just (L loc typ)) ma md moper -> do
mkCheck loc "the type of function" $
checkTyp gr typ
typ <- compAbsTyp [] typ -- to calculate let definitions
case md of
Just eqs -> mapM_ (\(L loc eq) -> mkCheck loc "the definition of function" $
checkDef gr (m,c) typ eq) eqs
checkDef gr (fst sm,c) typ eq) eqs
Nothing -> return ()
return (AbsFun (Just (L loc typ)) ma md moper)
update sm c (AbsFun (Just (L loc typ)) ma md moper)
CncCat mty mdef mref mpr mpmcfg -> do
mty <- case mty of
Just (L loc typ) -> chIn loc "linearization type of" $
(if False --flag optNewComp opts
then do (typ,_) <- CN.checkLType (CN.resourceValues opts gr) typ typeType
typ <- computeLType gr [] typ
return (Just (L loc typ))
else do (typ,_) <- checkLType gr [] typ typeType
typ <- computeLType gr [] typ
return (Just (L loc typ)))
Just (L loc typ) -> chIn loc "linearization type of" $ do
(typ,_) <- checkLType g typ typeType
typ <- normalForm g typ
return (Just (L loc typ))
Nothing -> return Nothing
mdef <- case (mty,mdef) of
(Just (L _ typ),Just (L loc def)) ->
chIn loc "default linearization of" $ do
(def,_) <- checkLType gr [] def (mkFunType [typeStr] typ)
(def,_) <- checkLType g def (mkFunType [typeStr] typ)
return (Just (L loc def))
_ -> return Nothing
mref <- case (mty,mref) of
(Just (L _ typ),Just (L loc ref)) ->
chIn loc "reference linearization of" $ do
(ref,_) <- checkLType gr [] ref (mkFunType [typ] typeStr)
(ref,_) <- checkLType g ref (mkFunType [typ] typeStr)
return (Just (L loc ref))
_ -> return Nothing
mpr <- case mpr of
(Just (L loc t)) ->
chIn loc "print name of" $ do
(t,_) <- checkLType gr [] t typeStr
(t,_) <- checkLType g t typeStr
return (Just (L loc t))
_ -> return Nothing
return (CncCat mty mdef mref mpr mpmcfg)
update sm c (CncCat mty mdef mref mpr mpmcfg)
CncFun mty mt mpr mpmcfg -> do
mt <- case (mty,mt) of
(Just (cat,cont,val),Just (L loc trm)) ->
(Just (_,cat,cont,val),Just (L loc trm)) ->
chIn loc "linearization of" $ do
(trm,_) <- checkLType gr [] trm (mkFunType (map (\(_,_,ty) -> ty) cont) val) -- erases arg vars
return (Just (L loc trm))
(trm,_) <- checkLType g trm (mkFunType (map (\(_,_,ty) -> ty) cont) val) -- erases arg vars
return (Just (L loc (etaExpand [] trm cont)))
_ -> return mt
mpr <- case mpr of
(Just (L loc t)) ->
chIn loc "print name of" $ do
(t,_) <- checkLType gr [] t typeStr
(t,_) <- checkLType g t typeStr
return (Just (L loc t))
_ -> return Nothing
return (CncFun mty mt mpr mpmcfg)
update sm c (CncFun mty mt mpr mpmcfg)
ResOper pty pde -> do
(pty', pde') <- case (pty,pde) of
(Just (L loct ty), Just (L locd de)) -> do
ty' <- chIn loct "operation" $
(if False --flag optNewComp opts
then CN.checkLType (CN.resourceValues opts gr) ty typeType >>= return . CN.normalForm (CN.resourceValues opts gr) (L loct c) . fst -- !!
else checkLType gr [] ty typeType >>= computeLType gr [] . fst)
ty' <- chIn loct "operation" $ do
(ty,_) <- checkLType g ty typeType
normalForm g ty
(de',_) <- chIn locd "operation" $
(if False -- flag optNewComp opts
then CN.checkLType (CN.resourceValues opts gr) de ty'
else checkLType gr [] de ty')
checkLType g de ty'
return (Just (L loct ty'), Just (L locd de'))
(Nothing , Just (L locd de)) -> do
(de',ty') <- chIn locd "operation" $
(if False -- flag optNewComp opts
then CN.inferLType (CN.resourceValues opts gr) de
else inferLType gr [] de)
inferLType g de
return (Just (L locd ty'), Just (L locd de'))
(Just (L loct ty), Nothing) -> do
chIn loct "operation" $
checkError (pp "No definition given to the operation")
return (ResOper pty' pde')
update sm c (ResOper pty' pde')
ResOverload os tysts -> chIn NoLoc "overloading" $ do
tysts' <- mapM (uncurry $ flip (\(L loc1 t) (L loc2 ty) -> checkLType gr [] t ty >>= \(t,ty) -> return (L loc1 t, L loc2 ty))) tysts -- return explicit ones
tysts0 <- lookupOverload gr (m,c) -- check against inherited ones too
tysts1 <- mapM (uncurry $ flip (checkLType gr []))
[(mkFunType args val,tr) | (args,(val,tr)) <- tysts0]
tysts' <- mapM (uncurry $ flip (\(L loc1 t) (L loc2 ty) -> checkLType g t ty >>= \(t,ty) -> return (L loc1 t, L loc2 ty))) tysts -- return explicit ones
tysts0 <- lookupOverload gr (fst sm,c) -- check against inherited ones too
tysts1 <- sequence
[checkLType g tr (mkFunType args val) | (args,(val,tr)) <- tysts0]
--- this can only be a partial guarantee, since matching
--- with value type is only possible if expected type is given
checkUniq $
sort [let (xs,t) = typeFormCnc x in t : map (\(b,x,t) -> t) xs | (_,x) <- tysts1]
return (ResOverload os [(y,x) | (x,y) <- tysts'])
--checkUniq $
-- sort [let (xs,t) = typeFormCnc x in t : map (\(b,x,t) -> t) xs | (_,x) <- tysts1]
update sm c (ResOverload os [(y,x) | (x,y) <- tysts'])
ResParam (Just (L loc pcs)) _ -> do
ts <- chIn loc "parameter type" $
liftM concat $ mapM mkPar pcs
return (ResParam (Just (L loc pcs)) (Just ts))
(sm,cnt,ts,pcs) <- chIn loc "parameter type" $
mkParamValues sm c 0 [] pcs
update sm c (ResParam (Just (L loc pcs)) (Just (ts,cnt)))
_ -> return info
_ -> return sm
where
gr = prependModule sgr (m,mo)
chIn loc cat = checkInModule cwd mo loc ("Happened in" <+> cat <+> c)
gr = prependModule sgr sm
g = Gl gr (stdPredef g)
chIn loc cat = checkInModule cwd (snd sm) loc ("Happened in" <+> cat <+> c)
mkPar (f,co) = do
vs <- liftM sequence $ mapM (\(_,_,ty) -> allParamValues gr ty) co
return $ map (mkApp (QC (m,f))) vs
mkParamValues sm c cnt ts [] = return (sm,cnt,[],[])
mkParamValues sm@(mn,mi) c cnt ts ((p,co):pcs) = do
co <- mapM (\(b,v,ty) -> normalForm g ty >>= \ty -> return (b,v,ty)) co
sm <- case lookupIdent p (jments mi) of
Ok (ResValue (L loc _) _) -> update sm p (ResValue (L loc (mkProdSimple co (QC (mn,c)))) cnt)
Bad msg -> checkError (pp msg)
vs <- liftM sequence $ mapM (\(_,_,ty) -> allParamValues gr ty) co
(sm,cnt,ts,pcs) <- mkParamValues sm c (cnt+length vs) ts pcs
return (sm,cnt,map (mkApp (QC (mn,p))) vs ++ ts,(p,co):pcs)
checkUniq xss = case xss of
x:y:xs
| x == y -> checkError $ "ambiguous for type" <+>
ppType (mkFunType (tail x) (head x))
ppTerm Terse 0 (mkFunType (tail x) (head x))
| otherwise -> checkUniq $ y:xs
_ -> return ()
mkCheck loc cat ss = case ss of
[] -> return info
[] -> return sm
_ -> chIn loc cat $ checkError (vcat ss)
compAbsTyp g t = case t of
@@ -296,35 +284,50 @@ checkInfo opts cwd sgr (m,mo) c info = checkInModule cwd mo NoLoc empty $ do
Abs _ _ _ -> return t
_ -> composOp (compAbsTyp g) t
etaExpand xs t [] = t
etaExpand xs (Abs bt x t) (_ :cont) = Abs bt x (etaExpand (x:xs) t cont)
etaExpand xs t ((bt,_,ty):cont) = Abs bt x (etaExpand (x:xs) (App t (Vr x)) cont)
where
x = freeVar 1 xs
freeVar i xs
| elem x xs = freeVar (i+1) xs
| otherwise = x
where
x = identS ("v"++show i)
update (mn,mi) c info = return (mn,mi{jments=Map.insert c info (jments mi)})
-- | for grammars obtained otherwise than by parsing ---- update!!
checkReservedId :: Ident -> Check ()
checkReservedId x =
when (isReservedWord x) $
when (isReservedWord GF x) $
checkWarn ("reserved word used as identifier:" <+> x)
-- auxiliaries
-- | linearization types and defaults
linTypeOfType :: Grammar -> ModuleName -> Type -> Check (Context,Type)
linTypeOfType cnc m typ = do
let (cont,cat) = typeSkeleton typ
val <- lookLin cat
args <- mapM mkLinArg (zip [0..] cont)
return (args, val)
linTypeOfType :: Grammar -> ModuleName -> L Type -> Check ([Ident],Ident,Context,Type)
linTypeOfType cnc m (L loc typ) = do
let (ctxt,res_cat) = typeSkeleton typ
val <- lookLin res_cat
lin_args <- mapM mkLinArg (zip [1..] ctxt)
let (args,arg_cats) = unzip lin_args
return (arg_cats, snd res_cat, args, val)
where
mkLinArg (i,(n,mc@(m,cat))) = do
val <- lookLin mc
let vars = mkRecType varLabel $ replicate n typeStr
symb = argIdent n cat i
rec <- if n==0 then return val else
errIn (render ("extending" $$
nest 2 vars $$
"with" $$
nest 2 val)) $
plusRecType vars val
return (Explicit,symb,rec)
return ((Explicit,varX i,rec),cat)
lookLin (_,c) = checks [ --- rather: update with defLinType ?
lookupLincat cnc m c >>= computeLType cnc []
lookupLincat cnc m c >>= normalForm g
,return defLinType
]
g = Gl cnc (stdPredef g)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,205 @@
-- | Translate concrete syntax to Haskell
module GF.Compile.ConcreteToHaskell(concretes2haskell,concrete2haskell) where
import PGF2(Literal(..))
import Data.List(isPrefixOf,sort,sortOn)
import qualified Data.Map as Map
import GF.Text.Pretty
import GF.Grammar.Predef
import GF.Grammar.Grammar
import GF.Grammar.Macros
import GF.Infra.Ident
import GF.Infra.Option
import GF.Haskell as H
import GF.Compile.GrammarToCanonical
-- | Generate Haskell code for the all concrete syntaxes associated with
-- the named abstract syntax in given the grammar.
concretes2haskell opts absname gr = do
gr <- grammar2canonical opts absname gr
let abstr:concrs = modules gr
return [(filename,render80 $ concrete2haskell opts abstr concr)
| concr@(MN mn,_) <- concrs,
let filename = showIdent mn ++ ".hs" :: FilePath
]
-- | Generate Haskell code for the given concrete module.
-- The only options that make a difference are
-- @-haskell=noprefix@ and @-haskell=variants@.
concrete2haskell opts abstr@(absname,_) concr@(cncname,mi) =
haskPreamble absname cncname $$
vcat (
nl:Comment "--- Parameter types ---":
[paramDef id ps | (id,ResParam (Just (L _ ps)) _) <- Map.toList (jments mi)] ++
nl:Comment "--- Type signatures for linearization functions ---":
[signature id | (id,CncCat _ _ _ _ _) <- Map.toList (jments mi)] ++
nl:Comment "--- Linearization types ---":
[lincatDef id ty | (id,CncCat (Just (L _ ty)) _ _ _ _) <- Map.toList (jments mi)] ++
nl:Comment "--- Linearization functions ---":
concat (Map.elems lindefs) ++
nl:Comment "--- Type classes for projection functions ---":
-- map labelClass (S.toList labels) ++
nl:Comment "--- Record types ---":
[] -- concatMap recordType recs
)
where
nl = Comment ""
signature c = TypeSig lf (Fun abs (pure lin))
where
abs = tcon0 (prefixIdent "A." (gId c))
lin = tcon0 lc
lf = linfunName c
lc = lincatName c
gId :: Ident -> Ident
gId = (if haskellOption opts HaskellNoPrefix then id else prefixIdent "G")
va = haskellOption opts HaskellVariants
pure = if va then ListT else id
haskPreamble :: ModuleName -> ModuleName -> Doc
haskPreamble absname cncname =
"{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, LambdaCase #-}" $$
"module" <+> cncname <+> "where" $$
"import Prelude hiding (Ordering(..))" $$
"import Control.Applicative((<$>),(<*>))" $$
"import qualified" <+> absname <+> "as A" $$
"" $$
"-- | Token sequences, output form linearization functions" $$
"type Str = [Tok] -- token sequence" $$
"" $$
"-- | Tokens" $$
"data Tok = TK String | TP [([Prefix],Str)] Str | BIND | SOFT_BIND | SOFT_SPACE | CAPIT | ALL_CAPIT" $$
" deriving (Eq,Ord,Show)" $$
"" $$
"--- Standard definitions ---" $$
"linString (A.GString s) ="<+>pure "R_s [TK s]" $$
"linInt (A.GInt i) ="<+>pure "R_s [TK (show i)]" $$
"linFloat (A.GFloat x) ="<+>pure "R_s [TK (show x)]" $$
"" $$
"----------------------------------------------------" $$
"-- Automatic translation from GF to Haskell follows" $$
"----------------------------------------------------"
where
pure = if va then brackets else pp
paramDef id pvs = Data (conap0 (gId id)) (map paramCon pvs) derive
where
paramCon (id,ctxt) = ConAp (gId id) [tcon0 (gId cat) | (_,_,QC (_,cat)) <- ctxt]
derive = ["Eq","Ord","Show"]
convLinType (Sort s)
| s == cStr = tcon0 (identS "Str")
convLinType (QC (_,p)) = tcon0 (gId p)
convLinType (RecType lbls) = tcon (rcon' ls) (map convLinType ts)
where (ls,ts) = unzip $ sortOn fst lbls
convLinType (Table pt lt) = Fun (convLinType pt) (convLinType lt)
lincatDef c ty = tsyn0 (lincatName c) (convLinType ty)
lindefs =
Map.fromListWith (++)
[linDef id absctx cat lincat rhs |
(id,CncFun (Just (absctx,cat,_,lincat)) (Just (L _ rhs)) _ _) <- Map.toList (jments mi)]
linDef f absctx cat lincat rhs0 =
(cat,[Eqn (linfunName cat,lhs) rhs'])
where
lhs = [ConP (aId f) (map VarP abs_args)]
aId f = prefixIdent "A." (gId f)
--[C.Type absctx (TypeApp cat _)] = [t | FunDef f' t<-funs, f'==f]
(xs,rhs) = termFormCnc rhs0
abs_args = map abs_arg args
abs_arg = prefixIdent "abs_"
args = map (prefixIdent "g" . snd) xs
rhs' = lets (zipWith letlin args absctx)
(convert rhs)
where
vs = [(x,a)|((_,x),a)<-zip xs args]
letlin a acat =
(a,Ap (Var (linfunName acat)) (Var (abs_arg a)))
convert (Vr v) = Var (gId v)
convert (EInt n) = lit n
convert (EFloat d) = lit d
convert (K s) = single (Const "TK" `Ap` lit s)
convert Empty = List []
convert (App t1 t2) = Ap (convert t1) (convert t2)
convert (R lbls) = aps (rcon ls) (map (convert.snd) ts)
where (ls,ts) = unzip (sortOn fst lbls)
convert (P t lbl) = ap (proj lbl) (convert t)
convert (ExtR t1 t2) = Const "ExtR" -- TODO
convert (T _ cs) = LambdaCase (map ppCase cs)
where
ppCase (p,t) = (convertPatt p,convert t)
convert (V _ ts) = Const "V" -- TODO
convert (S t p)
| va = select_va (convert t) (convert p)
| otherwise = Ap (convert t) (convert p)
where
select_va (List [t]) (List [p]) = Op t "!" p
select_va (List [t]) p = Op t "!$" p
select_va t p = Op t "!*" p
convert (Q (_,id)) = single (Var id)
convert (QC (_,id)) = single (Var id)
convert (C t1 t2)
| va = concat_va (convert t1) (convert t2)
| otherwise = plusplus (convert t1) (convert t2)
where
concat_va (List [List ts1]) (List [List ts2]) = List [List (ts1++ts2)]
concat_va t1 t2 = Op t1 "+++" t2
convert (Glue t1 t2) = Const "Glue"
convert (FV ts)
| va = join (List (map convert ts))
| otherwise = case ts of
[] -> Const "error" `Ap` Const (show "empty variant")
(t:ts) -> convert t
where
join (List [x]) = x
join x = Const "concat" `Ap` x
convert (Alts def alts) = single (Const "TP" `Ap` List (map convAlt alts) `Ap` convert def)
where
convAlt (t1,t2) = Pair (convert t1) (convert t2)
convert (Strs ss) = List (map lit ss)
convert t = error (show t)
convertPatt (PC c ps) = ConP (gId c) (map convertPatt ps)
convertPatt (PP (_,c) ps) = ConP (gId c) (map convertPatt ps)
convertPatt (PV v) = VarP v
convertPatt PW = WildP
convertPatt (PR lbls) = ConP (rcon' ls) (map convertPatt ps)
where (ls,ps) = unzip $ sortOn fst lbls
convertPatt (PString s) = Lit s
convertPatt (PT _ p) = convertPatt p
convertPatt (PAs v p) = AsP v (convertPatt p)
convertPatt (PImplArg p) = convertPatt p
convertPatt (PTilde _) = WildP
convertPatt (PAlt _ _) = WildP -- TODO
convertPatt p = error (show p)
lit s = Const (show s) -- hmm
ap = if va then ap' else Ap
where
ap' (List [f]) x = fmap f x
ap' f x = Op f "<*>" x
fmap f (List [x]) = Ap f x
fmap f x = Op f "<$>" x
aps f [] = f
aps f (a:as) = aps (ap f a) as
proj = Var . identS . proj'
proj' (LIdent l) = "proj_" ++ showRawIdent l
rcon = Var . rcon'
rcon' = identS . rcon_name
rcon_name ls = "R"++concat (sort ['_':showRawIdent l | LIdent l <- ls])
lincatName,linfunName :: Ident -> Ident
lincatName c = prefixIdent "Lin" c
linfunName c = prefixIdent "lin" c

View File

@@ -33,7 +33,7 @@ convertFile conf src file = do
(ex, end) = break (=='"') (tail exend)
in ((unwords (words cat),ex), tail end) -- quotes ignored
pgf = resource_pgf conf
lang = language conf
lang = concrete conf
convEx (cat,ex) = do
appn "("
let typ = maybe (error "no valid cat") id $ readType cat
@@ -61,7 +61,7 @@ convertFile conf src file = do
data ExConfiguration = ExConf {
resource_pgf :: PGF,
verbose :: Bool,
language :: Concr,
concrete :: Concr,
printExp :: Expr -> String
}

View File

@@ -4,7 +4,6 @@ import PGF2
import GF.Compile.PGFtoHaskell
--import GF.Compile.PGFtoAbstract
import GF.Compile.PGFtoJava
import GF.Compile.PGFtoJSON
import GF.Infra.Option
--import GF.Speech.CFG
import GF.Speech.PGFToCFG
@@ -35,7 +34,7 @@ exportPGF opts fmt pgf =
FmtPGFPretty -> multi "txt" (showPGF)
FmtCanonicalGF -> [] -- canon "gf" (render80 . abstract2canonical)
FmtCanonicalJson-> []
FmtJSON -> multi "json" pgf2json
FmtSourceJson -> []
FmtHaskell -> multi "hs" (grammar2haskell opts name)
FmtJava -> multi "java" (grammar2java opts name)
FmtBNF -> single "bnf" bnfPrinter
@@ -50,6 +49,7 @@ exportPGF opts fmt pgf =
FmtSLF -> single "slf" slfPrinter
FmtRegExp -> single "rexp" regexpPrinter
FmtFA -> single "dot" slfGraphvizPrinter
FmtLR -> single "dot" (\_ -> graphvizLRAutomaton)
where
name = fromMaybe (abstractName pgf) (flag optName opts)
@@ -60,4 +60,3 @@ exportPGF opts fmt pgf =
single :: String -> (PGF -> Concr -> String) -> [(FilePath,String)]
single ext pr = [(concreteName cnc <.> ext, pr pgf cnc) | cnc <- Map.elems (languages pgf)]

View File

@@ -4,7 +4,8 @@ module GF.Compile.GenerateBC(generateByteCode) where
import GF.Grammar
import GF.Grammar.Lookup(lookupAbsDef,lookupFunType)
import GF.Data.Operations
import PGF2.Internal(CodeLabel,Instr(..),IVal(..),TailInfo(..),Literal(..))
import PGF2(Literal(..))
import PGF2.ByteCode
import qualified Data.Map as Map
import Data.List(nub,mapAccumL)
import Data.Maybe(fromMaybe)
@@ -18,9 +19,7 @@ generateByteCode gr arity eqs =
b = if arity == 0 || null eqs
then instrs
else CHECK_ARGS arity:instrs
in case bs of
[[FAIL]] -> [] -- in the runtime this is a more efficient variant of [[FAIL]]
_ -> reverse bs
in reverse bs
where
is = push_is (arity-1) arity []

View File

@@ -0,0 +1,364 @@
{-# LANGUAGE BangPatterns, RankNTypes, FlexibleInstances, MultiParamTypeClasses, PatternGuards #-}
----------------------------------------------------------------------
-- |
-- Maintainer : Krasimir Angelov
-- Stability : (stable)
-- Portability : (portable)
--
-- Convert PGF grammar to PMCFG grammar.
--
-----------------------------------------------------------------------------
module GF.Compile.GeneratePMCFG
(generatePMCFG, pmcfgForm, type2fields
) where
import GF.Grammar hiding (VApp,VRecType)
import GF.Grammar.Predef
import GF.Grammar.Lookup
import GF.Infra.CheckM
import GF.Infra.Option
import GF.Text.Pretty
import GF.Compile.Compute.Concrete
import GF.Data.Operations(Err(..))
import PGF2.Transactions
import Control.Monad
import Control.Monad.State
import Control.Monad.ST
import qualified Data.Map.Strict as Map
import qualified Data.Sequence as Seq
import Data.List(mapAccumL,sortOn,sortBy)
import Data.Maybe(fromMaybe,isNothing)
import Data.STRef
generatePMCFG :: Options -> FilePath -> SourceGrammar -> SourceModule -> Check SourceModule
generatePMCFG opts cwd gr cmo@(cm,cmi)
| mstatus cmi == MSComplete && isModCnc cmi && isNothing (mseqs cmi) =
do let gr' = prependModule gr cmo
(js,seqs) <- runStateT (Map.traverseWithKey (\id info -> StateT (addPMCFG opts cwd gr' cmi id info)) (jments cmi)) Map.empty
return (cm,cmi{jments = js, mseqs=Just (mapToSequence seqs)})
| otherwise = return cmo
where
mapToSequence m = Seq.fromList (map fst (sortOn snd (Map.toList m)))
type SequenceSet = Map.Map [Symbol] Int
addPMCFG opts cwd gr cmi id (CncCat mty@(Just (L loc ty)) mdef mref mprn Nothing) seqs = do
(defs,seqs) <-
case mdef of
Nothing -> checkInModule cwd cmi loc ("Happened in the PMCFG generation for the lindef of" <+> id) $ do
term <- mkLinDefault gr ty
pmcfgForm gr term [(Explicit,identW,typeStr)] ty seqs
Just (L loc term) -> checkInModule cwd cmi loc ("Happened in the PMCFG generation for the lindef of" <+> id) $ do
pmcfgForm gr term [(Explicit,identW,typeStr)] ty seqs
(refs,seqs) <-
case mref of
Nothing -> checkInModule cwd cmi loc ("Happened in the PMCFG generation for the linref of" <+> id) $ do
term <- mkLinReference gr ty
pmcfgForm gr term [(Explicit,identW,ty)] typeStr seqs
Just (L loc term) -> checkInModule cwd cmi loc ("Happened in the PMCFG generation for the linref of" <+> id) $ do
pmcfgForm gr term [(Explicit,identW,ty)] typeStr seqs
mprn <- case mprn of
Nothing -> return Nothing
Just (L loc prn) -> checkInModule cwd cmi loc ("Happened in the computation of the print name for" <+> id) $ do
prn <- normalForm (Gl gr stdPredef) prn
return (Just (L loc prn))
return (CncCat mty mdef mref mprn (Just (defs,refs)),seqs)
addPMCFG opts cwd gr cmi id (CncFun mty@(Just (_,cat,ctxt,val)) mlin@(Just (L loc term)) mprn Nothing) seqs = do
(rules,seqs) <-
checkInModule cwd cmi loc ("Happened in the PMCFG generation for" <+> id) $
pmcfgForm gr term ctxt val seqs
mprn <- case mprn of
Nothing -> return Nothing
Just (L loc prn) -> checkInModule cwd cmi loc ("Happened in the computation of the print name for" <+> id) $ do
prn <- normalForm (Gl gr stdPredef) prn
return (Just (L loc prn))
return (CncFun mty mlin mprn (Just rules),seqs)
addPMCFG opts cwd gr cmi id info seqs = return (info,seqs)
pmcfgForm :: Grammar -> Term -> Context -> Type -> SequenceSet -> Check ([Production],SequenceSet)
pmcfgForm gr t ctxt ty seqs = do
res <- runEvalM (Gl gr stdPredef) $ do
(_,args) <- mapAccumM (\arg_no (_,_,ty) -> do
t <- EvalM (\(Gl gr _) k e mt d r msgs -> do (mt,_,t) <- type2metaTerm gr arg_no mt 0 [] ty
k t mt d r msgs)
tnk <- newThunk [] t
return (arg_no+1,tnk))
0 ctxt
v <- eval [] t args
(lins,params) <- flatten v ty ([],[])
lins <- fmap reverse $ mapM str2lin lins
(r,rs,_) <- compute params
args <- zipWithM tnk2lparam args ctxt
vars <- getVariables
let res = LParam r (order rs)
return (vars,args,res,lins)
return (runState (mapM mkProduction res) seqs)
where
tnk2lparam tnk (_,_,ty) = do
v <- force tnk
(_,params) <- flatten v ty ([],[])
(r,rs,_) <- compute params
return (PArg [] (LParam r (order rs)))
compute [] = return (0,[],1)
compute ((v,ty):params) = do
(r, rs ,cnt ) <- param2int v ty
(r',rs',cnt') <- compute params
return (r*cnt'+r',combine' cnt rs cnt' rs',cnt*cnt')
mkProduction (vars,args,res,lins) = do
lins <- mapM getSeqId lins
return (Production vars args res lins)
where
getSeqId :: [Symbol] -> State (Map.Map [Symbol] SeqId) SeqId
getSeqId lin = state $ \m ->
case Map.lookup lin m of
Just seqid -> (seqid,m)
Nothing -> let seqid = Map.size m
in (seqid,Map.insert lin seqid m)
type2metaTerm :: SourceGrammar -> Int -> MetaThunks s -> LIndex -> [(LIndex,(Ident,Type))] -> Type -> ST s (MetaThunks s,Int,Term)
type2metaTerm gr d ms r rs (Sort s) | s == cStr =
return (ms,r+1,TSymCat d r rs)
type2metaTerm gr d ms r rs (RecType lbls) = do
((ms',r'),ass) <- mapAccumM (\(ms,r) (lbl,ty) -> case lbl of
LVar j -> return ((ms,r),(lbl,(Just ty,TSymVar d j)))
lbl -> do (ms',r',t) <- type2metaTerm gr d ms r rs ty
return ((ms',r'),(lbl,(Just ty,t))))
(ms,r) lbls
return (ms',r',R ass)
type2metaTerm gr d ms r rs (Table p q)
| count == 1 = do (ms',r',t) <- type2metaTerm gr d ms r rs q
return (ms',r+(r'-r),T (TTyped p) [(PW,t)])
| null (collectParams q)
= do let pv = varX (length rs+1)
(ms',delta,t) <-
fixST $ \(~(_,delta,_)) ->
do (ms',r',t) <- type2metaTerm gr d ms r ((delta,(pv,p)):rs) q
return (ms',r'-r,t)
return (ms',r+delta*count,T (TTyped p) [(PV pv,t)])
| otherwise = do ((ms',r'),ts) <- mapAccumM (\(ms,r) _ -> do (ms',r',t) <- type2metaTerm gr d ms r rs q
return ((ms',r'),t))
(ms,r) [0..count-1]
return (ms',r+(r'-r),V p ts)
where
collectParams (QC q) = [q]
collectParams (Table _ t) = collectParams t
collectParams t = collectOp collectParams t
count = case allParamValues gr p of
Ok ts -> length ts
Bad msg -> error msg
type2metaTerm gr d ms r rs ty@(QC q) = do
let i = Map.size ms + 1
tnk <- newSTRef (Narrowing i ty)
return (Map.insert i tnk ms,r,Meta i)
type2metaTerm gr d ms r rs ty
| Just n <- isTypeInts ty = do
let i = Map.size ms + 1
tnk <- newSTRef (Narrowing i ty)
return (Map.insert i tnk ms,r,Meta i)
flatten (VR as) (RecType lbls) st = do
foldM collect st lbls
where
collect st (lbl,ty) =
case lookup lbl as of
Just tnk -> do v <- force tnk
flatten v ty st
Nothing -> evalError ("Missing value for label" <+> pp lbl $$
"among" <+> hsep (punctuate (pp ',') (map fst as)))
flatten v@(VT _ env cs) (Table p q) st = do
ts <- getAllParamValues p
foldM collect st ts
where
collect st t = do
tnk <- newThunk [] t
let v0 = VS v tnk []
v <- patternMatch v0 (map (\(p,t) -> (env,[p],[tnk],t)) cs)
flatten v q st
flatten (VV _ tnks) (Table _ q) st = do
foldM collect st tnks
where
collect st tnk = do
v <- force tnk
flatten v q st
flatten v (Sort s) (lins,params) | s == cStr = do
deepForce v
return (v:lins,params)
flatten v ty@(QC q) (lins,params) = do
deepForce v
return (lins,(v,ty):params)
flatten v ty (lins,params)
| Just n <- isTypeInts ty = do deepForce v
return (lins,(v,ty):params)
| otherwise = evalError (pp (showValue v))
deepForce (VR as) = mapM_ (\(lbl,v) -> force v >>= deepForce) as
deepForce (VApp q tnks) = mapM_ (\tnk -> force tnk >>= deepForce) tnks
deepForce (VC v1 v2) = deepForce v1 >> deepForce v2
deepForce (VAlts def alts) = do deepForce def
mapM_ (\(v,_) -> deepForce v) alts
deepForce (VSymCat d r rs) = mapM_ (\(_,(tnk,_)) -> force tnk >>= deepForce) rs
deepForce _ = return ()
str2lin (VApp q [])
| q == (cPredef, cBIND) = return [SymBIND]
| q == (cPredef, cNonExist) = return [SymNE]
| q == (cPredef, cSOFT_BIND) = return [SymSOFT_BIND]
| q == (cPredef, cSOFT_SPACE) = return [SymSOFT_SPACE]
| q == (cPredef, cCAPIT) = return [SymCAPIT]
| q == (cPredef, cALL_CAPIT) = return [SymALL_CAPIT]
str2lin (VStr s) = return [SymKS s]
str2lin (VSymCat d r rs) = do (r, rs) <- compute r rs
return [SymCat d (LParam r (order rs))]
where
compute r' [] = return (r',[])
compute r' ((cnt',(tnk,ty)):tnks) = do
v <- force tnk
(r, rs, cnt) <- param2int v ty
(r',rs') <- compute r' tnks
return (r*cnt'+r',combine cnt' rs rs')
str2lin (VSymVar d r) = return [SymVar d r]
str2lin VEmpty = return []
str2lin (VC v1 v2) = liftM2 (++) (str2lin v1) (str2lin v2)
str2lin v0@(VAlts def alts)
= do def <- str2lin def
alts <- forM alts $ \(v1,v2) -> do
lin <- str2lin v1
ss <- to_strs v2
return (lin,ss)
return [SymKP def alts]
where
to_strs (VStrs vs) = mapM to_str vs
to_strs (VPatt _ _ p) = from_patt p
to_strs v = fail
to_str (VStr s) = return s
to_str _ = fail
from_patt (PAlt p1 p2) = liftM2 (++) (from_patt p1) (from_patt p2)
from_patt (PSeq _ _ p1 _ _ p2) = liftM2 (liftM2 (++)) (from_patt p1) (from_patt p2)
from_patt (PString s) = return [s]
from_patt (PChars cs) = return (map (:[]) cs)
from_patt _ = fail
fail = evalError ("Complex patterns are not supported in:" $$ nest 2 (pp (showValue v0)))
str2lin v = do t <- value2term False [] v
evalError ("the string:" <+> ppTerm Unqualified 0 t $$
"cannot be evaluated at compile time.")
param2int (VR as) (RecType lbls) = compute lbls
where
compute [] = return (0,[],1)
compute ((lbl,ty):lbls) = do
case lookup lbl as of
Just tnk -> do v <- force tnk
(r, rs ,cnt ) <- param2int v ty
(r',rs',cnt') <- compute lbls
return (r*cnt'+r',combine' cnt rs cnt' rs',cnt*cnt')
Nothing -> evalError ("Missing value for label" <+> pp lbl $$
"among" <+> hsep (punctuate (pp ',') (map fst as)))
param2int (VApp q tnks) ty = do
(r , ctxt,cnt ) <- getIdxCnt q
(r',rs', cnt') <- compute ctxt tnks
return (r+r',rs',cnt)
where
getIdxCnt q = do
(_,ResValue (L _ ty) idx) <- getInfo q
let (ctxt,QC p) = typeFormCnc ty
(_,ResParam _ (Just (_,cnt))) <- getInfo p
return (idx,ctxt,cnt)
compute [] [] = return (0,[],1)
compute ((_,_,ty):ctxt) (tnk:tnks) = do
v <- force tnk
(r, rs ,cnt ) <- param2int v ty
(r',rs',cnt') <- compute ctxt tnks
return (r*cnt'+r',combine' cnt rs cnt' rs',cnt*cnt')
param2int (VInt n) ty
| Just max <- isTypeInts ty= return (fromIntegral n,[],fromIntegral max+1)
param2int (VMeta tnk _) ty = do
tnk_st <- getRef tnk
case tnk_st of
Evaluated _ v -> param2int v ty
Narrowing j ty -> do ts <- getAllParamValues ty
return (0,[(1,j-1)],length ts)
param2int v ty = do t <- value2term True [] v
evalError ("the parameter:" <+> ppTerm Unqualified 0 t $$
"cannot be evaluated at compile time.")
combine' 1 rs 1 rs' = []
combine' 1 rs cnt' rs' = rs'
combine' cnt rs 1 rs' = rs
combine' cnt rs cnt' rs' = combine cnt' rs rs'
combine cnt' [] rs' = rs'
combine cnt' rs [] = [(r*cnt',pv) | (r,pv) <- rs]
combine cnt' ((r,pv):rs) ((r',pv'):rs') =
case compare pv pv' of
LT -> (r*cnt', pv ) : combine cnt' rs ((r',pv'):rs')
EQ -> (r*cnt'+r',pv ) : combine cnt' rs ((r',pv'):rs')
GT -> ( r',pv') : combine cnt' ((r,pv):rs) rs'
order = sortBy (\(r1,_) (r2,_) -> compare r2 r1)
mapAccumM f a [] = return (a,[])
mapAccumM f a (x:xs) = do (a, y) <- f a x
(a,ys) <- mapAccumM f a xs
return (a,y:ys)
type2fields :: SourceGrammar -> Type -> [String]
type2fields gr = type2fields empty
where
type2fields d (Sort s) | s == cStr = [show d]
type2fields d (RecType lbls) =
concatMap (\(lbl,ty) -> type2fields (d <+> pp lbl) ty) lbls
type2fields d (Table p q) =
let Ok ts = allParamValues gr p
in concatMap (\t -> type2fields (d <+> ppTerm Unqualified 5 t) q) ts
type2fields d _ = []
mkLinDefault :: SourceGrammar -> Type -> Check Term
mkLinDefault gr typ = liftM (Abs Explicit varStr) $ mkDefField typ
where
mkDefField ty =
case ty of
Table p t -> do t' <- mkDefField t
let T _ cs = mkWildCases t'
return $ T (TWild p) cs
Sort s | s == cStr -> return (Vr varStr)
QC p -> case lookupParamValues gr p of
Ok [] -> checkError ("no parameter values given to type" <+> ppQIdent Qualified p)
Ok (v:_) -> return v
Bad msg -> fail msg
RecType r -> do
let (ls,ts) = unzip r
ts <- mapM mkDefField ts
return $ R (zipWith assign ls ts)
_ | Just _ <- isTypeInts ty -> return $ EInt 0 -- exists in all as first val
_ -> checkError ("a field in a linearization type cannot be" <+> ty)
mkLinReference :: SourceGrammar -> Type -> Check Term
mkLinReference gr typ = do
mb_term <- mkRefField typ (Vr varStr)
return (Abs Explicit varStr (fromMaybe Empty mb_term))
where
mkRefField ty trm =
case ty of
Table pty ty -> case allParamValues gr pty of
Ok [] -> checkError ("no parameter values given to type" <+> pty)
Ok (p:ps) -> mkRefField ty (S trm p)
Bad msg -> fail msg
Sort s | s == cStr -> return (Just trm)
QC p -> return Nothing
RecType rs -> traverse rs trm
_ | Just _ <- isTypeInts ty -> return Nothing
_ -> checkError ("a field in a linearization type cannot be" <+> typ)
traverse [] trm = return Nothing
traverse ((l,ty):rs) trm = do res <- mkRefField ty (P trm l)
case res of
Just trm -> return (Just trm)
Nothing -> traverse rs trm

View File

@@ -0,0 +1,128 @@
-- | Translate grammars to Canonical form
-- (a common intermediate representation to simplify export to other formats)
module GF.Compile.GrammarToCanonical(
grammar2canonical
) where
import GF.Data.ErrM
import GF.Grammar
import GF.Grammar.Lookup(allOrigInfos,lookupOrigInfo)
import GF.Infra.Option(Options,noOptions)
import GF.Infra.CheckM
import GF.Compile.Compute.Concrete2
import qualified Data.Map as Map
import qualified Data.Set as Set
import Data.Maybe(mapMaybe,fromMaybe)
import Control.Monad (forM)
-- | Generate Canonical code for the named abstract syntax and all associated
-- concrete syntaxes
grammar2canonical :: Options -> ModuleName -> Grammar -> Check Grammar
grammar2canonical opts absname gr = do
abs <- abstract2canonical absname gr
cncs <- concretes2canonical opts absname gr
return (mGrammar (abs:cncs))
-- | Generate Canonical code for the named abstract syntax
abstract2canonical :: ModuleName -> Grammar -> Check Module
abstract2canonical absname gr = do
let infos = [(id,info) | ((mn,id),info) <- allOrigInfos gr absname]
return (absname, ModInfo {
mtype = MTAbstract,
mstatus = MSComplete,
mflags = convFlags gr absname,
mextend = [],
mwith = Nothing,
mopens = [],
mexdeps = [],
msrc = "",
mseqs = Nothing,
jments = Map.fromList infos
})
-- | Generate Canonical code for the all concrete syntaxes associated with
-- the named abstract syntax in given the grammar.
concretes2canonical :: Options -> ModuleName -> Grammar -> Check [Module]
concretes2canonical opts absname gr = do
res <- sequence
[concrete2canonical gr absname cnc modinfo
| cnc<-allConcretes gr absname,
let Ok modinfo = lookupModule gr cnc]
let pts = Set.unions (map fst res)
ms <- closure pts (Set.toList pts) (Map.fromList (map snd res))
return (Map.toList ms)
where
closure pts [] ms = return ms
closure pts (q@(m,id):qs) ms = do
(_,info@(ResParam (Just (L _ ps)) _)) <- lookupOrigInfo gr q
let pts' = Set.unions [paramTypes ty | (_,ctx) <- ps, (_,_,ty) <- ctx]
new_pts = Set.difference pts' pts
closure (Set.union new_pts pts) (Set.toList new_pts++qs) (insert q info ms)
insert (m,id) info ms =
let mi0 = fromMaybe emptyRes (Map.lookup m ms)
mi = mi0{jments=Map.insert id info (jments mi0)}
in Map.insert m mi ms
emptyRes =
ModInfo {
mtype = MTResource,
mstatus = MSComplete,
mflags = noOptions,
mextend = [],
mwith = Nothing,
mopens = [],
mexdeps = [],
msrc = "",
mseqs = Nothing,
jments = Map.empty
}
type QSet = Set.Set (ModuleName,Ident)
-- | Generate Canonical GF for the given concrete module.
concrete2canonical :: Grammar -> ModuleName -> ModuleName -> ModuleInfo -> Check (QSet,Module)
concrete2canonical gr absname cncname modinfo = do
let g = Gl gr (stdPredef g)
infos <- mapM (convInfo g) (allOrigInfos gr cncname)
let pts = Set.unions (map fst infos)
return (pts,
(cncname, ModInfo {
mtype = MTConcrete absname,
mstatus = MSComplete,
mflags = convFlags gr cncname,
mextend = [],
mwith = Nothing,
mopens = [],
mexdeps = [],
msrc = "",
mseqs = Nothing,
jments = Map.fromList (mapMaybe snd infos)
}))
where
convInfo g ((mn,id), CncCat (Just (L loc typ)) lindef linref pprn mb_prods) = do
typ <- normalForm g typ
let pts = paramTypes typ
return (pts,Just (id,CncCat (Just (L loc typ)) lindef linref pprn mb_prods))
convInfo g ((mn,id), CncFun mb_ty@(Just r@(_,cat,ctx,lincat)) (Just (L loc def)) pprn mb_prods) = do
def <- normalForm g (eta_expand def ctx)
return (Set.empty,Just (id,CncFun mb_ty (Just (L loc def)) pprn mb_prods))
convInfo g _ = return (Set.empty,Nothing)
eta_expand t [] = t
eta_expand t ((Implicit,x,_):ctx) = Abs Implicit x (eta_expand (App t (ImplArg (Vr x))) ctx)
eta_expand t ((Explicit,x,_):ctx) = Abs Explicit x (eta_expand (App t (Vr x)) ctx)
paramTypes (RecType fs) = Set.unions (map (paramTypes.snd) fs)
paramTypes (Table t1 t2) = Set.union (paramTypes t1) (paramTypes t2)
paramTypes (App tf ta) = Set.union (paramTypes tf) (paramTypes ta)
paramTypes (Sort _) = Set.empty
paramTypes (EInt _) = Set.empty
paramTypes (QC q) = Set.singleton q
paramTypes (FV ts) = Set.unions (map paramTypes ts)
paramTypes _ = Set.empty
convFlags :: Grammar -> ModuleName -> Options
convFlags gr mn = err (const noOptions) mflags (lookupModule gr mn)

View File

@@ -1,4 +1,4 @@
{-# LANGUAGE ImplicitParams, BangPatterns, FlexibleContexts, MagicHash #-}
{-# LANGUAGE BangPatterns, FlexibleContexts, MagicHash #-}
module GF.Compile.GrammarToPGF (grammar2PGF) where
import GF.Compile.GeneratePMCFG
@@ -6,7 +6,7 @@ import GF.Compile.GenerateBC
import GF.Compile.OptimizePGF
import PGF2 hiding (mkType)
import PGF2.Internal
import PGF2.Transactions
import GF.Grammar.Predef
import GF.Grammar.Grammar hiding (Production)
import qualified GF.Grammar.Lookup as Look
@@ -18,113 +18,125 @@ import GF.Infra.Option
import GF.Infra.UseIO (IOE)
import GF.Data.Operations
import Control.Monad(forM_,foldM)
import Data.List
import Data.Char
import qualified Data.Set as Set
import qualified Data.Map as Map
import qualified Data.IntMap as IntMap
import qualified Data.Sequence as Seq
import Data.Array.IArray
import Data.Maybe(fromMaybe)
import System.FilePath
import System.Directory
import GHC.Prim
import GHC.Base(getTag)
grammar2PGF :: Options -> Maybe PGF -> SourceGrammar -> ModuleName -> Map.Map PGF2.Fun Double -> IO PGF
grammar2PGF opts mb_pgf gr am probs = do
let abs_name = mi2i am
pgf <- case mb_pgf of
Just pgf | abstractName pgf == abs_name ->
do return pgf
_ | snd (flag optLinkTargets opts) ->
do let fname = maybe id (</>)
(flag optOutputDir opts)
(fromMaybe abs_name (flag optName opts)<.>"ngf")
exists <- doesFileExist fname
if exists
then removeFile fname
else return ()
putStr ("(Boot image "++fname++") ")
newNGF abs_name (Just fname) 0
| otherwise ->
do newNGF abs_name Nothing 0
grammar2PGF :: Options -> SourceGrammar -> ModuleName -> Map.Map PGF2.Fun Double -> IO PGF
grammar2PGF opts gr am probs = do
cnc_infos <- getConcreteInfos gr am
return $
build (let gflags = if flag optSplitPGF opts
then [("split", LStr "true")]
else []
(an,abs) = mkAbstr am probs
cncs = map (mkConcr opts abs) cnc_infos
in newPGF gflags an abs cncs)
pgf <- modifyPGF pgf $ do
sequence_ [setAbstractFlag name value | (name,value) <- optionsPGF aflags]
sequence_ [createCategory c ctxt p | (c,ctxt,p) <- cats]
sequence_ [createFunction f ty arity bcode p | (f,ty,arity,bcode,p) <- funs]
forM_ (allConcretes gr am) $ \cm ->
createConcrete (mi2i cm) $ do
let cflags = err (const noOptions) mflags (lookupModule gr cm)
sequence_ [setConcreteFlag name value | (name,value) <- optionsPGF cflags]
let infos = ( Seq.fromList [Left [SymCat 0 (LParam 0 [])]]
, let id_prod = Production [] [PArg [] (LParam 0 [])] (LParam 0 []) [0]
prods = ([id_prod],[id_prod])
in [(cInt, CncCat (Just (noLoc GM.defLinType)) Nothing Nothing Nothing (Just prods))
,(cString,CncCat (Just (noLoc GM.defLinType)) Nothing Nothing Nothing (Just prods))
,(cFloat, CncCat (Just (noLoc GM.defLinType)) Nothing Nothing Nothing (Just prods))
]
)
: prepareSeqTbls (Look.allOrigInfos gr cm)
infos <- processInfos createCncCats infos
infos <- processInfos createCncFuns infos
return ()
return pgf
where
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 probs = (mi2i am, newAbstr flags cats funs)
adefs =
[((cPredefAbs,c), AbsCat (Just (L NoLoc []))) | c <- [cFloat,cInt,cString]] ++
Look.allOrigInfos gr am
toLogProb = realToFrac . negate . log
cats = [(c', snd (mkContext [] cont), toLogProb (fromMaybe 0 (Map.lookup c' probs))) |
((m,c),AbsCat (Just (L _ cont))) <- adefs, let c' = i2i c]
funs = [(f', mkType [] ty, arity, bcode, toLogProb (fromMaybe 0 (Map.lookup f' funs_probs))) |
((m,f),AbsFun (Just (L _ ty)) ma mdef _) <- adefs,
let arity = mkArity ma mdef ty,
let bcode = mkDef gr arity mdef,
let f' = i2i f]
funs_probs = (Map.fromList . concat . Map.elems . fmap pad . Map.fromListWith (++))
[(i2i cat,[(i2i f,Map.lookup f' probs)]) | ((m,f),AbsFun (Just (L _ ty)) _ _ _) <- adefs,
let (_,(_,cat),_) = GM.typeForm ty,
let f' = i2i f]
where
adefs =
[((cPredefAbs,c), AbsCat (Just (L NoLoc []))) | c <- [cFloat,cInt,cString]] ++
Look.allOrigInfos gr am
flags = optionsPGF aflags
toLogProb = realToFrac . negate . log
cats = [(c', snd (mkContext [] cont), toLogProb (fromMaybe 0 (Map.lookup c' probs))) |
((m,c),AbsCat (Just (L _ cont))) <- adefs, let c' = i2i c]
funs = [(f', mkType [] ty, arity, bcode, toLogProb (fromMaybe 0 (Map.lookup f' funs_probs))) |
((m,f),AbsFun (Just (L _ ty)) ma mdef _) <- adefs,
let arity = mkArity ma mdef ty,
let bcode = mkDef gr arity mdef,
let f' = i2i f]
funs_probs = (Map.fromList . concat . Map.elems . fmap pad . Map.fromListWith (++))
[(i2i cat,[(i2i f,Map.lookup f' probs)]) | ((m,f),AbsFun (Just (L _ ty)) _ _ _) <- adefs,
let (_,(_,cat),_) = GM.typeForm ty,
let f' = i2i f]
pad :: [(a,Maybe Double)] -> [(a,Double)]
pad pfs = [(f,fromMaybe deflt mb_p) | (f,mb_p) <- pfs]
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)
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) =
let cflags = err (const noOptions) mflags (lookupModule gr cm)
ciCmp | flag optCaseSensitive cflags = compare
| otherwise = compareCaseInsensitive
prepareSeqTbls infos =
(map addSeqTable . Map.toList . Map.fromListWith (++))
[(m,[(c,info)]) | ((m,c),info) <- infos]
where
addSeqTable (m,infos) =
case lookupModule gr m of
Ok mi -> case mseqs mi of
Just seqs -> (fmap Left seqs,infos)
Nothing -> (Seq.empty,[])
Bad msg -> error msg
flags = optionsPGF aflags
processInfos f [] = return []
processInfos f ((seqtbl,infos):rest) = do
seqtbl <- foldM f seqtbl infos
rest <- processInfos f rest
return ((seqtbl,infos):rest)
seqs = (mkSetArray . Set.fromList . concat) $
(elems (ex_seqs :: Array SeqId [Symbol]) : [maybe [] elems (mseqs mi) | (m,mi) <- allExtends gr cm])
createCncCats seqtbl (c,CncCat (Just (L _ ty)) _ _ mprn (Just (lindefs,linrefs))) = do
seqtbl <- createLincat (i2i c) (type2fields gr ty) lindefs linrefs seqtbl
case mprn of
Nothing -> return ()
Just (L _ prn) -> setPrintName (i2i c) (unwords (term2tokens prn))
return seqtbl
createCncCats seqtbl _ = return seqtbl
!(!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)
= genCncFuns gr am cm ex_seqs ciCmp seqs cdefs fid_cnt1 cnccat_ranges
createCncFuns seqtbl (f,CncFun _ _ mprn (Just prods)) = do
seqtbl <- createLin (i2i f) prods seqtbl
case mprn of
Nothing -> return ()
Just (L _ prn) -> setPrintName (i2i f) (unwords (term2tokens prn))
return seqtbl
createCncFuns seqtbl _ = return seqtbl
printnames = genPrintNames cdefs
startCat = (fromMaybe "S" (flag optStartCat aflags))
(lindefs',linrefs',productions',cncfuns',sequences',cnccats') =
(if flag optOptimizePGF opts then optimizePGF startCat else id)
(lindefs,linrefs,productions,cncfuns,elems seqs,cnccats)
in (mi2i cm, newConcr abs
flags
printnames
lindefs'
linrefs'
productions'
cncfuns'
sequences'
cnccats'
fid_cnt2)
getConcreteInfos gr am = mapM flatten (allConcretes gr am)
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
-- we have to create the PMCFG code just before linking
addMissingPMCFGs cm seqs [] = return (seqs,[])
addMissingPMCFGs cm seqs (((m,id), info):is) = do
(seqs,info) <- addPMCFG opts gr cenv Nothing am cm seqs id info
(seqs,infos) <- addMissingPMCFGs cm seqs is
return (seqs, ((m,id), info) : infos)
term2tokens (K tok) = [tok]
term2tokens (C t1 t2) = term2tokens t1 ++ term2tokens t2
term2tokens (Typed t _) = term2tokens t
term2tokens _ = []
i2i :: Ident -> String
i2i = showIdent
@@ -132,27 +144,27 @@ i2i = showIdent
mi2i :: ModuleName -> String
mi2i (MN i) = i2i i
mkType :: (?builder :: Builder s) => [Ident] -> A.Type -> B s PGF2.Type
mkType :: [Ident] -> A.Type -> PGF2.Type
mkType scope t =
case GM.typeForm t of
(hyps,(_,cat),args) -> let (scope',hyps') = mkContext scope hyps
in dTyp hyps' (i2i cat) (map (mkExp scope') args)
in DTyp hyps' (i2i cat) (map (mkExp scope') args)
mkExp :: (?builder :: Builder s) => [Ident] -> A.Term -> B s Expr
mkExp :: [Ident] -> A.Term -> Expr
mkExp scope t =
case t of
Q (_,c) -> eFun (i2i c)
QC (_,c) -> eFun (i2i c)
Q (_,c) -> EFun (i2i c)
QC (_,c) -> EFun (i2i c)
Vr x -> case lookup x (zip scope [0..]) of
Just i -> eVar i
Nothing -> eMeta 0
Abs b x t-> eAbs b (i2i x) (mkExp (x:scope) t)
App t1 t2-> eApp (mkExp scope t1) (mkExp scope t2)
EInt i -> eLit (LInt (fromIntegral i))
EFloat f -> eLit (LFlt f)
K s -> eLit (LStr s)
Meta i -> eMeta i
_ -> eMeta 0
Just i -> EVar i
Nothing -> EMeta 0
Abs b x t-> EAbs b (i2i x) (mkExp (x:scope) t)
App t1 t2-> EApp (mkExp scope t1) (mkExp scope t2)
EInt i -> ELit (LInt (fromIntegral i))
EFloat f -> ELit (LFlt f)
K s -> ELit (LStr s)
Meta i -> EMeta i
_ -> EMeta 0
{-
mkPatt scope p =
case p of
@@ -169,11 +181,12 @@ mkPatt scope p =
in (scope',C.PImplArg p')
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],[PGF2.Hypo])
mkContext scope hyps = mapAccumL (\scope (bt,x,ty) -> let ty' = mkType scope ty
in if x == identW
then ( scope,hypo bt (i2i x) ty')
else (x:scope,hypo bt (i2i x) ty')) scope hyps
then ( scope,(bt,i2i x,ty'))
else (x:scope,(bt,i2i x,ty'))) scope hyps
mkDef gr arity (Just eqs) = generateByteCode gr arity eqs
mkDef gr arity Nothing = []
@@ -182,7 +195,7 @@ 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 _ ty = let (ctxt, _, _) = GM.typeForm ty -- constructor
in length ctxt
{-
genCncCats gr am cm cdefs = mkCncCats 0 cdefs
where
mkCncCats index [] = (index,[])
@@ -445,3 +458,4 @@ compareCaseInsensitive (x:xs) (y:ys) =
EQ -> compare x y
x -> x
x -> x
-}

View File

@@ -2,7 +2,7 @@
module GF.Compile.OptimizePGF(optimizePGF) where
import PGF2(Cat,Fun)
import PGF2.Internal
import PGF2.Transactions
import Data.Array.ST
import Data.Array.Unboxed
import qualified Data.Map as Map
@@ -12,15 +12,16 @@ import qualified Data.IntMap as IntMap
import qualified Data.List as List
import Control.Monad.ST
type ConcrData = ([(FId,[FunId])], -- ^ Lindefs
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
optimizePGF startCat = error "TODO: optimizePGF" {- topDownFilter startCat . bottomUpFilter
catString = "String"
catInt = "Int"
@@ -187,3 +188,4 @@ filterProductions prods0 hoc0 prods
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

@@ -17,7 +17,6 @@
module GF.Compile.PGFtoHaskell (grammar2haskell) where
import PGF2
import PGF2.Internal
import GF.Data.Operations
import GF.Infra.Option
@@ -40,7 +39,6 @@ grammar2haskell opts name gr = foldr (++++) [] $
where gr' = hSkeleton gr
gadt = haskellOption opts HaskellGADT
dataExt = haskellOption opts HaskellData
pgf2 = haskellOption opts HaskellPGF2
lexical cat = haskellOption opts HaskellLexical && isLexicalCat opts cat
gId | haskellOption opts HaskellNoPrefix = rmForbiddenChars
| otherwise = ("G"++) . rmForbiddenChars
@@ -55,8 +53,7 @@ grammar2haskell opts name gr = foldr (++++) [] $
extraImports | gadt = ["import Control.Monad.Identity", "import Data.Monoid"]
| dataExt = ["import Data.Data"]
| otherwise = []
pgfImports | pgf2 = ["import PGF2 hiding (Tree)", "", "showCId :: CId -> String", "showCId = id"]
| otherwise = ["import PGF hiding (Tree)"]
pgfImports = ["import PGF2", ""]
types | gadt = datatypesGADT gId lexical gr'
| otherwise = datatypes gId derivingClause lexical gr'
compos | gadt = prCompos gId lexical gr' ++ composClass
@@ -79,7 +76,7 @@ haskPreamble gadt name derivingClause imports =
"",
predefInst gadt derivingClause "GString" "String" "unStr" "mkStr",
"",
predefInst gadt derivingClause "GInt" "Int" "unInt" "mkInt",
predefInst gadt derivingClause "GInt" "Integer" "unInt" "mkInt",
"",
predefInst gadt derivingClause "GFloat" "Double" "unFloat" "mkFloat",
"",
@@ -235,14 +232,14 @@ hInstance gId lexical m (cat,rules)
| otherwise =
"instance Gf" +++ gId cat +++ "where\n" ++
unlines ([mkInst f xx | (f,xx) <- nonLexicalRules (lexical cat) rules]
++ if lexical cat then [" gf (" ++ lexicalConstructor cat +++ "x) = mkApp (mkCId x) []"] else [])
++ if lexical cat then [" gf (" ++ lexicalConstructor cat +++ "x) = mkApp x []"] else [])
where
ec = elemCat cat
baseVars = mkVars (baseSize (cat,rules))
mkInst f xx = let xx' = mkVars (length xx) in " gf " ++
(if null xx then gId f else prParenth (gId f +++ foldr1 (+++) xx')) +++
"=" +++ mkRHS f xx'
mkRHS f vars = "mkApp (mkCId \"" ++ f ++ "\")" +++
mkRHS f vars = "mkApp \"" ++ f ++ "\"" +++
"[" ++ prTList ", " ["gf" +++ x | x <- vars] ++ "]"
mkVars :: Int -> [String]
@@ -266,7 +263,7 @@ fInstance gId lexical m (cat,rules) =
mkInst f xx =
" Just (i," ++
"[" ++ prTList "," xx' ++ "])" +++
"| i == mkCId \"" ++ f ++ "\" ->" +++ mkRHS f xx'
"| i == \"" ++ f ++ "\" ->" +++ mkRHS f xx'
where
xx' = ["x" ++ show i | (_,i) <- zip xx [1..]]
mkRHS f vars

View File

@@ -50,7 +50,7 @@ import System.FilePath
import GF.Text.Pretty
type ModName = String
type ModEnv = Map.Map ModName (UTCTime,[ModName])
type ModEnv = Map.Map ModName (FilePath,UTCTime,[ModName])
-- | Returns a list of all files to be compiled in topological order i.e.
@@ -98,14 +98,17 @@ getAllFiles opts ps env file = do
-- returns 'ModuleInfo'. It fails if there is no such module
--findModule :: ModName -> IOE ModuleInfo
findModule name = do
(file,gfTime,gfoTime) <- findFile gfoDir ps name
(file,gfTime,gfoTime) <- findFile gfoDir ps env name
let mb_envmod = Map.lookup name env
(st,t) = selectFormat opts (fmap fst mb_envmod) gfTime gfoTime
(st,t) = selectFormat opts (fmap snd3 mb_envmod) gfTime gfoTime
snd3 (_,y,_) = y
thd3 (_,_,z) = z
(st,(mname,imps)) <-
case st of
CSEnv -> return (st, (name, maybe [] snd mb_envmod))
CSEnv -> return (st, (name, maybe [] thd3 mb_envmod))
CSRead -> do let gfo = if isGFO file then file else gf2gfo opts file
t_imps <- gfoImports gfo
case t_imps of
@@ -121,8 +124,8 @@ getAllFiles opts ps env file = do
return (name,st,t,isJust gfTime,imps,dropFileName file)
--------------------------------------------------------------------------------
findFile gfoDir ps name =
maybe noSource haveSource =<< getFilePath ps (gfFile name)
findFile gfoDir ps env name =
maybe noSource haveSource =<< getFilePath ps (gfFile name)
where
haveSource gfFile =
do gfTime <- getModificationTime gfFile
@@ -130,7 +133,7 @@ findFile gfoDir ps name =
return (gfFile, Just gfTime, mb_gfoTime)
noSource =
maybe noGFO haveGFO =<< getFilePath gfoPath (gfoFile name)
maybe noGFO haveGFO =<< getFilePath gfoPath (gfoFile name)
where
gfoPath = maybe id (:) gfoDir ps
@@ -138,8 +141,11 @@ findFile gfoDir ps name =
do gfoTime <- getModificationTime gfoFile
return (gfoFile, Nothing, Just gfoTime)
noGFO = raise (render ("File" <+> gfFile name <+> "does not exist." $$
"searched in:" <+> vcat ps))
noGFO =
case Map.lookup name env of
Just (fpath,t,_) -> return (fpath, Nothing, Nothing)
Nothing -> raise (render ("File" <+> gfFile name <+> "does not exist." $$
"searched in:" <+> vcat ps <+> (show (env :: Map.Map ModName (FilePath,UTCTime,[ModName])))))
gfImports opts file = importsOfModule `fmap` parseModHeader opts file

View File

@@ -36,6 +36,7 @@ import GF.Grammar.Lookup
import GF.Grammar.Macros
import GF.Grammar.Printer
import GF.Data.Operations
import PGF2(abstractName,functionType,categoryContext)
import Control.Monad
import Data.List (nub,(\\))
@@ -58,10 +59,7 @@ renameModule cwd gr mo@(m,mi) = do
return (m, mi{jments = js})
type Status = (StatusMap, [(OpenSpec, StatusMap)])
type StatusMap = Map.Map Ident StatusInfo
type StatusInfo = Ident -> Term
type StatusMap = Ident -> Maybe Term
-- Delays errors, allowing many errors to be detected and reported
renameIdentTerm env = accumulateError (renameIdentTerm' env)
@@ -74,14 +72,12 @@ renameIdentTerm' env@(act,imps) t0 =
Cn c -> ident (\_ s -> checkError s) c
Q (m',c) | m' == cPredef {- && isInPredefined c -} -> return t0
Q (m',c) -> do
m <- lookupErr m' qualifs
f <- lookupIdent c m
return $ f c
f <- lookupErr m' qualifs
maybe (notFound c) return (f c)
QC (m',c) | m' == cPredef {- && isInPredefined c -} -> return t0
QC (m',c) -> do
m <- lookupErr m' qualifs
f <- lookupIdent c m
return $ f c
f <- lookupErr m' qualifs
maybe (notFound c) return (f c)
_ -> return t0
where
opens = [st | (OSimple _,st) <- imps]
@@ -95,67 +91,68 @@ renameIdentTerm' env@(act,imps) t0 =
| otherwise = checkError s
ident alt c =
case Map.lookup c act of
Just f -> return (f c)
_ -> case mapMaybe (Map.lookup c) opens of
[f] -> return (f c)
case act c of
Just t -> return t
_ -> case mapMaybe (\f -> f c) opens of
[t] -> return t
[] -> alt c ("constant not found:" <+> c $$
"given" <+> fsep (punctuate ',' (map fst qualifs)))
fs -> case nub [f c | f <- fs] of
[tr] -> return tr
ts -> case nub ts of
[t] -> return t
ts@(t:_) -> do checkWarn ("atomic term" <+> ppTerm Qualified 0 t0 $$
"conflict" <+> hsep (punctuate ',' (map (ppTerm Qualified 0) ts)) $$
"given" <+> fsep (punctuate ',' (map fst qualifs)))
return (bestTerm ts) -- Heuristic for resource grammar. Returns t for all others.
where
-- Hotfix for https://github.com/GrammaticalFramework/gf-core/issues/56
-- Real bug is probably somewhere deeper in recognising excluded functions. /IL 2020-06-06
notFromCommonModule :: Term -> Bool
notFromCommonModule term =
let t = render $ ppTerm Qualified 0 term :: String
in not $ any (\moduleName -> moduleName `L.isPrefixOf` t)
["CommonX", "ConstructX", "ExtendFunctor"
,"MarkHTMLX", "ParamX", "TenseX", "TextX"]
return t
-- If one of the terms comes from the common modules,
-- we choose the other one, because that's defined in the grammar.
bestTerm :: [Term] -> Term
bestTerm [] = error "constant not found" -- not reached: bestTerm is only called for case ts@(t:_)
bestTerm ts@(t:_) =
let notCommon = [t | t <- ts, notFromCommonModule t]
in case notCommon of
[] -> t -- All terms are from common modules, return first of original list
(u:_) -> u -- ≥1 terms are not from common modules, return first of those
info2status :: Maybe ModuleName -> Ident -> Info -> StatusInfo
info2status :: Maybe ModuleName -> Ident -> Info -> Term
info2status mq c i = case i of
AbsFun _ _ Nothing _ -> maybe Con (curry QC) mq
ResValue _ -> maybe Con (curry QC) mq
ResParam _ _ -> maybe Con (curry QC) mq
AnyInd True m -> maybe Con (const (curry QC m)) mq
AnyInd False m -> maybe Cn (const (curry Q m)) mq
_ -> maybe Cn (curry Q) mq
AbsFun _ _ Nothing _ -> maybe Con (curry QC) mq c
ResValue _ _ -> maybe Con (curry QC) mq c
ResParam _ _ -> maybe Con (curry QC) mq c
AnyInd True m -> maybe Con (const (curry QC m)) mq c
AnyInd False m -> maybe Cn (const (curry Q m)) mq c
_ -> maybe Cn (curry Q) mq c
tree2status :: OpenSpec -> Map.Map Ident Info -> StatusMap
tree2status o = case o of
OSimple i -> Map.mapWithKey (info2status (Just i))
OQualif i j -> Map.mapWithKey (info2status (Just j))
tree2status o map = case o of
OSimple i -> flip Map.lookup (Map.mapWithKey (info2status (Just i)) map)
OQualif i j -> flip Map.lookup (Map.mapWithKey (info2status (Just j)) map)
buildStatus :: FilePath -> Grammar -> Module -> Check Status
buildStatus cwd gr mo@(m,mi) = checkInModule cwd mi NoLoc empty $ do
let gr1 = prependModule gr mo
exts = [(OSimple m,mi) | (m,mi) <- allExtends gr1 m]
ops <- mapM (\o -> lookupModule gr1 (openedModule o) >>= \mi -> return (o,mi)) (mopens mi)
let sts = map modInfo2status (exts++ops)
exts = [(o,modInfo2status o mi) | (m,mi) <- allExtends gr1 m, let o = OSimple m]
ops <- mapM (openSpec2status gr1) (mopens mi)
let sts = exts++ops
return (if isModCnc mi
then (Map.empty, reverse sts) -- the module itself does not define any names
else (self2status m mi,reverse sts)) -- so the empty ident is not needed
then (const Nothing, reverse sts) -- the module itself does not define any names
else (self2status m mi,reverse sts))
modInfo2status :: (OpenSpec,ModuleInfo) -> (OpenSpec, StatusMap)
modInfo2status (o,mo) = (o,tree2status o (jments mo))
openSpec2status gr o =
do mi <- lookupModule gr (openedModule o)
return (o,modInfo2status o mi)
where
mn = openedModule o
pgf2status o pgf id =
case functionType pgf sid of
Just _ -> Just (QC (mn, id))
Nothing -> case categoryContext pgf sid of
Just _ -> Just (QC (mn, id))
Nothing -> Nothing
where
sid = showIdent id
mn = case o of
OSimple i -> i
OQualif i j -> j
modInfo2status :: OpenSpec -> ModuleInfo -> StatusMap
modInfo2status o (ModInfo{jments=jments}) = tree2status o jments
modInfo2status o (ModPGF pgf) = pgf2status o pgf
self2status :: ModuleName -> ModuleInfo -> StatusMap
self2status c m = Map.mapWithKey (info2status (Just c)) (jments m)
self2status c m = flip Map.lookup (Map.mapWithKey (info2status (Just c)) (jments m))
renameInfo :: FilePath -> Status -> Module -> Ident -> Info -> Check Info
@@ -168,9 +165,9 @@ renameInfo cwd status (m,mi) i info =
ResParam (Just pp) m -> do
pp' <- renLoc (mapM (renParam status)) pp
return (ResParam (Just pp') m)
ResValue t -> do
ResValue t i -> do
t <- renLoc (renameTerm status []) t
return (ResValue t)
return (ResValue t i)
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)
_ -> return info
@@ -237,9 +234,16 @@ renameTerm env vars = ren vars where
, checkError ("unknown qualified constant" <+> trm)
]
EPatt p -> do
EPatt minp maxp p -> do
(p',_) <- renpatt p
return $ EPatt p'
return $ EPatt minp maxp p'
Reset ctl mb_ct t qid -> do
mv_ct <- case mb_ct of
Just ct -> liftM Just $ ren vs ct
Nothing -> return mb_ct
t <- ren vs t
return (Reset ctl mv_ct t qid)
_ -> composOp (ren vs) trm
@@ -306,14 +310,14 @@ renamePattern env patt =
(q',ws) <- renp q
return (PAlt p' q', vs ++ ws)
PSeq p q -> do
PSeq minp maxp p minq maxq q -> do
(p',vs) <- renp p
(q',ws) <- renp q
return (PSeq p' q', vs ++ ws)
return (PSeq minp maxp p' minq maxq q', vs ++ ws)
PRep p -> do
PRep minp maxp p -> do
(p',vs) <- renp p
return (PRep p', vs)
return (PRep minp maxp p', vs)
PNeg p -> do
(p',vs) <- renp p
@@ -332,7 +336,7 @@ renameContext :: Status -> Context -> Check Context
renameContext b = renc [] where
renc vs cont = case cont of
(bt,x,t) : xts
| isWildIdent x -> do
| x == identW -> do
t' <- ren vs t
xts' <- renc vs xts
return $ (bt,x,t') : xts'

View File

@@ -31,7 +31,7 @@ getLocalTags x (m,mi) =
getLocations (AbsFun mb_type _ mb_eqs _) = maybe (ltype "fun") mb_type ++
maybe (list (loc "def")) mb_eqs
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 ++
maybe (loc "oper-def") mb_def
getLocations (ResOverload _ defs) = list (\(x,y) -> ltype "overload-type" x ++

File diff suppressed because it is too large Load Diff

View File

@@ -35,7 +35,7 @@ data AExp =
AVr Ident Val
| ACn QIdent Val
| AType
| AInt Int
| AInt Integer
| AFloat Double
| AStr String
| AMeta MetaId Val

View File

@@ -57,6 +57,10 @@ extendModule cwd gr (name,m)
extOne mo (n,cond) = do
m0 <- lookupModule gr n
case m0 of
ModPGF _ -> checkError ("cannot extend the precompiled module" <+> n)
_ -> return ()
-- test that the module types match, and find out if the old is complete
unless (sameMType (mtype m) (mtype mo))
(checkError ("illegal extension type to module" <+> name))
@@ -78,7 +82,7 @@ extendModule cwd gr (name,m)
-- | rebuilding instance + interface, and "with" modules, prior to renaming.
-- AR 24/10/2003
rebuildModule :: FilePath -> SourceGrammar -> SourceModule -> Check SourceModule
rebuildModule cwd gr mo@(i,mi@(ModInfo mt stat fs_ me mw ops_ med_ msrc_ env_ js_)) =
rebuildModule cwd gr mo@(i,mi@(ModInfo mt stat fs_ me mw ops_ med_ msrc_ mseqs js_)) =
checkInModule cwd mi NoLoc empty $ do
---- deps <- moduleDeps ms
@@ -131,7 +135,7 @@ rebuildModule cwd gr mo@(i,mi@(ModInfo mt stat fs_ me mw ops_ med_ msrc_ env_ js
js
let js1 = Map.union js0 js_
let med1= nub (ext : infs ++ insts ++ med_)
return $ ModInfo mt0 stat' fs1 me Nothing ops1 med1 msrc_ env_ js1
return $ ModInfo mt0 stat' fs1 me Nothing ops1 med1 msrc_ mseqs js1
return (i,mi')
@@ -168,7 +172,7 @@ extendMod gr isCompl ((name,mi),cond) base new = foldM try new $ Map.toList (jme
indirInfo :: ModuleName -> Info -> Info
indirInfo n info = AnyInd b n' where
(b,n') = case info of
ResValue _ -> (True,n)
ResValue _ _ -> (True,n)
ResParam _ _ -> (True,n)
AbsFun _ _ Nothing _ -> (True,n)
AnyInd b k -> (b,k)
@@ -179,7 +183,7 @@ globalizeLoc fpath i =
AbsCat mc -> AbsCat (fmap gl mc)
AbsFun mt ma md moper -> AbsFun (fmap gl mt) ma (fmap (fmap gl) md) moper
ResParam mt mv -> ResParam (fmap gl mt) mv
ResValue t -> ResValue (gl t)
ResValue t i -> ResValue (gl t) i
ResOper mt m -> ResOper (fmap gl mt) (fmap gl m)
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
@@ -201,9 +205,9 @@ unifyAnyInfo m i j = case (i,j) of
(ResParam mt1 mv1, ResParam mt2 mv2) ->
liftM2 ResParam (unifyMaybeL mt1 mt2) (unifyMaybe mv1 mv2)
(ResValue (L l1 t1), ResValue (L l2 t2))
| t1==t2 -> return (ResValue (L l1 t1))
| otherwise -> fail ""
(ResValue (L l1 t1) i1, ResValue (L l2 t2) i2)
| t1==t2 && i1 == i2 -> return (ResValue (L l1 t1) i1)
| otherwise -> fail ""
(_, ResOverload ms t) | elem m ms ->
return $ ResOverload ms t
(ResOper mt1 m1, ResOper mt2 m2) ->

View File

@@ -110,12 +110,12 @@ batchCompile1 lib_dir (opts,filepaths) =
-- logStrLn $ "Finished "++show (length (modules gr'))++" modules."
return gr'
fcache <- liftIO $ newIOCache $ \ _ (imp,Hide (f,ps)) ->
do (file,_,_) <- findFile gfoDir ps imp
do (file,_,_) <- findFile gfoDir ps M.empty imp
return (file,(f,ps))
let find f ps imp =
do (file',(f',ps')) <- liftIO $ readIOCache fcache (imp,Hide (f,ps))
when (ps'/=ps) $
do (file,_,_) <- findFile gfoDir ps imp
do (file,_,_) <- findFile gfoDir ps M.empty imp
unless (file==file' || any fromPrelude [file,file']) $
do eq <- liftIO $ (==) <$> BS.readFile file <*> BS.readFile file'
unless eq $

View File

@@ -8,7 +8,6 @@ module GF.CompileOne(-- ** Compiling a single module
import GF.Compile.GetGrammar(getSourceModule)
import GF.Compile.Rename(renameModule)
import GF.Compile.CheckGrammar(checkModule)
import GF.Compile.Optimize(optimizeModule)
import GF.Compile.SubExOpt(subexpModule,unsubexpModule)
import GF.Compile.GeneratePMCFG(generatePMCFG)
import GF.Compile.Update(extendModule,rebuildModule)
@@ -19,7 +18,7 @@ import GF.Grammar.Printer(ppModule,TermPrintQual(..))
import GF.Grammar.Binary(decodeModule,encodeModule)
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,dumpOut,warnOut)
import GF.Infra.CheckM(runCheck')
import GF.Data.Operations(ErrorMonad,liftErr,(+++))
@@ -28,7 +27,6 @@ import System.FilePath(makeRelative)
import System.Random(randomIO)
import qualified Data.Map as Map
import GF.Text.Pretty(render,(<+>),($$)) --Doc,
import GF.System.Console(TermColors(..),getTermColors)
import Control.Monad((<=<))
import qualified Control.Monad.Fail as Fail
@@ -58,7 +56,7 @@ reuseGFO opts srcgr file =
decodeModule file
let sm0 = (fst sm00,(snd sm00){mflags=mflags (snd sm00) `addOptions` opts})
idump opts Source sm0
dumpOut opts Source (ppModule Internal sm0)
let sm1 = unsubexpModule sm0
(sm,warnings) <- -- putPointE Normal opts "creating indirections" $
@@ -81,7 +79,7 @@ useTheSource opts srcgr file =
sm <- putpOpt ("- parsing" +++ rfile)
("- compiling" +++ rfile ++ "... ")
(getSourceModule opts file)
idump opts Source sm
dumpOut opts Source (ppModule Internal sm)
compileSourceModule opts cwd (Just file) srcgr sm
where
putpOpt v m act
@@ -98,8 +96,8 @@ compileSourceModule opts cwd mb_gfFile gr =
else generateGFO <=< ifComplete (backend <=< middle) <=< frontend
where
-- Apply to all modules
frontend = runPass Extend "" . extendModule cwd gr
<=< runPass Rebuild "" . rebuildModule cwd gr
frontend = runPass Extend "extending" . extendModule cwd gr
<=< runPass Rebuild "rebuilding" . rebuildModule cwd gr
-- Apply to complete modules
middle = runPass TypeCheck "type checking" . checkModule opts cwd gr
@@ -107,10 +105,9 @@ compileSourceModule opts cwd mb_gfFile gr =
-- Apply to complete modules when not generating tags
backend mo3 =
do mo4 <- runPassE Optimize "optimizing" $ optimizeModule opts gr mo3
if isModCnc (snd mo4) && flag optPMCFG opts
then runPassI "generating PMCFG" $ generatePMCFG opts gr mb_gfFile mo4
else runPassI "" $ return mo4
do if isModCnc (snd mo3) && flag optPMCFG opts
then runPassI "generating PMCFG" $ fmap fst $ runCheck' opts (generatePMCFG opts cwd gr mo3)
else runPassI "" $ return mo3
ifComplete yes mo@(_,mi) =
if isCompleteModule mi then yes mo else return mo
@@ -128,14 +125,13 @@ compileSourceModule opts cwd mb_gfFile gr =
-- * Running a compiler pass, with impedance matching
runPass = runPass' fst fst snd (liftErr . runCheck' opts)
runPassE = runPass2e liftErr id
runPassI = runPass2e id id Canon
runPass2e lift dump = runPass' id dump (const "") lift
runPass' ret dump warn lift pass pp m =
do out <- putpp pp $ lift m
warnOut opts (warn out)
idump opts pass (dump out)
dumpOut opts pass (ppModule Internal (dump out))
return (ret out)
maybeM f = maybe (return ()) f
@@ -154,20 +150,3 @@ writeGFO opts cwd file mo =
(m,mi) = subexpModule mo
notAnyInd x = case x of AnyInd{} -> False; _ -> True
-- to output an intermediate stage
--intermOut :: Options -> Dump -> Doc -> IOE ()
intermOut opts d doc
| dump opts d = ePutStrLn (render ("\n\n--#" <+> show d $$ doc))
| otherwise = return ()
idump opts pass = intermOut opts (Dump pass) . ppModule Internal
warnOut opts warnings
| null warnings = return ()
| otherwise = do t <- getTermColors
ePutStr (blueFg t);ePutStr ws;ePutStrLn (restore t)
where
ws = if flag optVerbosity opts == Normal
then '\n':warnings
else warnings

View File

@@ -1,20 +1,24 @@
module GF.Compiler (mainGFC, linkGrammars, writeGrammar, writeOutputs) where
module GF.Compiler (mainGFC, writeGrammar, writeOutputs) where
import PGF2
import PGF2.Internal(unionPGF,writePGF,writeConcr)
import PGF2.Transactions
import GF.Compile as S(batchCompile,link,srcAbsName)
import GF.CompileInParallel as P(parallelBatchCompile)
import GF.Compile.Export
import GF.Compile.ConcreteToHaskell(concretes2haskell)
import GF.Compile.GrammarToCanonical--(concretes2canonical)
import GF.Compile.GrammarToCanonical
import GF.Compile.CFGtoPGF
import GF.Compile.GetGrammar
import GF.Grammar.BNFC
import GF.Grammar.CFG
import GF.Grammar.Grammar
import GF.Grammar.JSON(grammar2json)
import GF.Grammar.Printer(TermPrintQual(..),ppModule)
--import GF.Infra.Ident(showIdent)
import GF.Infra.UseIO
import GF.Infra.Option
import GF.Infra.CheckM
import GF.Data.ErrM
import GF.System.Directory
import GF.Text.Pretty(render,render80)
@@ -23,9 +27,9 @@ import Data.Maybe
import qualified Data.Map as Map
import qualified Data.Set as Set
import qualified Data.ByteString.Lazy as BSL
import GF.Grammar.CanonicalJSON (encodeJSON)
import Text.JSON (encode)
import System.FilePath
import Control.Monad(when,unless,forM_)
import Control.Monad(when,unless,forM_,foldM)
-- | 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@)
@@ -47,43 +51,32 @@ mainGFC opts fs = do
compileSourceFiles :: Options -> [FilePath] -> IOE ()
compileSourceFiles opts fs =
do output <- batchCompile opts fs
exportCanonical output
unless (flag optStopAfterPhase opts == Compile) $
linkGrammars opts output
do cnc_gr@(cnc,gr) <- S.batchCompile opts Nothing fs
let absname = srcAbsName gr cnc
exportCanonical absname gr
unless (flag optStopAfterPhase opts == Compile) $ do
let pgfFile = outputPath opts (grammarName' opts (render absname)<.>"pgf")
pgf <- link opts Nothing cnc_gr
writeGrammar opts pgf
writeOutputs opts pgf
where
batchCompile = maybe batchCompile' parallelBatchCompile (flag optJobs opts)
batchCompile' opts fs = do (t,cnc_gr) <- S.batchCompile opts fs
return (t,[cnc_gr])
exportCanonical (_time, canonical) =
do when (FmtHaskell `elem` ofmts && haskellOption opts HaskellConcrete) $
mapM_ cnc2haskell canonical
exportCanonical absname gr =
do when (FmtHaskell `elem` ofmts && haskellOption opts HaskellConcrete) $ do
(res,_) <- runCheck (concretes2haskell opts absname gr)
mapM_ writeExport res
when (FmtCanonicalGF `elem` ofmts) $
do createDirectoryIfMissing False "canonical"
mapM_ abs2canonical canonical
mapM_ cnc2canonical canonical
when (FmtCanonicalJson `elem` ofmts) $ mapM_ grammar2json canonical
(gr_canon,_) <- runCheck (grammar2canonical opts absname gr)
forM_ (modules gr_canon) $ \m@(mn,_) -> do
writeExport ("canonical/"++render mn++".gf",render80 (ppModule Unqualified m))
when (FmtCanonicalJson `elem` ofmts) $
do (gr_canon,_) <- runCheck (grammar2canonical opts absname gr)
writeExport (render absname ++ ".json", encode (grammar2json gr_canon))
when (FmtSourceJson `elem` ofmts) $
do writeExport (render absname ++ ".json", encode (grammar2json gr))
where
ofmts = flag optOutputFormats opts
cnc2haskell (cnc,gr) =
do mapM_ writeExport $ concretes2haskell opts (srcAbsName gr cnc) gr
abs2canonical (cnc,gr) =
writeExport ("canonical/"++render absname++".gf",render80 canAbs)
where
absname = srcAbsName gr cnc
canAbs = abstract2canonical absname gr
cnc2canonical (cnc,gr) =
mapM_ (writeExport.fmap render80) $
concretes2canonical opts (srcAbsName gr cnc) gr
grammar2json (cnc,gr) = encodeJSON (render absname ++ ".json") gr_canon
where absname = srcAbsName gr cnc
gr_canon = grammar2canonical opts absname gr
writeExport (path,s) = writing opts path $ writeUTF8File path s
@@ -92,7 +85,7 @@ compileSourceFiles opts fs =
-- 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
-- recreated. Calls 'writeGrammar' and 'writeOutputs'.
linkGrammars opts (t_src,~cnc_grs@(~(cnc,gr):_)) =
linkGrammars opts (t_src,cnc_gr@(cnc,gr)) =
do let abs = render (srcAbsName gr cnc)
pgfFile = outputPath opts (grammarName' opts abs<.>"pgf")
t_pgf <- if outputJustPGF opts
@@ -100,8 +93,7 @@ linkGrammars opts (t_src,~cnc_grs@(~(cnc,gr):_)) =
else return Nothing
if t_pgf >= Just t_src
then putIfVerb opts $ pgfFile ++ " is up-to-date."
else do pgfs <- mapM (link opts) cnc_grs
let pgf = foldl1 (\one two -> fromMaybe two (unionPGF one two)) pgfs
else do pgf <- link opts Nothing cnc_gr
writeGrammar opts pgf
writeOutputs opts pgf
@@ -133,16 +125,32 @@ unionPGFFiles opts fs =
else doIt
doIt =
do pgfs <- mapM readPGFVerbose fs
let pgf = foldl1 (\one two -> fromMaybe two (unionPGF one two)) pgfs
let pgfFile = outputPath opts (grammarName opts pgf <.> "pgf")
if pgfFile `elem` fs
then putStrLnE $ "Refusing to overwrite " ++ pgfFile
else writeGrammar opts pgf
writeOutputs opts pgf
case fs of
[] -> return ()
(f:fs) -> do mb_probs <- case flag optProbsFile opts of
Nothing -> return Nothing
Just file -> fmap Just (readProbabilitiesFromFile file)
pgf <- if snd (flag optLinkTargets opts)
then case flag optName opts of
Just name -> do let fname = maybe id (</>) (flag optOutputDir opts) (name<.>"ngf")
putStrLnE ("(Boot image "++fname++")")
exists <- doesFileExist fname
if exists
then removeFile fname
else return ()
echo (\f -> bootNGFWithProbs f mb_probs fname) f
Nothing -> do putStrLnE $ "To boot from a list of .pgf files add option -name"
echo (\f -> readPGFWithProbs f mb_probs) f
else echo (\f -> readPGFWithProbs f mb_probs) f
pgf <- foldM (\pgf -> echo (modifyPGF pgf . mergePGF)) pgf fs
let pgfFile = outputPath opts (grammarName opts pgf <.> "pgf")
if pgfFile `elem` fs
then putStrLnE $ "Refusing to overwrite " ++ pgfFile
else writeGrammar opts pgf
writeOutputs opts pgf
echo read f = putPointE Normal opts ("Reading " ++ f ++ "...") (liftIO (read f))
readPGFVerbose f =
putPointE Normal opts ("Reading " ++ f ++ "...") $ liftIO $ readPGF f
-- | Export the PGF to the 'OutputFormat's specified in the 'Options'.
-- Calls 'exportPGF'.
@@ -157,19 +165,10 @@ writeOutputs opts pgf = do
-- A split PGF file is output if the @-split-pgf@ option is used.
writeGrammar :: Options -> PGF -> IOE ()
writeGrammar opts pgf =
if flag optSplitPGF opts then writeSplitPGF else writeNormalPGF
where
writeNormalPGF =
do let outfile = outputPath opts (grammarName opts pgf <.> "pgf")
writing opts outfile (writePGF outfile pgf)
writeSplitPGF =
do let outfile = outputPath opts (grammarName opts pgf <.> "pgf")
writing opts outfile $ writePGF outfile pgf
forM_ (Map.toList (languages pgf)) $ \(concrname,concr) -> do
let outfile = outputPath opts (concrname <.> "pgf_c")
writing opts outfile (writeConcr outfile concr)
if fst (flag optLinkTargets opts)
then do let outfile = outputPath opts (grammarName opts pgf <.> "pgf")
writing opts outfile (writePGF outfile pgf Nothing)
else return ()
writeOutput :: Options -> FilePath-> String -> IOE ()
writeOutput opts file str = writing opts path $ writeUTF8File path str
@@ -181,7 +180,7 @@ grammarName :: Options -> PGF -> String
grammarName opts pgf = grammarName' opts (abstractName pgf)
grammarName' opts abs = fromMaybe abs (flag optName opts)
outputJustPGF opts = null (flag optOutputFormats opts) && not (flag optSplitPGF opts)
outputJustPGF opts = null (flag optOutputFormats opts)
outputPath opts file = maybe id (</>) (flag optOutputDir opts) file

View File

@@ -50,6 +50,7 @@ import qualified Data.Map as Map
import Data.Map (Map)
--import Control.Applicative(Applicative(..))
import Control.Monad (liftM,liftM2) --,ap
import Control.Monad.Fix
import GF.Data.ErrM
import GF.Data.Relation
@@ -237,6 +238,10 @@ instance ErrorMonad Err where
handle a@(Ok _) _ = a
handle (Bad i) f = f i
instance MonadFix Err where
mfix f = let res@(~(Ok x)) = f x in res
liftErr e = err raise return e
{-
instance ErrorMonad (STM s) where

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