plugins 1.2 → 1.3
raw patch · 440 files changed
+9944/−8 lines, 440 filesnew-uploaderbinary-added
Files
- AUTHORS +5/−0
- README +111/−0
- TODO +26/−0
- docs/Makefile +31/−0
- docs/haskell.sty +452/−0
- docs/hs-plugins.1 +36/−0
- docs/hs-plugins.hdir +1/−0
- docs/hs-plugins.tex +1804/−0
- docs/munge.sed +16/−0
- docs/tex2page.sty +9/−0
- docs/tex2page.tex +1381/−0
- plugins.cabal +2/−2
- scripts/Setup-with-ghc.lhs +20/−0
- scripts/mkrelease.sh +11/−0
- scripts/openbsd-port/Makefile +21/−0
- scripts/openbsd-port/distinfo +3/−0
- scripts/openbsd-port/pkg/DESCR +6/−0
- scripts/openbsd-port/pkg/PLIST +28/−0
- src/System/Plugins/Env.hs +30/−4
- src/System/Plugins/Load.hs +2/−2
- src/System/Plugins/ParsePkgConfCabal.y_in +218/−0
- src/System/Plugins/ParsePkgConfLite.hs +616/−0
- src/System/Plugins/ParsePkgConfLite.y +159/−0
- testsuite/README +17/−0
- testsuite/TIMINGS +45/−0
- testsuite/build.mk +40/−0
- testsuite/check.mk +24/−0
- testsuite/conf/simple/Mailrc.conf +11/−0
- testsuite/conf/simple/Mailrc.stub +28/−0
- testsuite/conf/simple/Makefile +4/−0
- testsuite/conf/simple/api/API.hs +27/−0
- testsuite/conf/simple/prog/Main.hs +22/−0
- testsuite/conf/simple/prog/expected +1/−0
- testsuite/dynload/io/Makefile +6/−0
- testsuite/dynload/io/TestIO.hs +86/−0
- testsuite/dynload/io/api/API.hs +19/−0
- testsuite/dynload/io/prog/Main.hs +12/−0
- testsuite/dynload/io/prog/expected +1/−0
- testsuite/dynload/poly/Makefile +4/−0
- testsuite/dynload/poly/Plugin.hs +12/−0
- testsuite/dynload/poly/api/API.hs +24/−0
- testsuite/dynload/poly/prog/Main.hs +17/−0
- testsuite/dynload/poly/prog/expected +2/−0
- testsuite/dynload/should_fail/Makefile +4/−0
- testsuite/dynload/should_fail/Plugin.hs +12/−0
- testsuite/dynload/should_fail/api/API.hs +20/−0
- testsuite/dynload/should_fail/prog/Main.hs +14/−0
- testsuite/dynload/should_fail/prog/expected +4/−0
- testsuite/dynload/should_fail_1/Makefile +4/−0
- testsuite/dynload/should_fail_1/Plugin.hs +15/−0
- testsuite/dynload/should_fail_1/api/API.hs +20/−0
- testsuite/dynload/should_fail_1/prog/Main.hs +11/−0
- testsuite/dynload/should_fail_1/prog/expected +4/−0
- testsuite/dynload/should_fail_2/Makefile +4/−0
- testsuite/dynload/should_fail_2/Plugin.in +19/−0
- testsuite/dynload/should_fail_2/Plugin.stub +12/−0
- testsuite/dynload/should_fail_2/api/API.hs +22/−0
- testsuite/dynload/should_fail_2/prog/Main.hs +19/−0
- testsuite/dynload/should_fail_2/prog/expected +8/−0
- testsuite/dynload/should_fail_2/prog/expected.604 +7/−0
- testsuite/dynload/should_fail_2/prog/expected.605 +7/−0
- testsuite/dynload/should_fail_3/Makefile +4/−0
- testsuite/dynload/should_fail_3/Plugin.in +19/−0
- testsuite/dynload/should_fail_3/Plugin.stub +12/−0
- testsuite/dynload/should_fail_3/api/API.hs +22/−0
- testsuite/dynload/should_fail_3/prog/Main.hs +18/−0
- testsuite/dynload/should_fail_3/prog/expected +9/−0
- testsuite/dynload/should_fail_3/prog/expected.604 +8/−0
- testsuite/dynload/should_fail_3/prog/expected.605 +8/−0
- testsuite/dynload/simple/Makefile +4/−0
- testsuite/dynload/simple/Plugin.hs +11/−0
- testsuite/dynload/simple/api/API.hs +20/−0
- testsuite/dynload/simple/prog/Main.hs +15/−0
- testsuite/dynload/simple/prog/expected +1/−0
- testsuite/eval.mk +25/−0
- testsuite/eval/eval1/Main.hs +5/−0
- testsuite/eval/eval1/Makefile +2/−0
- testsuite/eval/eval1/expected +1/−0
- testsuite/eval/eval2/Main.hs +6/−0
- testsuite/eval/eval2/Makefile +2/−0
- testsuite/eval/eval2/expected +1/−0
- testsuite/eval/eval3/Main.hs +38/−0
- testsuite/eval/eval3/Makefile +2/−0
- testsuite/eval/eval3/expected +1/−0
- testsuite/eval/eval_/Main.hs +9/−0
- testsuite/eval/eval_/Makefile +2/−0
- testsuite/eval/eval_/expected +1/−0
- testsuite/eval/eval_fn/Main.hs +10/−0
- testsuite/eval/eval_fn/Makefile +2/−0
- testsuite/eval/eval_fn/expected +1/−0
- testsuite/eval/eval_fn1/Main.hs +15/−0
- testsuite/eval/eval_fn1/Makefile +2/−0
- testsuite/eval/eval_fn1/Poly.hs +16/−0
- testsuite/eval/eval_fn1/expected +2/−0
- testsuite/eval/foreign_eval/Makefile +2/−0
- testsuite/eval/foreign_eval/README +1/−0
- testsuite/eval/foreign_eval/dont_test +0/−0
- testsuite/eval/foreign_eval/expected +1/−0
- testsuite/eval/foreign_eval/main.c +16/−0
- testsuite/eval/foreign_eval1/Makefile +2/−0
- testsuite/eval/foreign_eval1/dont_test +0/−0
- testsuite/eval/foreign_eval1/expected +1/−0
- testsuite/eval/foreign_eval1/main.c +16/−0
- testsuite/eval/foreign_should_fail/Makefile +2/−0
- testsuite/eval/foreign_should_fail/dont_test +0/−0
- testsuite/eval/foreign_should_fail/expected +2/−0
- testsuite/eval/foreign_should_fail/expected.604 +1/−0
- testsuite/eval/foreign_should_fail/expected.605 +1/−0
- testsuite/eval/foreign_should_fail/main.c +16/−0
- testsuite/eval/foreign_should_fail_illtyped/Makefile +2/−0
- testsuite/eval/foreign_should_fail_illtyped/dont_test +0/−0
- testsuite/eval/foreign_should_fail_illtyped/expected +4/−0
- testsuite/eval/foreign_should_fail_illtyped/expected.604 +1/−0
- testsuite/eval/foreign_should_fail_illtyped/expected.605 +1/−0
- testsuite/eval/foreign_should_fail_illtyped/main.c +16/−0
- testsuite/eval/unsafeidir/Main.hs +16/−0
- testsuite/eval/unsafeidir/Makefile +2/−0
- testsuite/eval/unsafeidir/a/Extra.hs +3/−0
- testsuite/eval/unsafeidir/expected +1/−0
- testsuite/foreign.mk +22/−0
- testsuite/hier/hier1/Makefile +8/−0
- testsuite/hier/hier1/Modules/Flags.hs +15/−0
- testsuite/hier/hier1/Modules/Makefile +6/−0
- testsuite/hier/hier1/Plugin.hs +14/−0
- testsuite/hier/hier1/api/API.hs +16/−0
- testsuite/hier/hier1/prog/Main.hs +21/−0
- testsuite/hier/hier1/prog/expected +1/−0
- testsuite/hier/hier2/A/B/C/Module.hs +8/−0
- testsuite/hier/hier2/A/Makefile +7/−0
- testsuite/hier/hier2/Makefile +7/−0
- testsuite/hier/hier2/api/API.hs +4/−0
- testsuite/hier/hier2/prog/Main.hs +15/−0
- testsuite/hier/hier2/prog/expected +1/−0
- testsuite/hier/hier3/Main.hs +25/−0
- testsuite/hier/hier3/Makefile +7/−0
- testsuite/hier/hier3/One.hs +7/−0
- testsuite/hier/hier3/Two.hs +4/−0
- testsuite/hier/hier3/expected +5/−0
- testsuite/hier/hier4/A.hs +11/−0
- testsuite/hier/hier4/B.hs +4/−0
- testsuite/hier/hier4/C.hs +12/−0
- testsuite/hier/hier4/D.hs +6/−0
- testsuite/hier/hier4/Main.hs +12/−0
- testsuite/hier/hier4/Makefile +4/−0
- testsuite/hier/hier4/expected +1/−0
- testsuite/iface/null/A.hs +1/−0
- testsuite/iface/null/B.hs +1/−0
- testsuite/iface/null/Main.hs +9/−0
- testsuite/iface/null/Makefile +2/−0
- testsuite/iface/null/expected +4/−0
- testsuite/iface/null/expected.604 +5/−0
- testsuite/iface/null/expected.605 +5/−0
- testsuite/load/io/Makefile +6/−0
- testsuite/load/io/TestIO.hs +88/−0
- testsuite/load/io/api/API.hs +16/−0
- testsuite/load/io/prog/Main.hs +15/−0
- testsuite/load/io/prog/expected +1/−0
- testsuite/load/load_0/Makefile +6/−0
- testsuite/load/load_0/Test.hs +6/−0
- testsuite/load/load_0/api/API.hs +8/−0
- testsuite/load/load_0/prog/Main.hs +11/−0
- testsuite/load/load_0/prog/expected +1/−0
- testsuite/load/loadpkg/Main.hs +4/−0
- testsuite/load/loadpkg/Makefile +4/−0
- testsuite/load/loadpkg/expected +0/−0
- testsuite/load/null/Makefile +4/−0
- testsuite/load/null/Null.hs +11/−0
- testsuite/load/null/api/API.hs +12/−0
- testsuite/load/null/prog/Main.hs +17/−0
- testsuite/load/null/prog/expected +1/−0
- testsuite/load/thiemann0/Makefile +6/−0
- testsuite/load/thiemann0/Test.hs +11/−0
- testsuite/load/thiemann0/api/API.hs +8/−0
- testsuite/load/thiemann0/prog/Main.hs +16/−0
- testsuite/load/thiemann0/prog/expected +1/−0
- testsuite/load/thiemann2/C.hs +6/−0
- testsuite/load/thiemann2/Makefile +6/−0
- testsuite/load/thiemann2/api/API.hs +8/−0
- testsuite/load/thiemann2/prog/A.hs +8/−0
- testsuite/load/thiemann2/prog/B.hs +3/−0
- testsuite/load/thiemann2/prog/Main.hs +20/−0
- testsuite/load/thiemann2/prog/expected +1/−0
- testsuite/load/unloadpkg/Main.hs +6/−0
- testsuite/load/unloadpkg/Makefile +4/−0
- testsuite/load/unloadpkg/expected +0/−0
- testsuite/loadCLib/null/Makefile +4/−0
- testsuite/loadCLib/null/Null.hs +12/−0
- testsuite/loadCLib/null/api/API.hs +12/−0
- testsuite/loadCLib/null/prog/Main.hs +11/−0
- testsuite/loadCLib/null/prog/expected +1/−0
- testsuite/make/makeall001/A.hs +3/−0
- testsuite/make/makeall001/B.hs +3/−0
- testsuite/make/makeall001/C.hs +3/−0
- testsuite/make/makeall001/Makefile +3/−0
- testsuite/make/makeall001/Tiny.hs +13/−0
- testsuite/make/makeall001/api/API.hs +13/−0
- testsuite/make/makeall001/prog/Main.hs +18/−0
- testsuite/make/makeall001/prog/expected +1/−0
- testsuite/make/null/Makefile +4/−0
- testsuite/make/null/Null.hs +11/−0
- testsuite/make/null/api/API.hs +12/−0
- testsuite/make/null/prog/Main.hs +13/−0
- testsuite/make/null/prog/expected +1/−0
- testsuite/make/o/Makefile +3/−0
- testsuite/make/o/Plugin.hs +7/−0
- testsuite/make/o/api/API.hs +8/−0
- testsuite/make/o/prog/Main.hs +28/−0
- testsuite/make/o/prog/expected +1/−0
- testsuite/make/odir/Makefile +3/−0
- testsuite/make/odir/Plugin.hs +7/−0
- testsuite/make/odir/api/API.hs +8/−0
- testsuite/make/odir/prog/Main.hs +21/−0
- testsuite/make/odir/prog/expected +1/−0
- testsuite/make/remake001/Bar.hs +3/−0
- testsuite/make/remake001/Foo.hs +3/−0
- testsuite/make/remake001/Main.hs +36/−0
- testsuite/make/remake001/Makefile +4/−0
- testsuite/make/remake001/expected +4/−0
- testsuite/make/remake001_should_fail/Bar.hs +3/−0
- testsuite/make/remake001_should_fail/Foo.hs +3/−0
- testsuite/make/remake001_should_fail/Main.hs +31/−0
- testsuite/make/remake001_should_fail/Makefile +4/−0
- testsuite/make/remake001_should_fail/expected +4/−0
- testsuite/make/simple/Makefile +3/−0
- testsuite/make/simple/Tiny.hs +14/−0
- testsuite/make/simple/api/API.hs +13/−0
- testsuite/make/simple/prog/Main.hs +19/−0
- testsuite/make/simple/prog/expected +1/−0
- testsuite/makewith/global_pragma/Makefile +5/−0
- testsuite/makewith/global_pragma/Plugin.hs +17/−0
- testsuite/makewith/global_pragma/api/API.hs +8/−0
- testsuite/makewith/global_pragma/prog/Main.hs +19/−0
- testsuite/makewith/global_pragma/prog/expected +1/−0
- testsuite/makewith/io/Makefile +4/−0
- testsuite/makewith/io/README +2/−0
- testsuite/makewith/io/TestIO.stub +10/−0
- testsuite/makewith/io/api/API.hs +16/−0
- testsuite/makewith/io/prog/Main.hs +21/−0
- testsuite/makewith/io/prog/expected +6/−0
- testsuite/makewith/merge00/Bar.hs +3/−0
- testsuite/makewith/merge00/Foo.hs +4/−0
- testsuite/makewith/merge00/Main.hs +38/−0
- testsuite/makewith/merge00/Makefile +4/−0
- testsuite/makewith/merge00/expected +2/−0
- testsuite/makewith/mergeto0/Bar.hs +3/−0
- testsuite/makewith/mergeto0/Foo.hs +4/−0
- testsuite/makewith/mergeto0/Main.hs +37/−0
- testsuite/makewith/mergeto0/Makefile +4/−0
- testsuite/makewith/mergeto0/expected +3/−0
- testsuite/makewith/module_name/Bar.hs +3/−0
- testsuite/makewith/module_name/Foo.hs +4/−0
- testsuite/makewith/module_name/Main.hs +33/−0
- testsuite/makewith/module_name/Makefile +4/−0
- testsuite/makewith/module_name/expected +5/−0
- testsuite/makewith/multi_make/Bar.hs +4/−0
- testsuite/makewith/multi_make/Foo.hs +4/−0
- testsuite/makewith/multi_make/Main.hs +37/−0
- testsuite/makewith/multi_make/Makefile +4/−0
- testsuite/makewith/multi_make/Stub.hs +4/−0
- testsuite/makewith/multi_make/expected +6/−0
- testsuite/makewith/should_fail_0/Makefile +4/−0
- testsuite/makewith/should_fail_0/Plugin.in +3/−0
- testsuite/makewith/should_fail_0/Plugin.stub +6/−0
- testsuite/makewith/should_fail_0/api/API.hs +10/−0
- testsuite/makewith/should_fail_0/prog/Main.hs +19/−0
- testsuite/makewith/should_fail_0/prog/expected +1/−0
- testsuite/makewith/tiny/Makefile +5/−0
- testsuite/makewith/tiny/Tiny.conf +8/−0
- testsuite/makewith/tiny/Tiny.stub +31/−0
- testsuite/makewith/tiny/api/API.hs +13/−0
- testsuite/makewith/tiny/prog/Main.hs +21/−0
- testsuite/makewith/tiny/prog/expected +1/−0
- testsuite/makewith/unsafeio/Makefile +5/−0
- testsuite/makewith/unsafeio/README +3/−0
- testsuite/makewith/unsafeio/Unsafe.stub +13/−0
- testsuite/makewith/unsafeio/api/API.hs +13/−0
- testsuite/makewith/unsafeio/prog/Main.hs +20/−0
- testsuite/makewith/unsafeio/prog/README +8/−0
- testsuite/makewith/unsafeio/prog/expected +6/−0
- testsuite/misc/mkstemps/Main.hs +69/−0
- testsuite/misc/mkstemps/Makefile +2/−0
- testsuite/misc/mkstemps/expected +5/−0
- testsuite/multi/3plugins/Makefile +6/−0
- testsuite/multi/3plugins/Plugin1.hs +8/−0
- testsuite/multi/3plugins/Plugin2.hs +9/−0
- testsuite/multi/3plugins/Plugin3.hs +7/−0
- testsuite/multi/3plugins/api/API.hs +9/−0
- testsuite/multi/3plugins/prog/Main.hs +13/−0
- testsuite/multi/3plugins/prog/expected +3/−0
- testsuite/objc/expression_parser/ArithmeticExpressionParser.hs +30/−0
- testsuite/objc/expression_parser/English.lproj/Credits.rtf +29/−0
- testsuite/objc/expression_parser/English.lproj/InfoPlist.strings binary
- testsuite/objc/expression_parser/English.lproj/MainMenu.nib/classes.nib +4/−0
- testsuite/objc/expression_parser/English.lproj/MainMenu.nib/info.nib +21/−0
- testsuite/objc/expression_parser/English.lproj/MainMenu.nib/objects.nib binary
- testsuite/objc/expression_parser/English.lproj/MyDocument.nib/classes.nib +13/−0
- testsuite/objc/expression_parser/English.lproj/MyDocument.nib/info.nib +16/−0
- testsuite/objc/expression_parser/English.lproj/MyDocument.nib/keyedobjects.nib binary
- testsuite/objc/expression_parser/English.lproj/MyDocument.nib/objects.nib binary
- testsuite/objc/expression_parser/Info.plist +47/−0
- testsuite/objc/expression_parser/KeyValueParser.hs +33/−0
- testsuite/objc/expression_parser/Makefile +67/−0
- testsuite/objc/expression_parser/MyDocument.h +16/−0
- testsuite/objc/expression_parser/MyDocument.m +52/−0
- testsuite/objc/expression_parser/PluginEvalAux.hs +43/−0
- testsuite/objc/expression_parser/PluginExpressionParser.xcode/project.pbxproj +602/−0
- testsuite/objc/expression_parser/PluginExpressionParser_Prefix.pch +7/−0
- testsuite/objc/expression_parser/README +6/−0
- testsuite/objc/expression_parser/RunHaskell.h +4/−0
- testsuite/objc/expression_parser/dont_test +0/−0
- testsuite/objc/expression_parser/main.m +26/−0
- testsuite/objc/expression_parser/version.plist +16/−0
- testsuite/pdynload/badint/Makefile +5/−0
- testsuite/pdynload/badint/Plugin.hs +4/−0
- testsuite/pdynload/badint/api/API.hs +9/−0
- testsuite/pdynload/badint/prog/Main.hs +18/−0
- testsuite/pdynload/badint/prog/expected +1/−0
- testsuite/pdynload/bayley1/Load.hs +42/−0
- testsuite/pdynload/bayley1/Makefile +5/−0
- testsuite/pdynload/bayley1/Plugin1.hs +6/−0
- testsuite/pdynload/bayley1/Sub/Plugin2.hs +6/−0
- testsuite/pdynload/bayley1/api/API.hs +6/−0
- testsuite/pdynload/bayley1/prog/Main.hs +4/−0
- testsuite/pdynload/null/Makefile +4/−0
- testsuite/pdynload/null/Plugin.hs +5/−0
- testsuite/pdynload/null/api/API.hs +5/−0
- testsuite/pdynload/null/prog/Main.hs +19/−0
- testsuite/pdynload/null/prog/expected +1/−0
- testsuite/pdynload/numclass/Makefile +4/−0
- testsuite/pdynload/numclass/Plugin.hs +5/−0
- testsuite/pdynload/numclass/api/API.hs +5/−0
- testsuite/pdynload/numclass/prog/Main.hs +19/−0
- testsuite/pdynload/numclass/prog/expected +1/−0
- testsuite/pdynload/poly/Makefile +5/−0
- testsuite/pdynload/poly/Plugin.hs +9/−0
- testsuite/pdynload/poly/api/API.hs +12/−0
- testsuite/pdynload/poly/prog/Main.hs +17/−0
- testsuite/pdynload/poly/prog/expected +1/−0
- testsuite/pdynload/poly1/Makefile +4/−0
- testsuite/pdynload/poly1/Plugin.hs +5/−0
- testsuite/pdynload/poly1/api/API.hs +9/−0
- testsuite/pdynload/poly1/prog/Main.hs +18/−0
- testsuite/pdynload/poly1/prog/expected +1/−0
- testsuite/pdynload/should_fail0/Makefile +4/−0
- testsuite/pdynload/should_fail0/Plugin.hs +9/−0
- testsuite/pdynload/should_fail0/api/API.hs +13/−0
- testsuite/pdynload/should_fail0/prog/Main.hs +18/−0
- testsuite/pdynload/should_fail0/prog/expected +1/−0
- testsuite/pdynload/should_fail1/Makefile +5/−0
- testsuite/pdynload/should_fail1/Plugin.hs +5/−0
- testsuite/pdynload/should_fail1/api/API.hs +8/−0
- testsuite/pdynload/should_fail1/prog/Main.hs +17/−0
- testsuite/pdynload/should_fail1/prog/expected +1/−0
- testsuite/pdynload/small/Makefile +4/−0
- testsuite/pdynload/small/Plugin.hs +5/−0
- testsuite/pdynload/small/api/API.hs +9/−0
- testsuite/pdynload/small/prog/Main.hs +18/−0
- testsuite/pdynload/small/prog/expected +1/−0
- testsuite/pdynload/spj1/Makefile +5/−0
- testsuite/pdynload/spj1/Plugin.hs +17/−0
- testsuite/pdynload/spj1/api/API.hs +9/−0
- testsuite/pdynload/spj1/dont_test +0/−0
- testsuite/pdynload/spj1/prog/Main.hs +17/−0
- testsuite/pdynload/spj1/prog/expected +0/−0
- testsuite/pdynload/spj2/Makefile +5/−0
- testsuite/pdynload/spj2/Plugin.hs +13/−0
- testsuite/pdynload/spj2/api/API.hs +6/−0
- testsuite/pdynload/spj2/prog/Main.hs +17/−0
- testsuite/pdynload/spj2/prog/expected +1/−0
- testsuite/pdynload/spj3/Makefile +3/−0
- testsuite/pdynload/spj3/Plugin.hs +5/−0
- testsuite/pdynload/spj3/api/API.hs +9/−0
- testsuite/pdynload/spj3/prog/Main.hs +18/−0
- testsuite/pdynload/spj3/prog/expected +8/−0
- testsuite/pdynload/spj3/prog/expected.604 +9/−0
- testsuite/pdynload/spj3/prog/expected.605 +9/−0
- testsuite/pdynload/spj4/Makefile +5/−0
- testsuite/pdynload/spj4/Plugin.hs +16/−0
- testsuite/pdynload/spj4/api/API.hs +5/−0
- testsuite/pdynload/spj4/prog/Main.hs +17/−0
- testsuite/pdynload/spj4/prog/expected +1/−0
- testsuite/pdynload/typealias/Makefile +5/−0
- testsuite/pdynload/typealias/Plugin.hs +3/−0
- testsuite/pdynload/typealias/api/API.hs +8/−0
- testsuite/pdynload/typealias/prog/Main.hs +19/−0
- testsuite/pdynload/typealias/prog/expected +1/−0
- testsuite/pdynload/univquant/Makefile +4/−0
- testsuite/pdynload/univquant/Plugin.hs +8/−0
- testsuite/pdynload/univquant/api/API.hs +9/−0
- testsuite/pdynload/univquant/prog/Main.hs +17/−0
- testsuite/pdynload/univquant/prog/expected +1/−0
- testsuite/pkgconf/null/Makefile +16/−0
- testsuite/pkgconf/null/Null.hs +6/−0
- testsuite/pkgconf/null/api/API.hs +10/−0
- testsuite/pkgconf/null/api/package.conf.in +18/−0
- testsuite/pkgconf/null/dont_test +0/−0
- testsuite/pkgconf/null/prog/Main.hs +12/−0
- testsuite/plugs/plugs/Main.hs +69/−0
- testsuite/plugs/plugs/Makefile +28/−0
- testsuite/plugs/plugs/expected +9/−0
- testsuite/plugs/plugs/test.in +2/−0
- testsuite/plugs/runplugs/Main.hs +57/−0
- testsuite/plugs/runplugs/Makefile +30/−0
- testsuite/plugs/runplugs/expected +1/−0
- testsuite/plugs/runplugs/test.in +1/−0
- testsuite/reload/null/Makefile +4/−0
- testsuite/reload/null/Null.hs +11/−0
- testsuite/reload/null/api/API.hs +12/−0
- testsuite/reload/null/prog/Main.hs +19/−0
- testsuite/reload/null/prog/expected +2/−0
- testsuite/shell/shell/API.hs +8/−0
- testsuite/shell/shell/Main.hs +85/−0
- testsuite/shell/shell/Makefile +2/−0
- testsuite/shell/shell/Plugin.hs +5/−0
- testsuite/shell/shell/Plugin.stub +19/−0
- testsuite/shell/shell/README +23/−0
- testsuite/shell/shell/dont_test +0/−0
- testsuite/shell/simple/Main.hs +41/−0
- testsuite/shell/simple/Makefile +6/−0
- testsuite/shell/simple/Plugin.hs +5/−0
- testsuite/shell/simple/Plugin.stub +19/−0
- testsuite/shell/simple/README +23/−0
- testsuite/shell/simple/StringProcessorAPI.hs +8/−0
- testsuite/shell/simple/dont_test +0/−0
- testsuite/unload/null/Makefile +4/−0
- testsuite/unload/null/Null.hs +11/−0
- testsuite/unload/null/api/API.hs +12/−0
- testsuite/unload/null/prog/Main.hs +11/−0
- testsuite/unload/null/prog/expected +1/−0
- testsuite/unload/sjwtrap/Makefile +4/−0
- testsuite/unload/sjwtrap/Null.hs +6/−0
- testsuite/unload/sjwtrap/api/API.hs +9/−0
- testsuite/unload/sjwtrap/prog/Main.hs +15/−0
- testsuite/unload/sjwtrap/prog/expected +1/−0
- testsuite/unloadAll/null/Dep.hs +7/−0
- testsuite/unloadAll/null/Makefile +4/−0
- testsuite/unloadAll/null/Null.hs +12/−0
- testsuite/unloadAll/null/api/API.hs +12/−0
- testsuite/unloadAll/null/prog/Main.hs +15/−0
- testsuite/unloadAll/null/prog/expected +2/−0
+ AUTHORS view
@@ -0,0 +1,5 @@++Don Stewart <http://www.cse.unsw.edu.au/~dons>+Sean Seefried <http://www.cse.unsw.edu.au/~sseefried>+Andre Pang <http://www.algorithm.com.au>+
+ README view
@@ -0,0 +1,111 @@++------------------------------------------------------------------------+ hs-plugins+------------------------------------------------------------------------++Compiler and tool support for compiling and loading, and evaluating+Haskell at runtime. ++The library provides a convenient interface to GHC's runtime loader+and linker, letting you load compiled Haskell code. ++It also provides a `make' system for compiling plugin source+automagically and for combining the user's .hs file with a stub of+standard declarations and syntax, saving the user from having to write+standard code themselves.++It provides an `eval' function, for generating new, well-typed, compiled+code from a Haskell source string.++It also provides a new variation of printf for Haskell-- a runtime+generated, dynamically-typed printf.++Read the documentation in doc/ for more.++------------------------------------------------------------------------++BUILDING:+ $ chmod +x Setup.lhs configure+ $ ./Setup.lhs configure --prefix=/usr/local+ $ ./Setup.lhs build+ $ ./Setup.lhs install++------------------------------------------------------------------------++DEPENDENCIES:++* Requires GHC >= 6.4+* Requires Cabal++------------------------------------------------------------------------++* Optional:+ If you are doing a lot of `merge'-related operations, and require+ an extended haskell parser, you can compile hs-plugins to use + HSX, Niklas Broberg's Haskell parser library, available at:++ darcs get http://www.cs.chalmers.se/~d00nibro/haskell-src-exts++ To get hs-plugins to use HSX, use: ++ $ mv plugins.cabal.hsx plugins.cabal+ $ ./Setup.lhs configure --enable-hsx++ Make sure to install HSX first though :)++------------------------------------------------------------------------++* On cygwin/windows you (a) make sure the cygwin "find" is before the+ windows "find" on your PATH, and (b) to give the windows-style path+ (e.g., "c:/cygwin/usr/local") in the ./configure --prefix=foo/bar+ step++* 'plugs' requires a working readline library.++* If you wish to use TH in plugins, or to run load()-programs in GHCi,+ you require a patch to GHC's linker, that was committed into ghc+ 6.3, and ghc 6.2 -stable branch, and is available from 6.2.2 onwards.++* If you need to regenerate ./configure you need >= autoreconf-2.53++* The documentation relies on haddock, latex, dvips, tex2page:++ $ cd doc && make++------------------------------------------------------------------------++EXAMPLES:++Have a look in the testsuite/ directory for many examples of how to+arrange your code.++LICENSE:++This library is distributed under the terms of the LGPL. The runtime+loader code is based on code written by André Pang, and others, and is+distributed under the BSD-style Glasgow University license.++PORTABILITY:++Requires GHC 6.4 or greater, though most testing has be done on 6.4.+The dynamic loader requires a functional GHCi implementation.++---------------------+--------------------------------------------------+ Platform | Works Should work* Unknown Won't work+---------------------+--------------------------------------------------+i386-*-linux | X+i386-*-freebsd | X+i386-*-openbsd | X +powerpc-apple-darwin | X +powerpc-*-linux | X +sparc-*-solaris2 | X +ia64-*-linux | #+i386-*-solaris2 | X+sparc-*-linux | X+sparc-*-openbsd | X+i386-*-netbsd | X +amd64-*-openbsd | X+mips64-sgi-irix | X+---------------------+--------------------------------------------------++# .hi file parsing is currently broken
+ TODO view
@@ -0,0 +1,26 @@+For 1.0+----------+++ broken on mac.+symbols with suspiciously many _ chars+++ Add verbose versions of the load functions, to avoid -DDEBUG+++ mention that you need .o archives, not .a ones. Use Cabal, ghc-pkg -u+ or ld -r --whole-archive+++ hs-plugins doesn't know to look for packages in the user packages,+only in the global packages+++ version numbers in package loads are annyoing+++ .hi file parser is broken on Itanium, again.+++ build way=p and way=''++Cabal+--------++What we'd like is a cabalMake version of make, so rather than just+compiling simple plugins, we let cabalMake rebuild whole Haskell apps --+like Yi!
+ docs/Makefile view
@@ -0,0 +1,31 @@+# Copyright (c) 2004 Don Stewart - http://www.cse.unsw.edu.au/~dons+# LGPL version 2.1 or later (see http://www.gnu.org/copyleft/lesser.html)++.PHONY: build clean html++SRC = hs-plugins++build: $(SRC).ps html++$(SRC).ps: $(SRC).dvi+ dvips -f $(SRC).dvi > $@++html: $(SRC).tex+ tex2page $(SRC)+ tex2page $(SRC)+ sed -f munge.sed < $(SRC)/$(SRC).html > tmp.out+ mv tmp.out $(SRC)/$(SRC).html+ cp $(SRC)/$(SRC).html $(SRC)/index.html+ tar czf $(SRC).html.tar.gz $(SRC)+ mv $(SRC).html.tar.gz $(SRC)/++$(SRC).dvi: $(SRC).tex+ latex $(SRC).tex && latex $(SRC).tex++CLEANS= *.{ps,dvi,aux,log} *~ hs-plugins *-Z-* *.toc++clean: + rm -rf $(CLEANS)++all: doc+
+ docs/haskell.sty view
@@ -0,0 +1,452 @@+%%% This is a LaTeX2e style file.+%%%+%%% It supports setting functional languages like Haskell.+%%%+%%% Manuel M. T. Chakravarty <chak@cse.unsw.edu.au> [1998..2000]+%%%+%%% $Id: haskell.sty,v 1.2 2004/05/16 08:20:09 dons Exp $+%%%+%%% This file is free software; you can redistribute it and/or modify+%%% it under the terms of the GNU General Public License as published by+%%% the Free Software Foundation; either version 2 of the License, or+%%% (at your option) any later version.+%%%+%%% This file is distributed in the hope that it will be useful,+%%% but WITHOUT ANY WARRANTY; without even the implied warranty of+%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+%%% GNU General Public License for more details.+%%%+%%% Acknowledegments ==========================================================+%%%+%%% Thanks to Gabriele Keller <keller@cs.tu-berlin.de> for beta testing and+%%% code contributions. Thanks to the LaTeX3 project for improving the LaTeX+%%% sources (which helped me writing this code). Furthermore, I am grateful+%%% to Martin Erwig <Martin.Erwig@FernUni-Hagen.de> for feedback and+%%% suggestions, and to Conal Elliott <conal@MICROSOFT.com> for pointing out+%%% a tricky bug.+%%%+%%% TODO ======================================================================+%%%+%%% B ~ bug; F ~ feature+%%%+%%% * F: Along the lines of the discussion with Martin Erwig add support for+%%% keywords etc (see the emails)+%%%+%%% * B: If we have as input +%%%+%%% \<map+%%% g\>+%%%+%%% there won't be a `\hsap' inserted!! (Can this be solved by using+%%% \obeylines in \<...\>?)+%%%+%%% * B: A \relax is needed after a & if it immediately followed by a \hsbody{}+%%% (See TeXbook, S.240)+%%%+%%% * F: Implement a \hstext{...} as \(\text{...}\).+%%%+%%% * We would like hswhere* etc that are like haskell* (\hsalign already+%%% supports this, ie, there is a \hsalign*).+%%%+%%% * Star-Versions of if, let etc that use a single line layout (maybe not+%%% with star, because of the above).+%%%+%%% * Support for enforcing and prohibiting breaks in `haskell' displays.+%%%+%%% * Comments in a let-in should be aligned in the same way for the bindings+%%% and the body.+%%%+%%% * It would be nice to have different styles (indentation after in of+%%% let-in or not) etc; either to be set with a package option or in the+%%% preamble (the latter probably makes more sense). +%%%+%%% * Literate programming facility: Variant of the `haskell' env (maybe+%%% `hschunk', which is named and can be used in other chunks). But maybe+%%% it is not necessary to provide a chunk-based reordering mechanism,+%%% because most of the Haskell stuff can be in any order anyway...+%%% Important is to provide a way to define visually pleasing layout+%%% together with the raw Haskell form for program output. (Maybe `haskell*' +%%% as Haskell env that outputs its contents?)+%%%++%% Initialization+%% ==============++\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{haskell}[2000/10/05 v1.0e Chilli's Haskell Style]+++%% Parameters+%% ==========++\newskip\hsmargin+\hsmargin\leftmargini+++%% Main macros and environments+%% ============================++% applications+%+\newcommand{\hsap}{% % application by juxtaposition+ \unskip\mskip 4mu plus 1mu} % only the last \hsap counts++% commands to start and stop setting spaces as \hsap+%+{\obeyspaces\gdef\@hsSpaceToApp{\obeyspaces\let =\hsap}} % spaces matter!!!+{\obeyspaces\gdef\@hsNormalSpace{\let =\space}}++% commands to start and stop treating numbers specially, ie, we don't want+% them to be affected by font changing commands in Haskell contexts as this+% would give italic numerals; the trick is to redefine their math code such+% that they go into math class 0 and thus don't change families (cf. `The+% TeXbook', Chapter 17, pp152)+%+\newcommand{\@hsRmNumbers}{%+ \mathcode`0="0030+ \mathcode`1="0031+ \mathcode`2="0032+ \mathcode`3="0033+ \mathcode`4="0034+ \mathcode`5="0035+ \mathcode`6="0036+ \mathcode`7="0037+ \mathcode`8="0038+ \mathcode`9="0039+ }+\newcommand{\@hsNormalNumbers}{%+ \mathcode`0="7030+ \mathcode`1="7031+ \mathcode`2="7032+ \mathcode`3="7033+ \mathcode`4="7034+ \mathcode`5="7035+ \mathcode`6="7036+ \mathcode`7="7037+ \mathcode`8="7038+ \mathcode`9="7039+ }++% Save the bindings of the standard math commands+%+% This is somewhat subtle as we want to able to enter the original math mode+% within Haskell mode and we have to ensure that the different opening+% commands are matched by the correct versions of the closing commands.+%+\let\@hsmathorg=\(+\let\@hsmathendorg=\)+\let\hs@crorg=\\+\newcommand{\@hsmath}{%+ \relax\hbox\bgroup+ \@hsNormalSpace+ \@hsNormalNumbers+ \let\(=\@hsmathorgx+ \let\)=\@hsmathend+ \def\\{\hs@crorg}%+ \@hsmathorg+ }+\newcommand{\@hsmathend}{%+ \@hsmathendorg+ \egroup+ }+\newcommand{\@hsmathorgx}{%+ \relax\@hsmathorg+ \let\)=\@hsmathendorg+ }++%% Typesetting of Haskell+%% ======================++% Inline Haskell phrases are delimited by `\<' and `\>'.+%+% Note: `\>' is only locally redefined.+% +\newcommand{\<}{%+ \@hsmathorg+ \mathit\bgroup+ \@hsSpaceToApp+ \@hsRmNumbers+ \let\>=\@endhs+ \let\(=\@hsmath + \def\\{\cr} % for Haskell alignments+ }+\newcommand{\@endhs}{%+ \egroup+ \@hsmathendorg+ }++% Displayed Haskell (environment `haskell' and `haskell*')+%+% There are two kind of preambles for \halign: \hs@preambleNorm is for +% `amsmath' style alignments and \hs@preambleStar for `equation' style+% alignments (but with an unbound number of columns to its right)+%+% We need #### to get a ## in the \edef building the \halign command.+%+% first the preambles (also used in \hs@align below):+%+\def\hs@preambleNorm{%+ \noexpand\<####\unskip\noexpand\>\hfil&&\noexpand%+ \<{}####\unskip\noexpand\>\hfil}+\def\hs@preambleStar{%+ \noexpand\<####\unskip\noexpand\>\hfil&\hfil\noexpand%+ \<{}####\unskip{}\noexpand\>\hfil&&\noexpand\<{}####\noexpand\>\hfil}+%+% the environments:+%+\newenvironment{haskell}{%+ \@haskell\hs@preambleNorm}{%+ \@endhaskell+ }+\newenvironment{haskell*}{%+ \@haskell\hs@preambleStar}{%+ \@endhaskell+ }+%+% auxiliary definition getting the preamble as its first argument and starting +% the environment:+%+\def\@haskell#1{%+ \bgroup+ \vspace\abovedisplayskip+ \let\(=\@hsmath % Important when `\(' occurs after `&'! + \edef\@preamble{%+ \halign\bgroup\hskip\hsmargin#1\cr}+ \@preamble+ }+%+% Auxiliary definition ending environment:+%+\def\@endhaskell{%+ \crcr\egroup+ \vspace\belowdisplayskip+ \egroup\noindent\ignorespaces\global\@ignoretrue%+ }++% single line comment and keyword style+%+\newcommand{\hscom}[1]{%+ \relax\(\quad\textnormal{--- #1}\)}+\newcommand{\hskwd}[1]{%+ \mathbf{#1}}++% informal description+%+\newcommand{\hsinf}[1]{%+ \(\langle\textnormal{#1}\rangle\)}++% literals and some special symbols+%+\newcommand{\hschar}[1]{\textrm'\mathrm{#1}\textrm'} % character literals+\newcommand{\hsstr}[1]{"\mathrm{#1}"} % strings literals+\newcommand{\hsfrom}{\leftarrow} % <-++% aligned subphrases+%+% check for an optional star and combine prefix (in #1) with one of the two+% preambles (with star means to center the material between the first and+% second &) +%+\def\hs@align#1{%+ \@ifstar+ {\hs@align@pre{#1\hs@preambleStar}}%+ {\hs@align@pre{#1\hs@preambleNorm}}%+ }+%+% test for optional argument; #1: preamble+%+\def\hs@align@pre#1{%+ \@testopt{\hs@align@prealign#1}t}+%+% got all arguments, now for the real code; #1: preamble; #2: alignment; +% #3: body (the material set by the \halign)+%+\def\hs@align@prealign#1[#2]#3{%+ \relax\(+ \edef\@preamble{%+ \halign\bgroup#1\cr}+ \if #2t\vtop \else \if#2b\vbox \else \vcenter \fi\fi+ \bgroup%+ \@preamble+ #3%+ \crcr\egroup%+ \egroup\)+ }+%+% user-level command: alignment without a prefix+%+\newcommand{\hsalign}{%+ \relax+ \hs@align\relax%+ }++% subphrase breaking the surrounding alignment being flushed left+%+\newcommand{\hsnoalign}[1]{%+ \noalign{%+ \hs@align{\hskip\hsmargin}{#1}%+ }%+ }++% body expression breaking the surrounding alignment+%+% * setting \hsmargin to 0pt within the preamble (and _after_ it is used in+% the preamble) is crucial, as we want \hsmargin only to be applied in+% _outermost_ alignments+%+\newcommand{\hsbody}[1]{%+ {}\\+ \noalign{%+ \hs@align{\hskip\hsmargin\quad\hsmargin0pt}{#1}%+ }%+ }+++%% Defining commands for use in the Haskell mode+%% =============================================+%%+%% We use some of the low-level machinery defined in LaTeX's source file+%% `ltdefns.dtx'.+%%+%% \hscommand is similar to \newcommand, but there is no *-version.+%%+%% We use our own definitions here to insert a strategic `\relax' (see below)+%% and to obey spaces within the bodies of Haskell definitions.++\newcommand{\hscommand}[1]{\@testopt{\hs@newcommand#1}0}+\def\hs@newcommand#1[#2]{%+ \obeyspaces % spaces count in Haskell macros+ \@ifnextchar [{\hs@xargdef#1[#2]}%+ {\hs@argdef#1[#2]}}++% All this trouble only to be able to add the `\relax' into the expansion+% process. If we don't that, commands without optional arguments when+% invoked after an alignment character & don't work properly (actually, the+% \obeyspaces doesn't work). I am sure that has to do with the scanning for+% \omit etc in \halign (TeXbook, p240), but I don't understand yet why it+% is problematic in this case.+%+% Furthermore, we switch off \obeyspaces in the end.+%+\long\def\hs@argdef#1[#2]#3{%+ \@ifdefinable#1{%+ \expandafter\def\expandafter#1\expandafter{%+ \relax % in order to stop token expansion after &+ \csname\string#1\expandafter\endcsname}%+ \expandafter\@yargdef+ \csname\string#1\endcsname+ \@ne+ {#2}%+ {#3}}%+ \catcode`\ =10% % stop obeying spaces now+ }++% Switch off \obeyspaces in the end.+%+\long\def\hs@xargdef#1[#2][#3]#4{%+ \@ifdefinable#1{%+ \expandafter\def\expandafter#1\expandafter{%+ \expandafter+ \@protected@testopt+ \expandafter+ #1%+ \csname\string#1\expandafter\endcsname+ {#3}}%+ \expandafter\@yargdef+ \csname\string#1\endcsname+ \tw@+ {#2}%+ {#4}}%+ \catcode`\ =10% % stop obeying spaces now+ }+++%% Abbreviations+%% =============++% infix operators+%+\newcommand{\hsapp}{\mathbin{+\mkern-7mu+}}+\newcommand{\hsifix}[1]{\mathbin{\string`#1\string`}}++% let expression+%+\hscommand{\hslet}[3][t]{%+ \hsalign[#1]{%+ \hskwd{let}\\+ \quad\hsalign{#2}\\+ \hskwd{in}\\+ #3+ }%+ }+ +% if expression+%+\hscommand{\hsif}[4][t]{%+ \hsalign[#1]{%+ \hskwd{if} #2 \hskwd{then}\\+ \quad\hsalign{#3}\\+ \hskwd{else}\\+ \quad\hsalign{#4}% + }%+ }++% case expression+%+\hscommand{\hscase}[3][t]{%+ \hsalign[#1]{%+ \hskwd{case} #2 \hskwd{of}\\+ \quad\hsalign{#3}%+ }%+ }+ +% where clause+%+% * it is important to take the \quad into the preamble, so that nested+% \noaligns can break it+%+\hscommand{\hswhere}[1]{%+ \hsbody{%+ \hskwd{where}\\+ \hs@align{\quad}{#1}%+ }%+ }++% do expression+%+\hscommand{\hsdo}[2][t]{%+ \hsalign[#1]{%+ \hskwd{do}\\+ \quad\hsalign{#2}\\+ }%+ }+++%% Extensions for Distributed Haskell (Goffin)+%% ===========================================+%%+%% These definitions may change in the future.++\hscommand{\hsunif}{\mathbin{:=:}}+\hscommand{\hsalias}{\mathrel{\sim}}+\hscommand{\hsoutof}{\twoheadleftarrow}+\hscommand{\hsinto}{\twoheadrightarrow}+\hscommand{\hsparc}{\binampersand}+\hscommand{\hsseq}{\Longrightarrow}+\hscommand{\hsex}[2]{{\hskwd{ex} #1 \hskwd{in} #2}}++\hscommand{\hsexin}[3][t]{%+ \hsalign[#1]{%+ \hskwd{ex} #2 \hskwd{in}\\+ \quad\hsalign{#3}\\+ }%+ }++\hscommand{\hschoice}[2][t]{%+ \hsalign[#1]{%+ \hskwd{choice}\\+ \quad\hsalign{#2}\\+ }%+ }++
+ docs/hs-plugins.1 view
@@ -0,0 +1,36 @@+.TH HS-PLUGINS 1 2005-12-27 "hs-plugins version 1.0" "User Manual"++.SH NAME+hs-plugins \- dynamic linker library for Haskell++.SH DESCRIPTION+.ds c \fIhs-plugins\fP+\*c is a library for loading code written in Haskell into an+application at runtime, in the form of plugins. It also provides a+mechanism for (re-)compiling Haskell source at runtime. Thirdly, a+combination of runtime compilation and dynamic loading provides a set+of eval functions. Values exported by plugins are transparently+available to Haskell host applications, and bindings exist to use+Haskell plugins from at least C and Objective C programs. hs-plugins+requires GHC 6.4 or later.++.SH DOCUMENTATION+The hs-plugins user manual is distributed in html format, and may be+found at <http://www.cse.unsw.edu.au/~dons/hs-plugins/>++.SH BUGS+Bug reports, and any other feedback, should be sent to+Don Stewart <dons@cse.unsw.edu.au>+.SH COPYRIGHT+Copyright \(co 2003-2005 Don Stewart+.PP+The hs-plugins library modules are distributed under the terms of the+LGPL.+.SH "SEE ALSO"+.BR dlopen (3)++.SH AUTHOR++This manual page was written by Don Stewart, based on the man page for+cpphs (written by Ian Lynagh).+
+ docs/hs-plugins.hdir view
@@ -0,0 +1,1 @@+hs-plugins
+ docs/hs-plugins.tex view
@@ -0,0 +1,1804 @@+\documentclass{article}++\usepackage{url}+\usepackage{tex2page}++% typeset math as ascii+\htmlmathstyle{no-in-text-image no-display-image}++% something other than |+\verbescapechar\&++\cssblock +h1 {font-size: 16pt}+h2 {font-size: 15pt}+\endcssblock ++% color of verbatim elements+\cssblock+.verbatim {color: grey20}++.scheme .variable {color: grey20} +.scheme .keyword {color: navy}+.scheme .builtin {color: maroon}+\endcssblock++% add some extra keywords+\scmkeyword{as case class data default deriving do else hiding if}+\scmkeyword{import in infix infixl infixr instance let module newtype}+\scmkeyword{of qualified then type where forall \\ }+\scmbuiltin{: :: = -> <- @ ~ => - >>= >> }++\newcommand{\code}[1]{{\texttt{#1}}}+\newcommand{\hsplugins}{{\texttt{hs-plugins}}}++\title{hs-plugins\\+ Dynamically Loaded Haskell Modules}++\author{\urlh{http://www.cse.unsw.edu.au/~dons}{Don Stewart}}++\begin{document}++\maketitle++\medskip+%+{\htmlonly \textbf{Download \endhtmlonly +\urlh{ftp://ftp.cse.unsw.edu.au/pub/users/dons/hs-plugins/hs-plugins-1.0.tar.gz}+ {version 1.0}}+%+\medskip++\hsplugins{} is a library for loading code written in Haskell into an+application at runtime, in the form of plugins. It also provides a+mechanism for (re-)compiling Haskell source at runtime. Thirdly, a+combination of runtime compilation and dynamic loading provides a set of+\code{eval} functions-- a form of runtime metaprogramming. Values+exported by Haskell plugins are transparently available to Haskell host+applications, and bindings exist to use Haskell dynamically in C, Perl+and Objective C programs. \hsplugins{} requires GHC 6.4 or later.++\medskip++% grr. double spaced.++\tableofcontents++\newpage++\section{Download}++\begin{itemize}++\item+Download the latest stable release:\\+\url{ftp://ftp.cse.unsw.edu.au/pub/users/dons/hs-plugins/hs-plugins-1.0.tar.gz}++\item+Darcs repository of the latest code:\\+\url{darcs get http://www.cse.unsw.edu.au/~dons/code/hs-plugins}++\item+A tarball of the document you are reading:\\+\url{http://www.cse.unsw.edu.au/~dons/hs-plugins/hs-plugins.html.tar.gz}++\item+A postscript version of the document you are reading:\\+\url{http://www.cse.unsw.edu.au/~dons/hs-plugins/hs-plugins.ps.gz}++\item+Papers:+\begin{itemize}+\item A paper on interesting uses of \hsplugins{} to enable Haskell to be used+as an application extension language:\\+\url{http://www.cse.unsw.edu.au/~dons/papers/PSSC04.html}++\item+A paper on dynamic applications in Haskell, utilizing \hsplugins{}:\\+\url{http://www.cse.unsw.edu.au/~dons/papers/SC05.html}+\end{itemize}++\end{itemize}++It is known to run on \code{i386-\{linux,freebsd,openbsd\}},+\code{sparc-solaris2}, \code{powerpc-\{macosx,linux\}} and flavours of+Windows.++\section{History}++\begin{itemize}+ \item Jan 2006, v1.0+ \begin{itemize}+ \item Cabalised build system+ \item Behave better on 64 bit platforms+ \item Haddock documentation of the API.+ \item A couple of bug fixes+ \end{itemize}++ \item June 2005, v0.9.10+ \begin{itemize}+ \item Support for GHC 6.4, with help from Sean+ Seefried for the package.conf parser.+ \item Ported to Windows of various flavours thanks to Vivian McPhail and Shelarcy+ \item Removed posix and unix dependencies+ \item Now uses HSX parser, thanks to Niklas Broberg+ \item Extended load interface, thanks to Lemmih+ \item Source now in a darcs repository+ \item Supports building with GNU make -jN+ \item Simplified module hierarchy, moved under System.* namespace+ \item pdynload clarifications, thanks to Alistair Bayley + \item Miscellaneous bug fixes+ \end{itemize}++ \item February 2005, v0.9.8+ \begin{itemize}+ \item Fix bug in .hi parsing. + \item Add reloading of packages. + \item Fix bug in canonical module names + (fixing problems with "Foo.o" and "./Foo.o"+ \item Fix for hierarchical names, don't guess them,+ read them from the .hi file.+ \item Add new varients of load.+ \item Fix bug in makeAll, such that dependent module+ changes were not noticed.+ \item Add varient of eval:\code{ unsafeEval\_}, returing+ Either.+ \item Better, bigger testsuite.+ \item Better api.+ \end{itemize}++ \item September 2004.+ \begin{itemize}+ \item makeAll+ \item Better return type for make.+ \end{itemize}++ \item Mid August 2004, v0.9.6 release.+ \begin{itemize}+ \item More portable, thanks to debugging by Niklas Broberg.+ \item Other small fixes to the interfaces.+ \item Provides a runtime-generated printf.+ \end{itemize}++ \item Mid July 2004, added new pdynload strategy.++ \item Mid-June 2004, v0.9.5 release.+ \begin{itemize}+ \item dynamic typing is working++ \item static typing of interfaces is working++ \item Adds \code{eval}, and \code{hs\_eval}++ \item bugs fixed.+ \end{itemize}++ \item Early-June 2004, v0.9.4 release. + \begin{itemize}++ \item Adds a .hi file parser. We use this to work out+ plugin dependencies directly, meaning no more+ \code{.dep} files or \code{ghcp}. ++ \item It also adds a package.conf parser, meaning we+ can properly handle packages that either aren't stored+ in the normal location, don't have a canonical name,+ or are found using a -package-conf argument. Thanks to+ Sean for this work. ++ \item the interface to load() has changed to allow a+ list of package.conf files to search for packages.++ \item the interace to make() has changed, so that you+ can get back any stderr output produced during plugin+ compilation.++ \item It solves a bug whereby a package that is+ required by another package would not be loaded unless+ the plugin itself depended on this indirect package.++ \item more stable, more examples.+ \end{itemize}++ \item May 2004, v0.9.3 released, adding support for dependency+ conflict resolution between multiple plugins. Several plugins with+ shared dependencies can now be safely loaded at once. --prefix is now+ respected in ./configure. Thanks to Sean for this patch.++ \item v0.9.2 change licence to LGPL++ \item v0.9.1 expand on the documentation++ \item v0.9 released, initial source release++\end{itemize}++\section{Acknowledgements}++\begin{itemize}++\item Andr\'e Pang's \code{runtime\_loader} was the inspiration and basis+of the dynamic loader (\url{http://www.algorithm.com.au}).+\hsplugins{} has benefited from many discussions with him,+particularly to do with dependency checking and dynamic typing, and+bug reports. Andr\'e wrote an objective C binding to hs-plugins, and+helped with the design of eval(). He also fixed GHC so we could load+the dynamic loader dynamically.++\item Sean Seefried (\url{http://www.cse.unsw.edu.au/~sseefried}) was+the first user of \hsplugins{} and his code and feedback have helped+make the library much more useful and powerful.++\item Manuel Chakravarty's \code{take} system provided the basis for+\code{make}, and helped with several issues to do with safety of+plugins, apis and the applications that use them.+Manuel also helped with the design of eval(), and on how to+successfully evaluate polymorphic functions using rank-N types.++\item Simon Marlow helped with several issues to do with linking and+loading static and dynamic code, and provided many useful suggestions.++\item Hampus Ram's dynamic loader+(\url{http://www.dtek.chalmers.se/~d00ram/dynamic/}) provided the+design of the state maintained by the loader, and for thread safety+issues relating to this.++\item Shae Erisson provided several insights into more powerful uses+of the library. Thanks to everyone on \#haskell who provided+discussion about the library.++\item Malcolm Wallace's \code{hmake} provided some useful insights in+how to compile Haskell source in a way that makes it appear like an+interpreter, used in the interactive environment: \code{plugs}.++\item Niklas Broberg helped a lot by testing, and providing feedback for+the new make and load API. Thanks Niklas.++\item Finally, thanks to everyone who has worked on GHC and its+libraries: for GHCi, the .hi interface parser, the package system, and+all the other code the \hsplugins{} depends on.++\end{itemize}++\newpage++\section{Overview}++\hsplugins{} is a library for compiling and loading Haskell code into a+program at runtime. It allows you to write Haskell code (which may+be spread over multiple modules), and have an application (implemented in+any language with a Haskell FFI binding, including Haskell) load and use+your code at runtime.++\hsplugins{} provides 3 major features:+%+\begin{itemize}+ \item a dynamic loader,+ \item a compilation manager, and+ \item a Haskell evaluator+\end{itemize}++The \emph{dynamic loader} loads objects into the address space of an+application, along with any dependencies the plugin may have. The+loader is a binding to the GHC runtime system's dynamic linker, which+does single object loading. GHC also performs the necessary linking of+new objects into the running process. On top of the GHC loader is a+Haskell layer that arranges for module and package dependencies to be+found prior to loading individual modules.++The \emph{compilation manager} is a \code{make}-like system for+compiling Haskell source code into a form suitable for loading. While+plugins are normally thought of as strictly object code, there are a+variety of scenarios where it is desirable to be able to inspect the+source code of a plugin, or to be able to recompile a plugin at runtime.+The compilation manager fills this role. It is particularly useful in+the implementation of \code{eval}.++The \emph{evaluator}, \code{eval}, utilizes the loader and compilation+manager. When passed a string containing a Haskell expression, it+compiles the string to object code, loads the result, and returns a+Haskell value representing the compiled string to the caller. It can be+considered a Haskell interpreter, implemented as a library, and can be+used to embed Haskell evaluation facilities in an application.++\section{Dynamic Loader}++The interface to the \hsplugins{} library can be divided into a number+of sections representing the functional units of the library.+Additionally, depending on the level of trust the application places+in the plugins, a variety of additional checks can be made on the+plugin as it is loaded. The levels of type safety possible are+summarised at the end of Section \ref{sec:compilation-manger} section.+The dynamic loader is available by using \code{-package plugins}.++\subsection*{Interface}+%+\begin{quote}+\scm{+import System.Plugins++load :: FilePath + -> [FilePath] + -> [PackageConf] + -> Symbol + -> IO (LoadStatus a)+}++\scm{+load_ :: FilePath + -> [FilePath] + -> Symbol + -> IO (LoadStatus a)+}++\scm{+data LoadStatus a+ = LoadSuccess Module a + | LoadFailure Errors+}+\end{quote}+%+Example:+%+\begin{quote}+\scm{+do mv <- load "Plugin.o" ["api"] [] "resource"+ case mv of+ LoadFailure msg -> print msg+ LoadSuccess _ v -> return v+}+\end{quote}+%+This is the basic interface to the dynamic loader. Load the object file+specified by the first argument into the address space (the library will+preload any module or package dependencies). The second argument is an+include path to any additional objects to load (possibly the API of the+plugin). The third argument is a list of paths to any user-defined+\code{package.conf} files, specifying packages unknown to the GHC+package system. \code{Symbol} is a string specifying the symbol name you+wish to lookup. \code{load} returns a \code{LoadStatus} value representing+failure, or an abstract representation of the module (for calls to+\code{unload} or \code{reload}) with the symbol as a Haskell value. The+value returned must be given an explicit type signature, or provided+with appropriate type constraints such that GHC can determine the+expected type returned by \code{load}.++\code{load\_} is provided for the common situation where no user-defined+package.conf files are required.++\begin{quote}+\scm{+dynload :: Typeable a + => FilePath + -> [FilePath]+ -> [PackageConf]+ -> Symbol+ -> IO (LoadStatus a)+}+\end{quote}+%+Example:+%+\begin{quote}+\scm{+do mv <- dynload "Plugin.o" ["api"] ["plugins.conf.inplace"] "resource"+ case mv of+ LoadFailure msg -> print msg+ LoadSuccess _ v -> putStrLn v+}+\end{quote}+%+\code{dynload} is a safer form of \code{load}. It uses dynamic types+to perform a check on the value returned by \code{load} at runtime, to+ensure that it has the type the application expects it to have.++In order to use \code{dynload}, the symbol the plugin exports must be+of type \code{AltData.Dynamic:Dynamic}. (See the \code{AltData} library+distributed with \hsplugins{}, and the \hsplugins{}+\code{examples/dynload} directory. References to \code{Typeable} and+\code{Dynamic} refer to the \hsplugins{} reimplementation of these+libraries. \code{AltData.Dynamic} is used at the moment, as there is a+limitation in the existing Data.Dynamic library in the presence of+dynamic loading).++The value wrapped up in the \code{Dynamic} must be an instance of+\code{AltData.Typeable}. If the value exported by the plugin \emph{is}+of type \code{Dynamic}, and the value wrapped by the \code{Dynamic}+does not match the type expected of it by the application,+\code{dynload} will return \code{Nothing}, indicating that the plugin+is not typesafe with respect to the application. If the value passes+the typecheck, \code{dynload} will return \code{LoadSuccess}. If the value+exported by the plugin is \emph{not} of type \code{Dynamic},+\code{dynload} will crash---this is a limitation of the existing+\code{Dynamic} library, it can only type-check \code{Dynamic} values.+Additionally, Data.Dynamic is limited to monomorphic types, or must be+wrapped inside a rank-N type to hide the polymorphism from the+typechecker. This is a bit cumbersome. An alternative typesafe+\code{load} is available via the \code{pdynload} interface, which is+able to enforce the type of the plugin using GHC's type inference+mechanism, and is not restricted in its expressiveness (at the cost of+greater load times):++\begin{quote}+\scm{+pdynload :: FilePath+ -> [FilePath]+ -> [PackageConf]+ -> Type+ -> Symbol+ -> IO (LoadStatus a)+}++\scm{+pdynload_ :: FilePath+ -> [FilePath]+ -> [PackageConf]+ -> [Arg]+ -> Type+ -> Symbol+ -> IO (LoadStatus a)+}+\end{quote}+%+Example:+%+\begin{quote}+\scm{+do v <- pdynload "Plugin.o" ["api"] [] "API.Interface" "resource"+ case v of+ LoadSuccess _ a -> putStrLn "yay!"+ _ -> putStrLn "type error"+}+\end{quote}+%+\code{pdynload} is a replacement for \code{dynload}, which provides a+solution to the various problems caused by the existing dynamics+library in Haskell. Rather than use normal dynamics, which constrain+us to monomorphic types only (or rank-N types), it instead uses GHC's+type inference to unify the plugin's export value with that provided+by the api (via its .hi file). It is a form of \emph{staged type inference}+for module interfaces, allowing plugins to use any type definable in Haskell.+\code{pdynload} is like \code{dynload}, but requires a new \code{Type}+argument. This can be considered a type annotation on the value the plugin+should be constrained to.++Prior to loading the object, \code{pdynload} generates a tiny Haskell+source file containing, for example:+%+\begin{quote}+\scm{+module APITypeConstraint where+import qualified API+import qualified Plugin++_ = Plugin.resource :: API.Interface+}+\end{quote}+%+It then calls GHC's type checker on this file, which runs the full+Haskell type inference machinery. If the file typecheckes, then the+plugin type is correct, and the plugin is safe to load, otherwise it+is an error. ++Because we use the full Haskell type checker, we can have a form of+dynamic typechecking, on any type expressable in Haskell. A plugin's+value may, for example, have class constraints -- something not+checkable using the standard Dyanmic type. The cost is that+\code{pdynload} is roughly 46\% slower than an unchecked load.+ +The type of the plugin's resource field must be equivalent to the+\code{Type}. There are some restrictions on the arguments that may be+passed to pdynload. Currently, we require:+ \begin{itemize}+ \item The object name has the suffix (.o) removed and this+ becomes a qualified module name in the generated type-checker+ input file.++ \item The type name must be a single fully-qualified+ type-identifier, as the module name is stripped off (i.e.+ everything up to the last ".") and used as a qualified import.+ This means that you can't use, for example, \code{"Int ->+ String"} as a type (type synonyms are fine, though).++\end{itemize}++For example, \code{pdynload "API2.o" ["./"] [] "API.PluginAPI"+"doAction"} generates:++\begin{quote}+\scm{+module <temp-generated-name> where+import qualified API -- comes from API.PluginAPI argument+import qualified API2 -- comes from API2.o argument+_ = API2.doAction :: API.PluginAPI+}+\end{quote}++\begin{quote}+\scm{+unload :: Module -> IO ()+}++\scm{+unloadAll :: Module -> IO ()+}+\end{quote}++Unload an object, \emph{but not its dependencies} from the address+space. \code{unloadAll} performs cascading unloading of a module+\emph{and} its dependencies.++\begin{quote}+\scm{+reload :: Module -> Symbol -> IO (LoadStatus a)+}+\end{quote}++Unload, and then reload a module that must have been previously+loaded. Doesn't reload the dependencies. \code{reload} is useful in+conjunction with \code{make}---a call to \code{reload} can be+performed if \code{make} has recompiled the plugin source.++Additionally, some support is provided to manipulation of +libraries of Haskell modules (usually known as packages):++\begin{quote}+\scm{+loadPackage :: String -> IO ()++unloadPackage :: String -> IO ()++loadPackageWith :: String -> [PackageConf] -> IO ()+}+\end{quote}++\code{loadPackage} explcitly pulls in a library (which must be visible+in the current package namespace. \code{unloadPackage} unloads it.+\code{loadPackageWith} behaves like \code{loadPackage}, but you are able+to supply extra package.confs to augment the library search path.++Examples:+\begin{quote}+\scm{+do loadPackageWith "yi" ["yi.conf"]+ unloadPackage "yi-0.1"+}+\end{quote}++\newpage++\section{Compilation Manager}++The compilation manager is the system by which Haskell source code is+compiled to object code suitable for loading.++\subsection*{Interface}++\begin{quote}+\scm{+import System.Plugins++make :: FilePath + -> [Arg] + -> IO MakeStatus++makeAll :: FilePath + -> [Arg] + -> IO MakeStatus++recompileAll :: Module + -> [Arg] + -> IO MakeStatus++data MakeStatus + = MakeSuccess MakeCode FilePath + | MakeFailure Errors++data MakeCode = ReComp | NotReq+}+\end{quote}++Compile a Haskell source file to an object file, with any arguments+specified in the argument list passed through to GHC. Returns the+build status.++\code{make} generates a GHC \code{.hi} file containing a list of+package and objects that the source depends on. Subsequent calls to+\code{load} will use this interface file to load module and library+dependencies prior to loading the object itself. \code{makeAll} also+recursively compiles any dependencies it can find using GHC's+\code{--make} flag.++\code{recompileAll} is like \code{makeAll}, but rather than relying on+\code{ghc --make}, we explicitly check a module's dependencies.++\begin{quote}+\scm{+merge :: FilePath -> FilePath -> IO MergeStatus++mergeTo :: FilePath -> FilePath -> FilePath -> IO MergeStatus++mergeToDir :: FilePath -> FilePath -> FilePath -> IO MergeStatus++data MergeStatus + = MergeSuccess MergeCode Args FilePath + | MergeFailure Errors++type MergeCode = MakeCode+}+\end{quote}++The merging operation is extremely useful for providing extra default+syntax. An EDSL user then need not worry about declaring module names,+or having required imports. In this way, the stub file can also be+used to provide syntax declarations that would be inconvenient to+require of the plugin author. \code{merge} will include any import and+export declarations written in the stub, as well as any module name,+so that plugin author's need not worry about this compulsory syntax.+Additionally, if a plugin requires some non-standard library, which+must be provided as a \code{-package} flag to GHC, they may specify+this using the non-standard \code{GLOBALOPTIONS} pragma. Options+specified in the source this way will be added to the command line.+This is useful for users who wish to use GHC flags that cannot be+specified using the conventional \code{OPTIONS} pragma. The merging+operation uses the HSX parser library to parse Haskell source files.++\code{mergeTo} behaves like \code{merge}, but we can specify the file in+which to place output. \code{mergeToDir} lets you specify a directory in+which to place merged files.++\begin{quote}+\scm{+makeWith :: FilePath+ -> FilePath+ -> [Arg]+ -> IO MakeStatus+}+\end{quote}++This is a variety of \code{make} that first calls \code{merge} to+combine the plugin source with a syntax stub. The result is then+compiled. This is the preferred interface to EDSL authors who wish to+add extra syntax to a user's source. It is important to note that the+module and types from the second file argument are used to override+any of those that appear in the first argument. For example, consider+the following source files:++\begin{quote}+\scm{+module A where++a :: Integer+a = 1+}+\end{quote}++\begin{quote}+\scm{+module B where++a :: Int+}+\end{quote}++Calling \code{makeWith "A" "B" []} will merge the module name and types+from module B into module A, generating a third file:++\begin{quote}+\scm{+{-# LINE 1 "A.hs" #-}+module MxYz123 where++{-# LINE 3 "B.hs" #-}+a :: Int+{-# LINE 4 "A.hs" #-}+a = 1+}+\end{quote}++Leading to the desired result that we can ignore user-supplied module+names and types. Knowing the module name, in particular, is important+for dynamic loading, which requires the module name be known when+searching for symbols.++\begin{quote}+\scm{+hasChanged :: Module -> IO Bool+}+\end{quote}++\code{hasChanged} returns \code{True} if the module or any of its+dependencies have older object files than source files. Defaults to+\code{True} if some files couldn't be located.++\subsection*{Levels of Safety}++The normal dynamic loader, using \code{load} on object files only,+places full trust in the author of the plugin to provide a type-safe+object file, containing valid code. This can be mitigated somewhat via+the use of \code{make} to ensure that the plugin is at least Haskell+code that is well-typed internally (if we trust GHC to compile it+correctly). ++If we trust the user to provide an interface of \code{Dynamic} type, we+can check the plugin type at runtime, but the plugin's value must be+\code{Typeable}, which restricts it to be a monomorphic type (or to+using rank-N tricks). ++The greatest safety can be obtained by using \code{pdynload}, at the+cost of increased load times. \code{pdynload} essentially performs full+type inference on the plugin interface at runtime. The type safety of+the plugin, using \code{pdynload}, is then as safe as if the plugin was+statically compiled into the application. It does not provide any+\emph{further} safety than exists in static compilation. For example, it+does not preclude the use of (evil) \code{unsafeCoerce\#} to defeat+type-checking, either statically or at runtime. An extensive discussion+of type safe plugin loading is available in the \hsplugins{} paper+\urlh{http://www.cse.unsw.edu.au/~dons/hs-plugins/paper}{here}.++\newpage++\section{Eval.Haskell}++\code{eval}, and its siblings, provide a mechanism to compile and run+Haskell code at runtime, in the form of a String. The general framework+is that the string is used to create a plugin source file, which is+compiled and loaded, and type checked against its use. The resulting+value is returned to the caller. It resembles a runtime metaprogramming+\code{run} operator for closed code fragments.++\subsection*{Interface}++\begin{quote}+\scm{+import System.Eval.Haskell++eval :: Typeable a => String -> [Import] -> IO (Maybe a)++eval_ :: Typeable a =>+ String -- code to compile+ -> [Import] -- any imports+ -> [String] -- extra ghc flags+ -> [FilePath] -- extra package.conf files+ -> [FilePath] -- include search paths+ -> IO (Either [String] (Maybe a))+}+\end{quote}++\code{eval} takes a string, and a list of import module names, and+returns a \code{Maybe} value. \code{Nothing} means the code did not+compile, or did not typecheck at its splice point. \code{Just v} gives+you \code{v}, the result of evaluating your code. It is interesting to+note that \code{eval} has the type of an interpreter. The+\code{Typeable} constraint is used to type check the evaluated code when+it is loaded, using \code{dynload}. As usual, \code{eval\_} is a+version of \code{eval} that lets you pass extra flags to ghc and to the+dynamic loader.++The existing \code{Data.Dynamic} library requires that only monomorphic+values are \code{Typeable}, so in order to evaluate polymorphic+functions you need to wrap them up using rank-N types. Some examples:+%+\begin{quote}+\scm{+import System.Eval.Haskell++main = do i <- eval "1 + 6 :: Int" [] :: IO (Maybe Int)+ if isJust i then putStrLn (show (fromJust i)) else return ()+}+\end{quote}+ +When executed this program calls \code{eval} to compile and load the+simple arithmetic expression, returning the result, which is+displayed. If the value loaded is not of type \code{Int},+\code{dynload} will throw an exception.+ +The following example, due to Manuel Chakravarty, shows how to+evaluate a polymorphic function. Polymorphic values are not easily+made dynamically typeable, but this example shows how to do it. The+module \code{Poly} is imported as the second argument, providing the+type of the polymorphic function:+%+\begin{quote}+\scm{+import Poly+import System.Eval.Haskell++main = do m_f <- eval "Fn (\\x y -> x == y)" ["Poly"]+ when (isJust m_f) $ do+ let (Fn f) = fromJust m_f+ putStrLn $ show (f True True)+ putStrLn $ show (f 1 2)+}+\end{quote}+% +And the type of \code{Fn}:+%+\begin{quote}+\scm{+{-# OPTIONS -fglasgow-exts #-} +module Poly where++import AltData.Typeable++data Fn = Fn {fn :: forall t. Eq t => t -> t -> Bool}++instance Typeable Fn where+ typeOf _ = mkAppTy (mkTyCon "Poly.Fn") []+}+\end{quote}+% +When executed, this program produces:+%+\begin{quote}+\begin{verbatim}+$ ./a.out+True+False+\end{verbatim}+\end{quote}++We thus get dynamically typeable polymorphic functions.++\begin{quote}+\scm{+unsafeEval :: String -> [Import] -> IO (Maybe a)++unsafeEval_ :: String+ -> [Import]+ -> [String]+ -> [FilePath]+ -> IO (Either [String] a)+}+\end{quote}++Wrapping up polymorphic values can be annoying, so we provide a+\code{unsafeEval} function for people who like to live on the edge,+which dispenses with dynamic typing, relying instead on the+application to provide the correct type annotation on the call to+\code{eval}. If the type loaded by \code{eval} is wrong,+\code{unsafeEval} will crash. However, its lets us remove some+restrictions on what types can be evaluated, which can be useful.++{unsafeEval\_} lets the application have full control over the import+environment and load flags to the eval call, which is useful for+applications that wish to script themselves, and require specific+modules and packages to be in scope in the eval-generated module.++This example maps a \code{toUpper} over a list:+%+\begin{quote}+\scm{+import Eval.Haskell++main = do s <- unsafeEval "map toUpper \"haskell\"" ["Data.Char"]+ when (isJust s) $ putStrLn (fromJust s)+}+\end{quote}+ +And here we evaluate a lambda abstraction, applying the result to+construct a tuple. Note the type information that must be supplied in+order for Haskell to type the usage of \code{fn}:+%+\begin{quote}+\scm{+import System.Eval.Haskell++main = do fn <- unsafeEval "(\\(x::Int) -> (x,x))" [] :: IO (Maybe (Int -> (Int,Int)))+ when (isJust fn) $ putStrLn $ show $ (fromJust fn) 7+}+\end{quote}+\subsection{Utilities for use with eval}+\code{hs-plugins} proves the following utilities for use with \code{eval}:+\begin{itemize}+\item+\code{mkHsValues} is a helper function for converting \code{Data.Map}s+of names and values into Haskell code. It relies on the assumption+that the passed values' Show instances produce valid Haskell+literals (this is true for all prelude types). It's type is as follows:+\begin{quote}+\scm{+mkHsValues :: (Show a) => Data.Map String a -> String+}+\end{quote}+\end{itemize}+% \subsection{Foreign Eval}+% +% A preliminary binding to \code{eval} has been implemented to allow C+% (and Objective C) programs access to the evaluator. Foreign bindings+% to the compilation manager and dynamic loader are yet to be+% implemented, but shouldn't be too hard. An foreign binding to a+% Haskell module that wraps up calls to \code{make} and \code{load}+% would be fairly trivial.+% +% At the moment we have an ad-hoc binding to \code{eval}, so that C+% programmers who know the type of value that will be returned by+% Haskell can call the appropriate hook into the evaluator. If they get+% the type wrong, a nullPtr will be returned (so calling Haskell is+% still typesafe). The foreign bindings to \code{eval} all return+% \code{NULL} if an error occurred, otherwise a pointer to the value is+% returned.+% +% \begin{quote}+% \scm{+% foreign export ccall hs_eval_b :: CString -> IO (Ptr CInt)+% +% foreign export ccall hs_eval_c :: CString -> IO (Ptr CChar)+% +% foreign export ccall hs_eval_i :: CString -> IO (Ptr CInt)+% +% foreign export ccall hs_eval_s :: CString -> IO CString+% }+% \end{quote}+% +% An example C program for compiling and evaluating Haskell code at+% runtime follows. This program calculates a fibonacci number, returning+% it as a \code{CString} to the C program:+% %+% \begin{quote}+% \begin{verbatim}+% #include "EvalHaskell.h"+% #include <stdio.h>+% +% int main(int argc, char *argv[])+% {+% char *p;+% hs_init(&argc, &argv);+% p = hs_eval_s("show $ let fibs = 1:1:zipWith (+) fibs (tail fibs) in fibs !! 20");+% if (p != NULL)+% printf("%s\n",p);+% else+% printf("error in code\n");+% hs_exit();+% return 0;+% }+% \end{verbatim}+% \end{quote}+% ++\section{RTS Binding}++The low level interface is the binding to GHC's Linker.c. Therefore,+\hsplugins{} only works on platforms with a working GHCi. This library+is based on code from André Pang's runtime loader. The low level+interface is as follows:++\begin{itemize}+ \item \code{initLinker} \em start the linker up + \item \code{loadObject} \em load a vanilla .o+ \item \code{loadPackage} \em load a GHC library and its cbits+ \item \code{loadShared } \em load a .so object file+ \item \code{resolveObjs} \em and resolve symbols+\end{itemize}++Additionally, \code{Hi.Parser} provides an interface to a GHC+\code{.hi} file parser. Currently we only parse just the dependency+information, import and export information from \code{.hi} files, but+all the code is there for an application to extract other information+from \code{.hi} files.++\newpage++\section{Dynamic Loader Implementation}++The dynamic loader is the system by which modules, and their+dependencies can be loaded, unloaded or reloaded at runtime, and+through which we access the functions we need.++At its lowest level, the \hsplugins{} loader is a binding to the GHC+runtime loader and linker. This layer is a direct reimplementation of+Andre Pang's \code{runtime\_loader} (barely any code changed). The+code at this level can only load single modules, or packages/archives+(which are just objects too). Any dependency resolution must be+performed by hand.++On top of Andre's interface is a more convenient interface through+which user's should interact with the dynamic loader. The most+significant extension to Andre's work is the automatic calculation and+loading of a plugin's package or module dependencies via .hi file+information. It also handles initialisation of the loader, and+retrieval of values from the plugin in a more convenient way. Some+state is also stored in the loader to keep track of which modules and+packages have been loaded, to prevent unnecessary (actually, fatal)+loading of object files and packages already loaded. Thus you can+safely load several plugins at once, that share common dependencies,+without worrying about the dependencies being loaded multiple times.+We also store package.conf information in the state, so we can work+out where a package lives and what it depends on.++The ability to remember which packages and objects have been loaded is+based on ideas in Hampus Ram's dynamic loader, which has a more+advanced dependency tracking system, with the ability to unload the+dependencies of a plugin. \hsplugins{} doesn't provide ``cascading+unloading''. The advantage \hsplugins{} has over Hampus' loader seems+to be the automatic dependency resolution via vanilla .hi files and+the dynamic recompilation stuff.++Using \code{load}, any library packages, or any \code{.o} files, that a+plugin depends upon will be automatically loaded prior to loading the+module itself. \code{load} then looks up a symbol from the object file,+and returns the value associated with the symbol as a conventional+Haskell value. It should also be possible to load a GHCi-style \code{.o}+archive of object files this way, although there is currently no way+to extract multple plugin interfaces from a archive of objects.++The application writer is not required to recalculate dependencies if+the plugin changes, and the plugin author does not need to specify+what dependencies exist, as is required in the lower level interface.+This is achieved by using the dependency information calculated by GHC+itself, stored in .hi files, to work out which modules and packages to+load, and in what order. A plugin in \hsplugins{} is really a pair of+an object file (or archive) and a \code{.hi} file, containing package+and module dependency information. ++The \code{.hi} file is created by GHC when the plugin is compiled,+either by hand or via \code{make}. \code{load} uses a binary parser to+extract the relevant information from the \code{.hi} data. Because the+dependency information is stored in a separate file to the application+that loads the plugin, such information can be recalculated without+having to modify the application. Becaues of this, it was easy to+extend the load to support recompilation of module source, even if+dependencies change, because dependencies are no longer hard-coded+into the application source itself, but are specified by the plugin.++Assuming we have a plugin exporting some data, ``resource'', with a+record name \code{field :: String}, here is an example call to \code{load}:+%+\begin{quote}+\scm{+do m_v <- load "Test.o" ["."] [] "resource"+ v <- case m_v of+ LoadSuccess _ v -> return v+ _ -> error "load failed"+ putStrLn $ field v+}+\end{quote}++This loads the object file \code{Test.o}, and any packages or objects+\code{Test.o} depends on. It resolves undefined symbols, and returns+from the object file the Haskell value named ``resource'', as the+value ``v''. This must be a value exported by the plugin. We then+retrieve the \code{field} component of \code{v}, and print it out.++This simple usage assumes that the plugin to load is in the same+directory as the application, and that the api defining the interface+between plugin and application is also in the current directory (hence+the ``.'' in the 2nd argument to \code{load}).++\subsection*{Dynamically Loading the Dynamic Loader}++It is also possible to load the \code{plugins} or \code{eval}+libraries in GHC. Here, for example, we load the \code{plugs}+interactive environment in GHCi, and evaluated some code. The source to+\code{plugs} is in Appendix+\ref{sec:plugs}.+%+\begin{quote}+\begin{verbatim}+paprika$ ghci -package-conf ../../../plugins.conf.inplace -package eval+ ___ ___ _+ / _ \ /\ /\/ __(_)+ / /_\// /_/ / / | | GHC Interactive, version 6.3, for Haskell 98.+/ /_\\/ __ / /___| | http://www.haskell.org/ghc/+\____/\/ /_/\____/|_| Type :? for help.++Loading package base ... linking ... done.+Loading package altdata ... linking ... done.+Loading package unix ... linking ... done.+Loading package mtl ... linking ... done.+Loading package lang ... linking ... done.+Loading package posix ... linking ... done.+Loading package haskell98 ... linking ... done.+Loading package haskell-src ... linking ... done.+Loading package plugins ... linking ... done.+Loading package eval ... linking ... done.+Prelude> :l Main+Skipping Main ( Main.hs, Main.o )+Ok, modules loaded: Main.+Prelude Main> main+Loading package readline ... linking ... done.+ __ + ____ / /_ ______ ______ + / __ \/ / / / / __ `/ ___/ PLugin User's GHCi System, for Haskell 98+ / /_/ / / /_/ / /_/ (__ ) http://www.cse.unsw.edu.au/~dons/hs-plugins+ / .___/_/\__,_/\__, /____/ Type :? for help +/_/ /____/ ++Loading package base ... linking ... done+plugs> map (\x -> x + 1) [0..10]+[1,2,3,4,5,6,7,8,9,10,11]+plugs> :t "haskell"+"haskell" :: [Char]+plugs> :q+*** Exception: exit: ExitSuccess+Prelude Main> :q+Leaving GHCi.+\end{verbatim}+\end{quote}++\subsection*{Dynamic Typing}++Support is also provided to unwrap and check the type of dynamically+typed plugin values (those wrapper in a \code{toDyn}) via+\code{dynload}. This is the same as \code{load}, except that instead+of a returning the value it finds, it unwraps a dynamically typed+value, checks the type, and returns the unwrapped value. This is to+provide further trust that the symbol you are retrieving from the+plugin is of the type you think it is, beyond that trust you have by+knowing that the plugin was compiled against a shared API. By using+\code{dynload} it is not enough for an object file to just have the+same symbol name as the function you require, it must also carry the+\code{Data.Dynamic} representation of the type, too. \code{pdynload}+rectifies most of \code{dynload}'s limitations, but at the cost of+additional running time.++\section{Compilation Manager Implementation}++Along side the dynamic loader is the compilation manager. This is a+\code{make}-like system for compiling Haskell source, prior to loading+it. \code{make} checks if a source file is newer than its associated+object file. If so, the source is recompiled to an object file, and a+new dependency file is created, in case the dependencies have changed+in the source. This module can then be loaded. The idea is to allow+EDSL authors to write plugins without having to touch a compiler: it+is all transparent. It also allows us to enforce type safety in the+plugin by injecting type constraints into the plugin source, as has+been discussed eariler.++The effect is much like \emph{hi} (Hmake Interactive), funnily enough.+An application using both \code{make} and \code{load} behaves like a+Haskell interpreter, using \code{eval}. You modify your plugin, and+the application notices the change, recompiles it (possibly issuing+type errors) and then reloads the object file, providing the+application with the latest version of the code.+ +An example:+%+\begin{quote}+\scm{+do status <- make "Plugin.hs" []+ obj <- case status of+ MakeSuccess _ o -> return o+ MakeFailure e -> mapM_ putStrLn e >> error "failed"++ m_v <- load obj ["api"] [] "resource"+ v <- case m_v of+ LoadSuccess _ v -> return v+ _ -> error "load failed"+ putStrLn $ field v+}+\end{quote}++\code{make} accepts a source file as an argument, and a (usually empty)+list of GHC flags needed to compile the object file. It then checks to+see if compilation is required, and if so, it calls GHC to compile the+code, with and arguments supplied. If any errors were generated by+GHC, they are returned as the third component of the triple.++Usually it will be necessary to ensure that GHC can find the plugin+API to compile against. This can be done by either making sure the API+is in the same directory as the plugin, or by adding a \code{-i} flag to+\code{make}'s arguments. If the API is created as a ``package'' with a+package.conf file, \code{make} can be given \code{-package-conf} arguments+to the same effect.++Normally, \code{make} generates the \code{.o} and \code{.hi} files in+the same directory as the source file. This is not always desirable,+particularly for interpreter-like applications. To solve this, you can+pass \code{[''-odir'', path]} as elements of the arg list to+\code{make}, and it will respect these arguments, generating the+object and interface file in the directory specified. GHC's argument+\code{''-o''} is also respected in a similar manner, so you could also+say \code{[''-o'', obj]} for the same effect.++\code{make} is entirely optional. All user's have to do to use the+loader on its own is make sure they only load object files that also+have a \code{.hi} file. This will usually be the case if the plugin is+compiled with GHC.++\subsection*{makeWith}++\code{makeWith} merges two source files together, using the function+and value declarations from one file, with any syntax in the second,+creating a new third source file. It then compiles this source file+via \code{make}.++This function exists as a benefit to EDSL authors and is related to+the original motivation for \hsplugins{}, as a .conf file language+library. Configuration files need to be clean and simple, and you+can't rely, or trust, the user to get all the compulsory details+correct. So the solution is to factor out any compulsory syntax, such+as module names, imports, and also to provide a default instance of+the API, and store this code in a separate file provided by the+application writer, not the user. \code{makeWith} then merges+whatever the user has written, with the syntax stub, generating a+complete Haskell plugin source, with the correct module names and+import declarations. We also ensure the plugin only exports a single+interface value while we are here.++\code{makeWith} thus requires a Haskell parser to parse two source files+and merge the results. We are merging abstract syntax here. This is+implemented using the Language.Haskell parser library. Unfortunately,+this library doesn't implement all of GHC's extensions, so if you wish+to use \code{makeWith} you can only write Haskell source that can be+parsed by this library, which is just H98 and a few extensions. This+is another short coming in the current design that will be overcome+with \code{-package ghc}. Remember, however, for normal uses of+\code{make} and \code{load} you are unrestricted in what Haskell you use.+This is the same restriction present in happy, the Haskell parser,+placed on the code you can provide in the \code{.y} source.++\code{makeWith} also makes use of line pragmas. If the merged file+fails to compile, the judicious use of line number pragmas ensure that+the user receives errors messages reported with reference to their+source file, and not line number in the merged file. This is a+property of the Language.Haskell parser that we can make use of.++An example of \code{makeWith}:+%+\begin{quote}+\scm{+do status <- makeWith "Plugin.in" "Plugin.stub" []+ obj <- case status of+ MakeFailure e -> mapM_ putStrLn e >> error "failed"+ MakeSuccess _ o -> return o+ m_v <- load obj [apipath] [] "resource"+ v <- case m_v of+ LoadSuccess _ v -> return v+ _ -> error "load failed"+ putStrLn $ field v+}+\end{quote}++We combine the user's file (\code{Plugin.in}) with a stub of syntax+generating a new, third Haskell file in the default tmpdir. This is+compiled as per usual, producing object and interface files. The+object is then loaded, and we extract the value exported.++Using \code{makeWith} it is possible to write very simple, clear+Haskell plugins, that appear not to be Haskell at all. It is an easy+way to get EDSL user's writing plugins that are actually Haskell+programs, for .e.g, configuration files. See the examples that come+with the src.++\newpage++\section{An Example}++This is an introductory example.++\subsection*{API}++First we need an interface between the application and the plugin.+This module needs to be visible to both the app and the plugin, in the+interest of clear and well-defined interfaces: +%+\begin{quote}+\scm{+module StringProcAPI (Interface(..), plugin) where++data Interface = Interface {+ stringProcessor :: String -> String+}++plugin :: Interface+plugin = Interface { stringProcessor = id }+}+\end{quote}++Here we define \code{Interface} as the inteface signature for the+object passed between plugin and application. We'll use the record+syntax as it looks intuitive in the plugin. We provide a default+instance, the \code{plugin} value, that can be overwritten in the+actual plugin, ensuring sensible behaviour in the absence of any+plugins. The API should theoretically be compiled with \code{-Onot} to+avoid interface details leaking out into the \code{.hi} file.++\subsection*{The Plugin}++This is our plugin. Note that the plugin will be compiled entirely+seperately from the application. It must only rely on the API, and+nothing in the application source.+%+\begin{quote}+\scm{+module StringProcPlugin (resource) where++import StringProcAPI (plugin)++resource = plugin {+ stringProcessor = reverse +}+}+\end{quote}++Using the record syntax we overwrite the \code{function} field with our+own value, \code{reverse}. The value \code{resource} is the magic symbol+that must be defined, and which the application will use to find the+data the plugin exports.++Now, we can make this even easier on the plugin writer by the use of a+``stub'' file. \code{makeWith} lets you merge a plugin source with+another Haskell file, and compiles the result into the actual plugin+object. So the application can provide a stub file containing module+declarations and imports, and a default plugin value. Here is an+application-provided stub, factoring out compulsory syntax and type+declarations from the plugin:+%+\begin{quote}+\scm{+module StringProcPlugin ( resource ) where++import StringProcAPI++resource :: Interface+resource = plugin+}+\end{quote}++By factoring out compulsory syntax, the plugin author only has to+provide an overriding instance of the \code{resource} field. So all+the plugin actually consists of, is:+%+\begin{quote}+\scm{+resource = plugin {+ stringProcessor = reverse+}+}+\end{quote}++That is all the code we need! This file may be called anything at all.++More complex APIs may have more fields, of course. The nice thing+about this arrangement is that the user will write some simple syntax,+which will nonetheless by typechecked safely against the API. Errors+are also reported using line numbers from the source file, not the+stub, which makes things less confusing.++\subsection*{The Application}++Now we need to write an application that can use values of the kind+defined in the API, and which can compile and load plugins. The basic+mechanism to compile and load a plugin is as follows:+%+\begin{quote}+\scm{+do status <- make "StringProcPlugin.hs" []+ obj <- case status of+ MakeSuccess _ o -> return o+ MakeFailure e -> mapM_ putStrLn e >> error "failed"++ m_v <- load obj ["."] [] "resource"+ val <- case m_v of+ LoadSuccess _ v -> return v+ _ -> error "load failed"+}+\end{quote}+%+This code calls \code{make} to compile the plugin source, yielding+wrapper around a handle to an object file. The object can then be loaded+using \code{load}, and the code associated with the symbol+\code{resource} is retrieved. ++We embed this code in a simple shell-like loop, applying the function+exported by the plugin:+%+\begin{quote}+\scm{+import System.Plugins+import StringProcessorAPI+import System.Console.Readline+import System.Exit++source = "Plugin.hs"+stub = "Plugin.stub"+symbol = "resource"++main = do s <- makeWith source stub []+ o <- case s of+ MakeSuccess _ obj -> do+ ls <- load obj ["."] [] symbol+ case ls of LoadSuccess m v -> return (m,v)+ LoadFailure err -> error "load failed"+ MakeFailure e -> mapM_ putStrLn e >> error "compile failed"+ shell o++shell o@(m,plugin) = do + s <- readline "> "+ cmd <- case s of + Nothing -> exitWith ExitSuccess+ Just (':':'q':_) -> exitWith ExitSuccess+ Just s -> addHistory s >> return s++ s <- makeWith source stub [] -- maybe recompile the source+ o' <- case s of+ MakeSuccess ReComp o -> do + ls <- reload m symbol+ case ls of LoadSuccess m' v' -> return (m',v')+ LoadFailure err -> error "reload failed"+ MakeSuccess NotReq _ -> return o+ MakeFailure e -> mapM_ putStrLn e >> shell o+ eval cmd o'+ shell o'++eval ":?" _ = putStrLn ":?\n:q\n<string>"++eval s (_,plugin) = let fn = (stringProcessor plugin) in putStrLn (fn s)+}+\end{quote}++We have to import the hs-plugins library, and the API. The main loop+proceeds by compiling and loading the plugin for the first time, and+then calls \code{shell}, the interpeter loop. This loop lets us apply+the function in the plugin to strings we supply. We have to pass+around the \code{(Module, a)} pair we get back from \code{reload}, so+that we can pass it to \code{eval} to do the real work. The first+\code{eval} case is where we use the record syntax to select the+\code{function} field out of \code{v}, the plugin interface object,+and we apply it to s. Try it out:+%+\begin{quote}+\begin{verbatim}+paprika$ ./a.out +Loading package base ... linking ... done+Loading objects API Plugin ... done+> :?+":?"+":q"+"<string>"+> abcdefg+gfedcba+\end{verbatim}+\end{quote}++Now, if we edit the plugin while the shell is running, the next time+we type something at the prompt the plugin will be unloaded,+recompiled and reloaded. Because the plugin is really an EDSL, we can+use any Haskell we want, so we'll change the plugin to:+%+\begin{quote}+\scm{+import Data.Char++resource = plugin {+ stringProcessor = my_fn+}++my_fn s = map toUpper (reverse s)+}+\end{quote}++Back to the shell:+%+\begin{quote}+\begin{verbatim}+> abcdefg +Compiling plugin ... done+Reloading Plugin ... done+GFEDCBA+\end{verbatim}+\end{quote}++And that's it: dynamically recompiled and reload Haskell code!++\section{Multiple Plugins}++It is quite easy to load multiple plugins, that all implement the+common plugin API, and that all export the same value (though+implemented differently). This make \hsplugins{} suitable for+applications that wish to allow an arbitrary number of plugins. The+main problem with multiple plugins is that they may share+dependencies, and if \code{load} na\"ively loaded all dependencies+found in the set of \code{.hi} files associated with all the plugins,+the GHC rts would crash. To solve this the \hsplugins{} dynamic loader+maintains state storing a list of what modules and packages have been+loaded already. If \code{load} is called on a module that is already+loaded, or dependencies are attempted to load, that have already been+loaded, the dynamic loader ignores these extra dependencies. This+makes it quite easy to write an application that will allows an+arbitrary number of plugins to be loaded. An example follows.++\subsection*{Definition}++First we need to define the API that a plugin must type check against,+in order to be valid. +%+\begin{quote}+\scm{+module API where++data Interface = Interface { + valueOf :: String -> String +}++plugin :: Interface +plugin = Interface { valueOf = id }+}+\end{quote}++We can then implement a number of plugins that provide values of type+"Interface". We show three plugins that export string manipulation functions:+%+\begin{quote}+\scm{+module Plugin1 where++import API+import Data.Char++resource = plugin {+ valueOf = \s -> map toUpper s+}+}+\end{quote}++\begin{quote}+\scm{+module Plugin2 where++import API+import Data.Char++resource = plugin {+ valueOf = \s -> map toLower s+}+}+\end{quote}++\begin{quote}+\scm{+module Plugin3 where++import API++resource = plugin {+ valueOf = reverse+}+}+\end{quote}++And finally we need to write an application that would use these+plugins. Remember that the application is written without knowledge of+the plugins, and the plugins are written without knowledge of the+application. They are each implemented only in terms of the API, a+shared module and \code{.hi} file. An application needs to make the+API interface available to plugin authors, by distributing the API+object file and \code{.hi} file with the application.+%+\begin{quote}+\scm{+import System.Plugins+import API++main = do+ let plist = ["Plugin1.o", "Plugin2.o", "Plugin3.o"]+ plugins <- mapM (\p -> load p ["."] [] "resource") plist+ let functions = map (valueOf . fromLoadSuc) plugins+ mapM_ (\f -> putStrLn $ f "haskell is for hackers") functions++fromLoadSuc (LoadFailure _) = error "load failed"+fromLoadSuc (LoadSuccess _ v) = v++}+\end{quote}++This application simply loads all the plugins and retrieves the+functions they export. It then applies each of these functions to a+string, printing the result. We assume for this example that the+plugins are compiled once only, and are not compiled dynamically via+\code{make}. This implies that you have to use \code{GHC} to generate+the \code{.hi} file for each plugin. A sample Makefile to compile the+plugins, and the api:+%+\begin{quote}+\begin{verbatim}+all:+ ghc -Onot -c API.hs+ ghc -O -c Plugin1.hs+ ghc -O -c Plugin2.hs+ ghc -O -c Plugin3.hs+\end{verbatim}+\end{quote}++Ghc creates \code{.hi} files for each plugin, which can be inspected+using the \code{Plugins.BinIface.readBinIface} function. It parses the+\code{.hi} file, generating, roughly, the following:+%+\begin{quote}+\begin{verbatim}+interface "Main" Main+module dependencies: A, B+package dependencies: base, haskell98, lang, unix+\end{verbatim}+\end{quote}++which says that the plugin depends upon a variety of system packages,+and the modules A and B. All these dependencies must be loaded before+the plugin itself.++You then need to compile the application against the API, and against+the \hsplugins{} library:+%+\begin{quote}+\begin{verbatim}+ghc -O --make -package plugins Main.hs+\end{verbatim}+\end{quote}++Running the application produces the following result. Note that the+verbose output can be switched off by compiling \hsplugins{} without+the \code{-DDEBUG} flag. If you look at the \code{.hi} file, using+\code{ghc --show-iface}, you'll see that they all depend on the base+package, and on the API, but the state stored in the dynamic loader+ensures that these shared modules are only loaded once:+%+\begin{quote}+\begin{verbatim}+Loading package base ... linking ... done+Loading object API Plugin1 ... done+Loading object Plugin2 ... done+Loading object Plugin3 ... done++HASKELL IS FOR HACKERS+haskell is for hackers+srekcah rof si lleksah+\end{verbatim}+\end{quote}++Archives of plugins can be loaded in one go if they have been linked+into a .o GHCi package, see \code{loadPackage}.++\newpage++\appendix++\section{License} ++This library is distributed under the terms of the LGPL:++\begin{quote}++Copyright 2003-5, Don Stewart - \url{http://www.cse.unsw.edu.au/~dons}++This library is free software; you can redistribute it and/or+modify it under the terms of the GNU Lesser General Public+License as published by the Free Software Foundation; either+version 2.1 of the License, or (at your option) any later version.++This library is distributed in the hope that it will be useful,+but WITHOUT ANY WARRANTY; without even the implied warranty of+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU+Lesser General Public License for more details.++You should have received a copy of the GNU Lesser General Public+License along with this library; if not, write to the Free Software+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307+USA++\end{quote}++\section{Portability}++The library tries to be portable. There are two major points that+limit easy portabilty. The main issue is a dependence on the GHC dynamic+linker. \hsplugins{} is thus limited to platforms to which GHC's dyn+linker has been ported (this is essentially the same as the platforms+that can run GHCi).++\newpage++\section{A Haskell Interpreter using Plugins}+% \label{sec:plugs}++Here is a full length example of a Haskell interpreter/compiler in the+style of Malcolm Wallace's \code{hi}. Rather than compiling the+user's code to an executable, we use \hsplugins{} to instead load an+object file and execute that instead, using the \code{eval} interface.+This cuts out the linking phase from the process, making turnaround at+the prompt around twice as fast as \code{hi}.++\subsection*{Source of Plugs}++\begin{quote}+\scm{+import System.Eval.Haskell+import System.Plugins++import System.Exit ( ExitCode(..), exitWith )+import System.IO+import System.Console.Readline ( readline, addHistory )++symbol = "resource"++main = do+ putStrLn banner + putStr "Loading package base" >> hFlush stdout+ loadPackage "base" + putStr " ... linking ... " >> hFlush stdout+ resolveObjs+ putStrLn "done"++ shell []++shell :: [String] -> IO ()+shell imps = do + s <- readline "plugs> "+ cmd <- case s of + Nothing -> exitWith ExitSuccess+ Just (':':'q':_) -> exitWith ExitSuccess+ Just s -> addHistory s >> return s+ imps' <- run cmd imps+ shell imps'++run :: String -> [String] -> IO [String]+run "" is = return is+run ":?" is = putStrLn help >> return is++run ":l" _ = return []+run (':':'l':' ':m) is = return (m:is)++run (':':'t':' ':s) is = do + ty <- typeOf s is+ when (not $ null ty) (putStrLn $ s ++ " :: " ++ ty)+ return is++run (':':_) is = putStrLn help >> return is++run s is = do + s <- unsafeEval ("show $ "++s) is+ when (isJust s) (putStrLn (fromJust s))+ return is++banner = "\ +\ __ \n\+\ ____ / /_ ______ ______ \n\+\ / __ \\/ / / / / __ `/ ___/ PLugin User's GHCi System, for Haskell 98\n\+\ / /_/ / / /_/ / /_/ (__ ) http://www.cse.unsw.edu.au/~dons/hs-plugins\n\+\ / .___/_/\\__,_/\\__, /____/ Type :? for help \n\+\/_/ /____/ \n"++help = "\+\Commands :\n\ +\ <expr> evaluate expression\n\ +\ :t <expr> show type of expression (monomorphic only)\n\ +\ :l module bring module in to scope\n\ +\ :l clear module list\n\ +\ :quit quit\n\ +\ :? display this list of commands"+}+\end{quote}++\subsection*{A Transcript}++And a transcript:+%+\begin{quote}+\begin{verbatim}+$ ./plugs+ __ + ____ / /_ ______ ______ + / __ \/ / / / / __ `/ ___/ PLugin User's GHCi System, for Haskell 98+ / /_/ / / /_/ / /_/ (__ ) http://www.cse.unsw.edu.au/~dons/hs-plugins+ / .___/_/\__,_/\__, /____/ Type :? for help +/_/ /____/ ++Loading package base ... linking ... done+plugs> 1+1+plugs> let x = 1 + 2 in x+3+plugs> :l Data.List+plugs> case [1,3,2] of x -> sort x+[1,2,3]+plugs> reverse [1,3,2]+[2,3,1]+plugs> map (\x -> (x,2^x)) [1,2,3,4,5,6,7,8,9,10]+[(1,2),(2,4),(3,8),(4,16),(5,32),(6,64),(7,128),(8,256),(9,512),(10,1024)]+plugs> :t "haskell"+"haskell" :: [Char]+plugs> :quit+\end{verbatim}+\end{quote}++\end{document}
+ docs/munge.sed view
@@ -0,0 +1,16 @@++# de-boldify and <p>-ify the Contents.++/Contents/ { + :loop+ /Go to/ { + b end+ }+ s,<p>,,+ s,<b>,,+ s,</b>,,+ s,</p>,,+ n+ b loop+}+:end
+ docs/tex2page.sty view
@@ -0,0 +1,9 @@+% tex2page.sty+% Dorai Sitaram++% Loading this file in a LaTeX document+% gives it all the macros of tex2page.tex,+% but via a more LaTeX-convenient filename.++\input{tex2page}+
+ docs/tex2page.tex view
@@ -0,0 +1,1381 @@+% tex2page.tex+% Dorai Sitaram++% TeX files using these macros+% can be converted by the program+% tex2page into HTML++\message{version 2003-10-26} % last change ++\let\texonly\relax+\let\endtexonly\relax++\texonly++\newcount\evalQauxfilecount+\evalQauxfilecount=0++\def\eval{\begingroup+ \ifx\evalfortexQport\UNDEFINED+ \expandafter\csname newwrite\endcsname+ \evalfortexQport+ \immediate\openout\evalfortexQport+ \jobname.eval4tex + \immediate\write\evalfortexQport+ {\string\ifx\string\shipout\string\UNDEFINED+ \string\eval{(eval-for-tex-only)}%+ \string\else\string\endinput\string\fi}%+ \fi+ \global\advance\evalQauxfilecount by 1+ \edef\evalQauxfile{\jobname-Z-E-\the\evalQauxfilecount}%+ {\immediate\openin0=\evalQauxfile.tex + \ifeof0 \immediate\closein0 + \else \input \evalQauxfile.tex \fi}%+ \def\do##1{\catcode`##1=12 }\dospecials+ \catcode`\{=1 \catcode`\}=2 + \catcode`\^^M=12 + \newlinechar=`\^^M%+ \evalQii}++\def\evalQii#1{%+ \immediate\write\evalfortexQport{\string\eval{#1}}%+ \endgroup}++%\def\verbwritefile#1 {\relax}+%\let\verbwrite\gobbleencl++\def\verbwritefile{%+ \ifx\verbwritefileQport\UNDEFINED+ \expandafter\csname newwrite\endcsname\verbwritefileQport + \else\immediate\closeout\verbwritefileQport+ \fi+ \futurelet\verbwritefileQnext\verbwritefileQcheckchar}++\def\verbwritefileQcheckchar{%+ \ifx\verbwritefileQnext\bgroup+ \let\verbwritefileQnext\verbwritefileQbracedfile+ \else+ \let\verbwritefileQnext\verbwritefileQspacedfile+ \fi\verbwritefileQnext}++\def\verbwritefileQspacedfile#1 {%+ \immediate\openout\verbwritefileQport #1+}++\def\verbwritefileQbracedfile#1{%+ \verbwritefileQspacedfile #1+}++\def\verbwrite{%+ \ifx\verbwritefileQport\UNDEFINED+ \verbwritefile \jobname.txt \fi+ \begingroup+ \def\do##1{\catcode`##1=12 }\dospecials+ \catcode`\{=1 \catcode`\}=2 + \catcode`\^^M=12 \newlinechar=`\^^M%+ \futurelet\verbwriteQopeningchar\verbwriteQii}++\def\verbwriteQii{\ifx\verbwriteQopeningchar\bgroup+ \let\verbwriteQiii\verbwriteQbrace\else+ \let\verbwriteQiii\verbwriteQnonbrace\fi+ \verbwriteQiii}++\def\verbwriteQbrace#1{\immediate+ \write\verbwritefileQport{#1}\endgroup}++\def\verbwriteQnonbrace#1{%+ \catcode`\{12 \catcode`\}12+ \def\verbwriteQnonbraceQii##1#1{%+ \immediate\write\verbwritefileQport{##1}\endgroup}%+ \verbwriteQnonbraceQii} ++\ifx\loadonlyQevalfortex1%+ \let\maybeloadfollowing\endinput+\else+ \let\maybeloadfollowing\relax+\fi\maybeloadfollowing++\ifx\slatexignorecurrentfile\UNDEFINED\relax\fi++\edef\atcatcodebeforetiip{\the\catcode`\@ }+\catcode`\@11++% margins++\def\sidemargin{\afterassignment\sidemarginQadjustoffset+ \hoffset}++\def\sidemarginQadjustoffset{%+ \advance\hoffset -1true in+ \advance\hsize -2\hoffset}++\def\vertmargin{\afterassignment\vertmarginQadjustoffset+ \voffset}++\def\vertmarginQadjustoffset{%+ \advance\voffset -1true in+ \advance\vsize -2\voffset}++%++\def\defcsactive#1{\defnumactive{`#1}}++\def\defnumactive#1{\catcode#1\active+ \begingroup\lccode`\~#1%+ \lowercase{\endgroup\def~}}++% gobblegobblegobble++\def\gobblegroup{\bgroup+ \def\do##1{\catcode`##1=9 }\dospecials+ \catcode`\{1 \catcode`\}2 \catcode`\^^M=9+ \gobblegroupI}++\def\gobblegroupI#1{\egroup}++\def\gobbleencl{\bgroup+ \def\do##1{\catcode`##1=12 }\dospecials+ \catcode`\{1 \catcode`\}2 \catcode`\^^M=9+ \futurelet\gobbleenclnext\gobbleenclI}++\def\gobbleenclI{\ifx\gobbleenclnext\bgroup+ \let\gobbleenclnext\gobblegroupI+ \else\let\gobbleenclnext\gobbleenclII\fi+ \gobbleenclnext}++\def\gobbleenclII#1{%+ \def\gobbleenclIII##1#1{\egroup}%+ \gobbleenclIII}++% \verb+% Usage: \verb{...lines...} or \verb|...lines...|+% In the former case, | can be used as escape char within+% the verbatim text++\let\verbhook\relax++\def\verbfont{\tt}+%\hyphenchar\tentt-1++\def\verbsetup{\frenchspacing+ \def\do##1{\catcode`##1=12 }\dospecials+ \catcode`\|=12 % needed?+ \verbfont+ \edef\verbQoldhyphenchar{\the\hyphenchar\font}%+ \hyphenchar\font-1+ \def\verbQendgroup{\hyphenchar\font\verbQoldhyphenchar\endgroup}%+}++% The current font is cmtt iff fontdimen3 = 0 _and_+% fontdimen7 != 0++\def\checkifusingcmtt{\let\usingcmtt n%+ \ifdim\the\fontdimen3\the\font=0.0pt+ \ifdim\the\fontdimen7\the\font=0.0pt+ \else\let\usingcmtt y\fi\fi}++% In a nonmonospaced font, - followed by a letter+% is a regular hyphen. Followed by anything else, it is a+% typewriter hyphen.++\def\variablelengthhyphen{\futurelet\variablelengthhyphenI+ \variablelengthhyphenII}++\def\variablelengthhyphenII{\ifcat\noexpand\variablelengthhyphenI+ a-\else{\tt\char`\-}\fi}++\def\verbavoidligs{% avoid ligatures+ \defcsactive\`{\relax\lq}%+ \defcsactive\ {\leavevmode\ }%+ \defcsactive\^^I{\leavevmode\ \ \ \ \ \ \ \ }%+ \defcsactive\^^M{\leavevmode\endgraf}%+ \checkifusingcmtt+ \ifx\usingcmtt n%+ \defcsactive\<{\relax\char`\<}%+ \defcsactive\>{\relax\char`\>}%+ \defcsactive\-{\variablelengthhyphen}%+ \fi}++\def\verbinsertskip{%+ \let\firstpar y%+ \defcsactive\^^M{\ifx\firstpar y%+ \let\firstpar n%+ \verbdisplayskip+ \parskip 0pt+ \aftergroup\verbdisplayskip+ \else\leavevmode\fi\endgraf}%+ \verbhook}++\ifx\verb\UnDeFiNeD\else+% Save LaTeX's \verb away, because+% we'll be defining our own \verb+\let\LaTeXverb\verb+\fi++%\def\verb{\begingroup+% \verbsetup\verbI}++\def\verb{\begingroup+ \verbsetup\verbavoidligs\verbQcheckstar}++\def\verbQcheckstar{%+ \futurelet\verbQcheckstarQnext\verbQcheckstarQii}++\def\verbQcheckstarQii{%+ \if\verbQcheckstarQnext*%+ \let\verbQcheckstarQnext\verbQcheckstarQiii+ \else+ \let\verbQcheckstarQnext\verbI+ \fi+ \verbQcheckstarQnext}++\def\verbQcheckstarQiii#1{%+ \defcsactive\ {\relax\char`\ }%+ \verbI}++\def\verbc{\begingroup+ \verbsetup\afterassignment\verbcI+ \let\verbcII=}++\def\verbcI{{\verbfont\verbcII}\endgroup}++\let\E\verbc++\newcount\verbbracebalancecount++\def\verblbrace{\char`\{}+\def\verbrbrace{\char`\}}++\def\verbescapechar#1{%+ \def\escapifyverbescapechar{\catcode`#1=0 }}++\verbescapechar\|++{\catcode`\[1 \catcode`\]2+\catcode`\{12 \catcode`\}12+\gdef\verbI#1[%\verbavoidligs+ \verbinsertskip\verbhook+ %\edef\verbQoldhyphenchar{\the\hyphenchar\tentt}%+ %\hyphenchar\tentt=-1+ %\def\verbQendgroup{\hyphenchar\tentt\verbQoldhyphenchar\endgroup}%+ %\let\verbQendgroup\endgroup%+ \if#1{\escapifyverbescapechar+ \def\{[\char`\{]%+ \def\}[\char`\}]%+ \def\|[\char`\|]%+ \verbbracebalancecount0+ \defcsactive\{[\advance\verbbracebalancecount by 1+ \verblbrace]%+ \defcsactive\}[\ifnum\verbbracebalancecount=0+ \let\verbrbracenext\verbQendgroup\else+ \advance\verbbracebalancecount by -1+ \let\verbrbracenext\verbrbrace\fi+ \verbrbracenext]\else+ \defcsactive#1[\verbQendgroup]\fi+ \verbII+]]++\def\verbII{\futurelet\verbIInext\verbIII}++{\catcode`\^^M\active%+\gdef\verbIII{\ifx\verbIInext^^M\else%+ \defcsactive\^^M{\leavevmode\ }\fi}}++\let\verbdisplayskip\medbreak++% \verbatiminput FILENAME+% displays contents of file FILENAME verbatim.++%\def\verbatiminput#1 {{\verbsetup\verbavoidligs\verbhook+% \input #1 }}++% ^ original \verbatiminput++\ifx\verbatiminput\UNDEFINED+% LaTeX's (optional) verbatim package defines a \verbatiminput --+% don't clobber it+\def\verbatiminput{%+ \futurelet\verbatiminputQnext\verbatiminputQcheckchar}%+\fi++\def\verbatiminputQcheckchar{%+ \ifx\verbatiminputQnext\bgroup+ \let\verbatiminputQnext\verbatiminputQbracedfile+ \else+ \let\verbatiminputQnext\verbatiminputQspacedfile+ \fi\verbatiminputQnext}++\def\verbatiminputQbracedfile#1{\verbatiminputQdoit{#1}}++\def\verbatiminputQspacedfile#1 {\verbatiminputQdoit{#1}}++\def\verbatiminputQdoit#1{{\verbsetup+ \verbavoidligs\verbhook+ \input #1 }}+++% \url{URL} becomes+% <a href="URL">URL</a> in HTML, and+% URL in DVI.++% A-VERY-VERY-LONG-URL in a .bib file+% could be split by BibTeX+% across a linebreak, with % before the newline.+% To accommodate this, %-followed-by-newline will+% be ignored in the URL argument of \url and related+% macros.++\ifx\url\UnDeFiNeD+\def\url{\bgroup\urlsetup\let\dummy=}%+\fi++\def\urlsetup{\verbsetup\urlfont\verbavoidligs+ \catcode`\{1 \catcode`\}2+ \defcsactive\%{\urlpacifybibtex}%+ \defcsactive\ {\relax}%+ \defcsactive\^^M{\relax}%+ \defcsactive\.{\discretionary{}{\char`\.}{\char`\.}}%+ \defcsactive\/{\discretionary{\char`\/}{}{\char`\/}}%+ \defcsactive\`{\relax\lq}}++\let\urlfont\relax++\def\urlpacifybibtex{\futurelet\urlpacifybibtexnext\urlpacifybibtexI}++\def\urlpacifybibtexI{\ifx\urlpacifybibtexnext^^M%+ \else\%\fi}++% \mailto{ADDRESS} becomes+% <a href="mailto:ADDRESS">ADDRESS</a> in HTML, and+% ADDRESS in DVI.++\let\mailto\url++% \urlh{URL}{TEXT} becomes+% <a href="URL">TEXT</a> in HTML, and+% TEXT in DVI.++% If TEXT contains \\, the part after \\ appears in+% the DVI only. If, further, this part contains \1,+% the latter is replaced by a fixed-width representation+% of URL.++\def\urlh{\bgroup\urlsetup+ \afterassignment\urlhI+ \gdef\urlhQurlarg}++\def\urlhI{\egroup+ \bgroup+ \let\\\relax+ \def\1{{\urlsetup\urlhQurlarg}}%+ \let\dummy=}++\def\urlp#1{{#1} \bgroup\urlsetup+ \afterassignment\urlpQwrapparens+ \gdef\urlpQurlarg}++\def\urlpQwrapparens{\egroup+ {\rm(}{\urlsetup\urlpQurlarg}{\rm)}}++% \urlhd{URL}{HTML-TEXT}{DVI-TEXT} becomes+% <a href="URL">HTML-TEXT</a> in HTML, and+% DVI-TEXT in DVI++\def\urlhd{\bgroup+ \def\do##1{\catcode`##1=12 }\dospecials+ \catcode`\{1 \catcode`\}2+ \urlhdQeaturlhtmlargs}++\def\urlhdQeaturlhtmlargs#1#2{\egroup}++\ifx\hyperref\UnDeFiNeD+\let\href\urlh+\let\hypertarget\gobblegroup+\let\hyperlink\gobblegroup+\def\hyperref#1#2#3#4{#2\ref{#4}#3}+\fi++%++\let\ignorenextinputtimestamp\relax++% don't let caps disable end-of-sentence spacing++\def\nocapdot{%+\count255=`\A+\loop+\sfcode\the\count255=1000+\ifnum\count255<`\Z+\advance\count255 by 1+\repeat+}++%++%\ifx\newenvironment\UnDeFiNeD+\let\htmlonly\iffalse+\let\endhtmlonly\fi+%\else+%\usepackage{comment}+%\excludecomment{htmlonly}+%\fi++\def\rawhtml{\errmessage{Can't occur outside+ \string\htmlonly}}+\def\endrawhtml{\errmessage{Can't occur outside+ \string\htmlonly}}++\let\htmlheadonly\iffalse+\let\endhtmlheadonly\fi++\let\cssblock\iffalse+\let\endcssblock\fi++\def\inputcss#1 {\relax}+\let\htmlstylesheet\inputcss+\let\htmladdimg\gobblegroup++\def\htmlref{\bgroup\aftergroup\gobblegroup\let\dummy=}++%++\let\htmlcolophon\gobblegroup+\let\htmlmathstyle\gobblegroup+\let\htmladvancedentities\relax++% Scheme++\let\scm\verb+\let\scminput\verbatiminput++\let\scmwritefile\verbwritefile+\let\scmwrite\verbwrite+\let\scmdribble\scm++\ifx\slatexversion\UNDEFINED+% SLaTeX compat+\let\scmkeyword\gobblegroup+\let\scmbuiltin\gobblegroup+\let\scmconstant\scmbuiltin+\let\scmvariable\scmbuiltin+\let\setbuiltin\scmbuiltin+\let\setconstant\scmbuiltin+\let\setkeyword\scmkeyword +\let\setvariable\scmvariable+\def\schemedisplay{\begingroup+ \verbsetup\verbavoidligs+ \verbinsertskip+ \schemedisplayI}%+\def\schemeresponse{\begingroup+ \verbsetup\verbavoidligs+ \verbinsertskip+ \schemeresponseI}%+{\catcode`\|0 |catcode`|\12+ |long|gdef|schemedisplayI#1\endschemedisplay{%+ #1|endgroup}%+ |long|gdef|schemeresponseI#1\endschemeresponse{%+ #1|endgroup}}%+\fi++\let\slatexlikecomments\relax+\let\noslatexlikecomments\relax++% definitions (useful in reference manuals)++\ifx\@@line\UnDeFiNeD+\let\@@line\line+\fi++\def\defun#1{\def\defuntype{#1}%+\medbreak+\@@line\bgroup+ \hbox\bgroup+ \aftergroup\enddefun+ \vrule width .5ex \thinspace+ \vrule \enspace+ \vbox\bgroup\setbox0=\hbox{\defuntype}%+ \advance\hsize-\wd0+ \advance\hsize-1em+ \obeylines+ \parindent=0pt+ \aftergroup\egroup+ \strut+ \let\dummy=}++\def\enddefun{\hfil\defuntype\egroup\smallskip}+++% Images++\let\imgdef\def++%\def\imgpreamble{\let\magnificationoutsideimgpreamble\magnification+% \def\magnification{\count255=}}+%+%\def\endimgpreamble{\let\magnification\magnificationoutsideimgpreamble}+++\let\imgpreamble\iffalse+\let\endimgpreamble\fi++\let\makehtmlimage\relax+++% Tally control sequences are cheap count+% registers: they doesn't use up TeX's limited number of+% real count registers.++% A tally is a macro that expands to the+% number kept track of. Thus \edef\kount{0} defines a+% tally \kount that currently contains 0.++% \advancetally\kount n increments \kount by n.+% \globaladvancetally increments the global \kount.+% If \kount is not defined, the \[global]advancetally+% macros define it to be 0 before proceeding with the+% incrementation.++\def\newtally#1{\edef#1{0}}++\def\advancetallyhelper#1#2#3{%+ \ifx#2\UNDEFINED+ #1\edef#2{0}\fi+ \edef\setcountCCLV{\count255=#2 }%+ \setcountCCLV+ \advance\count255 by #3+ #1\edef#2{\the\count255 }}++\def\advancetally{\advancetallyhelper\relax}+\def\globaladvancetally{\advancetallyhelper\global}++% plain's \beginsection splits pages too easily++%\def\beginsection#1\par{\sectionhelp{1}{}{#1}}++\def\beginsection{\vskip-\lastskip+ \bigbreak\noindent+ \bgroup\bf+ \let\par\sectionafterskip}++\def\beginsectionstar*{\beginsection}++% plain's \{left,center,right}line can't handle catcode change+% within their argument++\def\leftline{\@@line\bgroup\bgroup+ \aftergroup\leftlinefinish+ \let\dummy=}++\def\leftlinefinish{\hss\egroup}++\def\centerline{\@@line\bgroup\bgroup+ \aftergroup\leftlinefinish+ \hss\let\dummy=}++\def\rightline{\@@line\bgroup\hss\let\dummy=}++%++\let\strike\fiverm % can be much better!++%++\let\htmlpagebreak\relax++\let\htmlpagelabel\gobblegroup++\def\htmlpageref{\errmessage{Can't occur except inside+ \string\htmlonly}}++% Miscellaneous stuff++%\def\hr{$$\hbox{---}$$}+\def\hr{\medbreak\centerline{---}\medbreak}+%\def\hr{\par\centerline{$*$}\par}+%\def\hr{\smallskip\@@line{\leaders\hbox{~.~}\hfill}\smallskip}++%Commonplace math that doesn't require image files. (Avoiding $+%here because $ triggers image-file generation.)++\let\nohtmlmathimg\relax+\let\nohtmlmathintextimg\relax+\let\nohtmlmathdisplayimg\relax++\let\htmlimageformat\gobblegroup+\let\htmlimgmagnification\gobblegroup++\let\externaltitle\gobblegroup++\def\mathg{$\bgroup\aftergroup\closemathg\let\dummy=}+\def\closemathg{$}++\let\mathp\mathg++\def\mathdg{$$\bgroup\aftergroup\closemathdg\let\dummy=}+\def\closemathdg{$$}++%+++\let\evalh\gobblegroup+\let\evalq\gobblegroup++% Backward compatible stuff++\let\endgifpreamble\endimgpreamble+\let\endhtmlgif\relax+\let\endhtmlimg\relax+\let\gifdef\imgdef+\let\gifpreamble\imgpreamble+%\let\href\urlh+\let\htmlgif\relax+\let\htmlimg\relax+\let\htmlimgformat\htmlimageformat+\let\n\noindent+\let\p\verb+\let\q\scm+\let\schemeeval\eval+\let\scmfile\scmdribble+\let\scmfileonly\scmwrite+\let\scmp\scm+%\let\scmverbatim\scm+\let\scmverbatimfile\scminput+\let\setverbatimescapechar\verbescapechar+%\let\verbatim\verb+\let\verbatimfile\verbatiminput+\let\verbinput\verbatiminput+\let\verbfilename\verbwritefile+\let\scmfilename\scmwritefile++% uppercase version of \romannumeral++\def\Romannumeral{\afterassignment\RomannumeralI\count255=}++\def\RomannumeralI{\uppercase\expandafter{\romannumeral\the\count255 }}++\def\f{\footnote}++\ifx\label\UnDeFiNeD+\else +\def\tag#1#2{\@bsphack+ \protected@write\@auxout{}%+ {\string\newlabel{#1}{{#2}{\thepage}}}%+\@esphack}%+\let\tagref\ref+\fi++\def\inputexternallabels#1 {\relax}+\def\includeexternallabels#1 {\relax}++% The rest of the file isn't needed for LaTeX++\ifx\section\UnDeFiNeD+\let\maybeloadfollowing\relax+\else +\catcode`\@\atcatcodebeforetiip+\let\maybeloadfollowing\endinput+\fi\maybeloadfollowing++% LaTeX stops loading here!++% Title++\newwrite\sectionscratchfileport++\def\subject{%+ \immediate\openout\sectionscratchfileport Z-sec-temp+ \begingroup+ \def\do##1{\catcode`##1=11 }\dospecials+ \catcode`\{=1 \catcode`\}=2+ \subjectI}++\def\subjectI#1{\endgroup+ \immediate\write\sectionscratchfileport {#1}%+ \immediate\closeout\sectionscratchfileport+ $$\vbox{\bf \def\\{\cr}%+ \halign{\hfil##\hfil\cr+ \input Z-sec-temp+ \cr}}$$%+ \medskip}++\let\title\subject++% Sections++\def\tracksectionchangeatlevel#1{%+ \expandafter\let\expandafter\thiscount\csname+ sectionnumber#1\endcsname+ \ifx\thiscount\relax+ \expandafter\edef\csname sectionnumber#1\endcsname{0}%+ \fi+ \expandafter\advancetally+ \csname sectionnumber#1\endcsname 1%+ \ifx\doingappendix0%+ \edef\recentlabel{\csname sectionnumber1\endcsname}%+ \else+ %\count255=\expandafter\csname sectionnumber1\endcsname+ \edef\recentlabel{\char\csname sectionnumber1\endcsname}%+ \fi+ \count255=0+ \loop+ \advance\count255 by 1+ \ifnum\count255=1+ \else\edef\recentlabel{\recentlabel.\csname+ sectionnumber\the\count255\endcsname}\fi+ \ifnum\count255<#1%+ \repeat+ \loop+ \advance\count255 by 1+ \expandafter\let\expandafter\nextcount\csname+ sectionnumber\the\count255\endcsname+ \ifx\nextcount\relax+ \let\continue0%+ \else+ \expandafter\edef\csname+ sectionnumber\the\count255\endcsname{0}%+ \let\continue1\fi+ \ifx\continue1%+ \repeat}++% Vanilla section-header look -- change this macro for new look++\newcount\secnumdepth++\secnumdepth=10++\def\sectiond#1{\count255=#1%+ \ifx\usingchapters1\advance\count255 by 1 \fi+ \edef\sectiondlvl{\the\count255 }%+ \futurelet\sectionnextchar\sectiondispatch}++\def\sectiondispatch{\ifx\sectionnextchar*%+ \def\sectioncontinue{\sectionstar{\sectiondlvl}}\else+ \ifnum\sectiondlvl>\secnumdepth+ \def\sectioncontinue{\sectionhelp{\sectiondlvl}{}}\else+ \tracksectionchangeatlevel{\sectiondlvl}+ \def\sectioncontinue{\sectionhelp{\sectiondlvl}%+ {\recentlabel\enspace}}\fi\fi+ \sectioncontinue}++\def\sectionstar#1*{\sectionhelp{#1}{}}+++\def\sectionhelp#1#2{%+ \edef\sectiondepth{#1}%+ \def\sectionnr{#2}%+ \immediate\openout\sectionscratchfileport Z-sec-temp+ \begingroup+ \def\do##1{\catcode`##1=11 }\dospecials+ \catcode`\{=1 \catcode`\}= 2+ \sectionheader}++\def\sectionheader#1{\endgroup+ \immediate\write\sectionscratchfileport {#1}%+ \immediate\closeout\sectionscratchfileport + \vskip -\lastskip+ \ifnum\sectiondepth>\tocdepth\else+ \tocactivate+ {\let\folio0%+ \edef\temp{\write\tocout+ {\string\tocentry{\sectiondepth}{\sectionnr}{#1}{\folio}}}%+ \temp}\fi+ \vskip1.5\bigskipamount+\goodbreak %???+ \noindent+ \hbox{\vtop{\pretolerance 10000+ \raggedright+ \noindent\bf\sectionnr+ \input Z-sec-temp }}%+ \bgroup\let\par\sectionafterskip}++% \edef\temp{\write\tocout{\string\hskip#1\space em\string\relax\space #2%+% \string\vtop{\string\hsize=.7\string\hsize+% \string\noindent\string\raggedright\space #3}\string\par}}\temp++\def\sectionafterskip{\egroup\nobreak\par\noindent}++\def\section{\sectiond1}+\def\subsection{\sectiond2}+\def\subsubsection{\sectiond3}+\def\paragraph{\sectiond4}+\def\subparagraph{\sectiond5}++\let\usingchapters0++\def\chapter{\global\let\usingchapters1%+\futurelet\chapternextchar\chapterdispatch}++\def\chapterdispatch{\ifx\chapternextchar*%+ \let\chaptercontinue\chapterstar\else+ \tracksectionchangeatlevel{1}%+ \def\chaptercontinue{\chapterhelp{\recentlabel\enspace}}\fi+ \chaptercontinue}++\def\chapterstar*{\chapterhelp{}}++\def\chapterhelp#1{%+ % #1=number #2=heading-text+ \def\chapternr{#1}%+ \immediate\openout\sectionscratchfileport Z-sec-temp+ \begingroup+ \def\do##1{\catcode`##1=11 }\dospecials+ \catcode`\{=1 \catcode`\}=2+ \chapterheader}++\def\chapterheader#1{\endgroup+ \immediate\write\sectionscratchfileport {#1}%+ \immediate\closeout\sectionscratchfileport+ \tocactivate+ {\let\folio0%+ \edef\temp{\write\tocout{\string\tocentry{1}{\chapternr}{#1}{\folio}}}%+ \temp}%+ \vfill\eject+ \null\vskip3em+ \noindent+ \ifx\chapternr\empty\hbox{~}\else+ \ifx\doingappendix0%+ \hbox{\bf Chapter \chapternr}\else+ \hbox{\bf Appendix \chapternr}\fi\fi+ \vskip 1em+ \noindent+ \hbox{\bf\vtop{%\hsize=.7\hsize+ \pretolerance 10000+ \noindent\raggedright\input Z-sec-temp }}%+ \bgroup\let\par\chapterafterskip}++\def\chapterafterskip{\egroup\nobreak\vskip3em \noindent}++\let\doingappendix=0++\def\appendix{\let\doingappendix=1%+ \count255=`\A%+ \advance\count255 by -1+ \expandafter\edef\csname+ sectionnumber1\endcsname{\the\count255 }}+++% toc++\let\tocactive0++\newcount\tocdepth++\tocdepth=10++\def\tocoutensure{\ifx\tocout\UNDEFINED+ \csname newwrite\endcsname\tocout\fi}++\def\tocactivate{\ifx\tocactive0%+ \tocoutensure+ \tocsave+ \openout\tocout \jobname.toc+ \global\let\tocactive1\fi}++\def\tocspecials{\def\do##1{\catcode`##1=12 }\dospecials}++\def\tocsave{\openin0=\jobname.toc+ \ifeof0 \closein0 \else+ \openout\tocout Z-T-\jobname.tex+ \let\tocsaved 0%+ \loop+ \ifeof0 \closeout\tocout+ \let\tocsaved1%+ \else{\tocspecials+ \read0 to \tocsaveline+ \edef\temp{\write\tocout{\tocsaveline}}\temp}%+ \fi+ \ifx\tocsaved0%+ \repeat+ \fi+ \closein0 }++\def\tocentry#1#2{%+ %#1=depth #2=secnum+ \ifnum#1=1+ \ifnum\tocdepth>2+ \medbreak\begingroup\bf+ \else\begingroup\fi+ \else\begingroup\fi+ \vtop\bgroup\raggedright+ \noindent\hskip #1 em+ #2%+ \bgroup+ \aftergroup\tocentryI+ %read section title+ \let\dummy=}++\def\tocentryI#1{%+ %#1=page nr+ , #1\strut\egroup+ \endgroup\par+}++\def\tableofcontents{%+ \ifx\tocactive0%+ \openin0 \jobname.toc+ \ifeof0 \closein0 \else+ \closein0 \input \jobname.toc+ \fi+ \tocoutensure+ \openout\tocout \jobname.toc+ \global\let\tocactive1%+ \else+ \input Z-T-\jobname.tex+ \fi}++% allow {thebibliography} to be used directly+% in (plain-TeX) source document without +% generating it via BibTeX++\ifx\thebibliography\UnDeFiNeD+\def\thebibliography#1{\vskip-\lastskip+ \begingroup+ \def\endthebibliography{\endgroup\endgroup}%+ \def\input##1 ##2{\relax}%+ \setbox0=\hbox{\biblabelcontents{#1}}%+ \biblabelwidth=\wd0+ \@readbblfile}%+\fi++% Cross-references++% \openxrefout loads all the TAG-VALUE associations in+% \jobname.xrf and then opens \jobname.xrf as an+% output channel that \tag can use++\def\openxrefout{%+ \openin0=\jobname.xrf+ \ifeof0 \closein0 + \else \closein0 {\catcode`\\0 \input \jobname.xrf }%+ \fi+ \expandafter\csname newwrite\endcsname\xrefout+ \openout\xrefout=\jobname.xrf+}++% I'd like to call \openxrefout lazily, but+% unfortunately it produces a bug in MiKTeX.+% So let's call it up front.++\openxrefout++% \tag{TAG}{VALUE} associates TAG with VALUE.+% Hereafter, \ref{TAG} will output VALUE.+% \tag stores its associations in \xrefout.+% \tag calls \openxrefout if \jobname.xrf hasn't+% already been opened++\def\tag#1#2{\ifx\xrefout\UNDEFINED\openxrefout\fi+ {\let\folio0%+ \edef\temp{%+ \write\xrefout{\string\expandafter\string\gdef+ \string\csname\space XREF#1\string\endcsname+ {#2}\string\relax}}%+ \temp}}++% \tagref{TAG} outputs VALUE, assuming \tag put such+% an association into \xrefout. \tagref calls+% \openxrefout if \jobname.xrf hasn't already+% been opened++% Later, we will \let \ref = \tagref after making+% sure we aren't in eplain, which uses the ctlseq+% \ref differently++\def\tagref#1{\ifx\xrefout\UNDEFINED\openxrefout\fi+ \expandafter\ifx\csname XREF#1\endcsname\relax+ %\message or \write16 ?+ \message{\the\inputlineno: Unresolved label `#1'.}?\else+ \csname XREF#1\endcsname\fi}++% \label, as in LaTeX++\let\recentlabel\relax++% The sectioning commands+% define \recentlabel so a subsequent call to \label will pick up the+% right label.++\def\label#1{\tag{#1}{\recentlabel}%+ \tag{PAGE#1}{\folio}}++% \pageref, as in LaTeX++\def\pageref#1{\ref{PAGE#1}}++% eplain users see the \ref they are used to. Others+% have \ref = \tagref++\ifx\eplain\UnDeFiNeD+\let\ref\tagref+\fi++%++\ifx\IfFileExists\UnDeFiNeD+\def\IfFileExists#1#2#3{%+ \openin0 #1 %+ \ifeof0 %+ #3%+ \else + #2\fi+ \closein0 }%+\fi++\ifx\InputIfFileExists\UnDeFiNeD+\def\InputIfFileExists#1#2#3{%+ \IfFileExists{#1}{#2\input #1 }{#3}}%+\fi++\let\iffileexists\IfFileExists++%++% dummy def to let load dvipsnam.def ++\ifx\ProvidesFile\UnDeFiNeD+\def\ProvidesFile#1[#2]{}%+\fi++%++% Index generation+%+% Your TeX source contains \index{NAME} to+% signal that NAME should be included in the index.+% Check the makeindex documentation to see the various+% ways NAME can be specified, eg, for subitems, for+% explicitly specifying the alphabetization for a name+% involving TeX control sequences, etc.+%+% The first run of TeX will create \jobname.idx.+% makeindex on \jobname[.idx] will create the sorted+% index \jobname.ind.+%+% Use \inputindex (without arguments) to include this+% sorted index, typically somewhere to the end of your+% document. This will produce the items and subitems.+% It won't produce a section heading however -- you+% will have to typeset one yourself.+%+% Use \printindex instead of \inputindex if you want+% the section heading ``Index'' automatically generated.++\def\sanitizeidxletters{\def\do##1{\catcode`##1=11 }%+ \do\\\do\$\do\&\do\#\do\^\do\_\do\%\do\~%+ \do\@\do\"\do\!\do\|\do\-\do\ \do\'}++\def\index{%\unskip+ \ifx\indexout\UNDEFINED+ \csname newwrite\endcsname\indexout+ \openout\indexout \jobname.idx\fi+ \begingroup+ \sanitizeidxletters+ \indexI}++\def\indexI#1{\endgroup+ \write\indexout{\string\indexentry{#1}{\folio}}%+ \ignorespaces}++% The following index style indents subitems on a+% separate lines++\def\theindex{\begingroup+ \parskip0pt \parindent0pt+ \def\indexitem##1{\par\hangindent30pt \hangafter1+ \hskip ##1 }%+ \def\item{\indexitem{0em}}%+ \def\subitem{\indexitem{2em}}%+ \def\subsubitem{\indexitem{4em}}%+ \def\see{{\it see} \bgroup\aftergroup\gobblegroup\let\dummy=}%+ \let\indexspace\medskip}++\def\endtheindex{\endgroup}++% \packindex declares that subitems be bundled into one+% semicolon-separated paragraph++\def\packindex{%+ \def\theindex{\begingroup+ \parskip0pt \parindent0pt+ \def\item{\par\hangindent20pt \hangafter1 }%+ \def\subitem{\unskip; }%+ \def\subsubitem{\unskip; }%+ \def\see{\bgroup\it see \aftergroup\gobblegroup\let\dummy=}%+ \let\indexspace\medskip}}++\def\inputindex{%+ \openin0 \jobname.ind+ \ifeof0 \closein0+ \message{\jobname.ind missing.}%+ \else\closein0+ \begingroup+ \def\begin##1{\csname##1\endcsname}%+ \def\end##1{\csname end##1\endcsname}%+ \input\jobname.ind+ \endgroup\fi}++\def\printindex{\csname beginsection\endcsname Index\par+ \inputindex}++%++\def\italiccorrection{\futurelet\italiccorrectionI+ \italiccorrectionII}++\def\italiccorrectionII{%+ \if\noexpand\italiccorrectionI,\else+ \if\noexpand\italiccorrectionI.\else+ \/\fi\fi}++\def\em{\it\ifmmode\else\aftergroup\italiccorrection\fi}++%\def\emph{\bgroup\it+% \ifmmode\else\aftergroup\italiccorrection\fi+% \let\dummy=}++\def\quote{\bgroup\narrower\smallbreak}+\def\endquote{\smallbreak\egroup}++\def\begin#1{\begingroup+ \def\end##1{\csname end#1\endcsname\endgroup}%+ \csname #1\endcsname}++\def\raggedleft{%+ \leftskip 0pt plus 1fil+ \parfillskip 0pt+}++\def\r#1{{\accent23 #1}}+++\ifx\strip@pt\UNDEFINED+\begingroup+ \catcode`P 12 \catcode`T 12+ \lowercase{\endgroup+ \gdef\strip@pt#1PT{#1}}%+\fi++% color++\ifx\color\UnDeFiNeD +%+\ifx\pdfoutput\UnDeFiNeD % PostScript+%+\def\colorCurrentColor{color cmyk 0 0 0 1}%+%+\def\colorRestoreCurrentColor{%+\special{\colorCurrentColor}\egroup\egroup}%+%+\def\colorWithModelrgb#1{\bgroup+\def\colorCurrentColor{color rgb #1}%+\special{\colorCurrentColor}%+\aftergroup\colorRestoreCurrentColor}%+%+\def\colorWithModelRGBaux#1 #2 #3\end{\bgroup+\dimen0=#1pt \divide\dimen0 by 255+\edef\red{\expandafter\strip@pt\the\dimen0 }%+\dimen0=#2pt \divide\dimen0 by 255+\edef\green{\expandafter\strip@pt\the\dimen0 }%+\dimen0=#3pt \divide\dimen0 by 255+\edef\blue{\expandafter\strip@pt\the\dimen0 }%+\def\colorCurrentColor{color rgb \red\space \green\space \blue}%+\special{\colorCurrentColor}%+\aftergroup\colorRestoreCurrentColor+\ignorespaces}+%+\def\colorWithModelcmyk#1{\bgroup+\def\colorCurrentColor{color cmyk #1}%+\special{\colorCurrentColor}%+\aftergroup\colorRestoreCurrentColor}%+%+\def\colorWithModelgray#1{\bgroup+\def\colorCurrentColor{color gray #1}%+\special{\colorCurrentColor}%+\aftergroup\colorRestoreCurrentColor}%+%+\def\colorWithModelnamed#1{\bgroup+\edef\colorCurrentColor{\csname+ColorNamed#1\endcsname}%+\special{\colorCurrentColor}%+\aftergroup\colorRestoreCurrentColor}%+%+\def\definecolorWithModelrgb#1#2{\egroup+\expandafter\def\csname ColorNamed#1\endcsname+{color rgb #2}}%+%+\def\definecolorWithModelcmyk#1#2{\egroup+\expandafter\def\csname ColorNamed#1\endcsname+{color cmyk #2}}%+%+\def\definecolorWithModelgray#1#2{\egroup+\expandafter\def\csname ColorNamed#1\endcsname+{color gray #2}}%+%+\else % PDF+%+\def\colorCurrentColor{0 0 0 1 k}%+%+\def\colorRestoreCurrentColor{%+\pdfliteral{\colorCurrentColor}\egroup\egroup}%+%+\def\colorWithModelrgb#1{\bgroup+\def\colorCurrentColor{#1 rg}%+\pdfliteral{\colorCurrentColor}%+\aftergroup\colorRestoreCurrentColor+\ignorespaces}%+%+\def\colorWithModelRGBaux#1 #2 #3\end{\bgroup+\dimen0=#1pt \divide\dimen0 by 255+\edef\red{\expandafter\strip@pt\the\dimen0 }%+\dimen0=#2pt \divide\dimen0 by 255+\edef\green{\expandafter\strip@pt\the\dimen0 }%+\dimen0=#3pt \divide\dimen0 by 255+\edef\blue{\expandafter\strip@pt\the\dimen0 }%+\def\colorCurrentColor{\red\space \green\space \blue\space rg}%+\pdfliteral{\colorCurrentColor}%+\aftergroup\colorRestoreCurrentColor+\ignorespaces}+%+\def\colorWithModelcmyk#1{\bgroup+\def\colorCurrentColor{#1 k}%+\pdfliteral{\colorCurrentColor}%+\aftergroup\colorRestoreCurrentColor+\ignorespaces}%+%+\def\colorWithModelgray#1{\bgroup+\def\colorCurrentColor{#1 g}%+\pdfliteral{\colorCurrentColor}%+\aftergroup\colorRestoreCurrentColor+\ignorespaces}%+%+\def\colorWithModelnamed#1{\bgroup+\edef\colorCurrentColor{\csname+ColorNamed#1\endcsname}%+\pdfliteral{\colorCurrentColor}%+\aftergroup\colorRestoreCurrentColor+\ignorespaces}%+%+\def\definecolorWithModelrgb#1#2{\egroup+\expandafter\def\csname ColorNamed#1\endcsname+{#2 rg}}%+%+\def\definecolorWithModelcmyk#1#2{\egroup+\expandafter\def\csname ColorNamed#1\endcsname+{#2 k}}%+%+\def\definecolorWithModelgray#1#2{\egroup+\expandafter\def\csname ColorNamed#1\endcsname+{#2 g}}%+%+\fi+%+\def\color{\futurelet\colorQpeekchar\colorQpossiblynamed}%+%+\def\colorQpossiblynamed{\bgroup+\defcsactive\,{ }%+\if\colorQpeekchar[%+\let\colorQproceed\colorQexplicitmodel\else+\let\colorQproceed\colorWithModelnamed\fi+\colorQproceed}%+%+\def\colorQexplicitmodel[#1]{%+\csname colorWithModel#1\endcsname}%+%+\def\colorWithModelRGB#1{%+\colorWithModelRGBaux#1\end}%+%+\def\definecolor#1#2{\bgroup+\defcsactive\,{ }%+\csname definecolorWithModel#2\endcsname{#1}}%+%+% foll lets load texmf/tex/latex/graphics/dvipsnam.def+\def\DefineNamedColor#1{\definecolor}%+%+% these colors are standard in latex+\definecolor{red}{rgb}{1 0 0}%+\definecolor{green}{rgb}{0 1 0}%+\definecolor{blue}{rgb}{0 1 1}%+\definecolor{cyan}{cmyk}{1 0 0 0}%+\definecolor{magenta}{cmyk}{0 1 0 0}%+\definecolor{yellow}{cmyk}{0 0 1 0}%+\definecolor{black}{cmyk}{0 0 0 1}%+\definecolor{white}{rgb}{1 1 1}%+%+\fi++%the rest of the file isn't needed for eplain?++\def\itemize{\par\begingroup+ \advance\leftskip\parindent+ \smallbreak+ \def\item{\smallbreak\noindent+ \llap{$\bullet$\enspace}\ignorespaces}}++\def\enditemize{\smallbreak\smallbreak\endgroup\par}++\newtally\enumeratelevel++\def\enumerate{\par\begingroup+ \advancetally\enumeratelevel1%+ \newtally\enumeratenumber+ \advance\leftskip\parindent+ \smallbreak+ \def\item{\smallbreak\noindent+ \advancetally\enumeratenumber1%+ \ifnum\enumeratelevel=1 + \edef\enumeratemark{\enumeratenumber}\else+ \ifnum\enumeratelevel=2 + \count255=\enumeratenumber + \advance\count255 by -1 \advance\count255 by `a+ \edef\enumeratemark{\noexpand\char\the\count255 }\else+ \ifnum\enumeratelevel=3 + \edef\enumeratemark{\romannumeral\enumeratenumber}\else+ \ifnum\enumeratelevel=4+ \count255=\enumeratenumber + \advance\count255 by -1 \advance\count255 by `A+ \edef\enumeratemark{\noexpand\char\the\count255 }\else+ \edef\enumeratemark{\enumeratenumber}\fi\fi\fi\fi+ \edef\recentlabel{\enumeratemark}% needed?+ \llap{\enumeratemark.\enspace}\ignorespaces}}++\def\endenumerate{\smallbreak\smallbreak\endgroup\par}++% Numbered footnotes++\ifx\plainfootnote\UNDEFINED+ \let\plainfootnote\footnote+\fi++\newtally\footnotenumber++\def\numfootnote{\globaladvancetally\footnotenumber 1%+ \bgroup\csname footnotehook\endcsname+ \plainfootnote{$^{\footnotenumber}$}\bgroup+ \edef\recentlabel{\footnotenumber}%+ \aftergroup\egroup+ \let\dummy=}++\let\f\numfootnote++\ifx\frac\UnDeFiNeD+\def\frac#1/#2{{#1\over#2}}%+\fi++% \path is like \verb except that its argument+% can break across lines at `.' and `/'.++\ifx\path\UnDeFiNeD+\def\path{\begingroup\verbsetup+ \pathfont+ \defcsactive\.{\discretionary{\char`\.}{}{\char`\.}}%+ \defcsactive\/{\discretionary{\char`\/}{}{\char`\/}}%+ \verbI}%+\fi++\let\pathfont\relax++\catcode`\@\atcatcodebeforetiip++\endtexonly++% end of file
plugins.cabal view
@@ -1,5 +1,5 @@ name: plugins-version: 1.2+version: 1.3 homepage: http://code.haskell.org/~dons/code/hs-plugins synopsis: Dynamic linking for Haskell and C objects description: Dynamic linking and runtime evaluation of Haskell,@@ -10,7 +10,7 @@ category: System license: BSD3 License-file: LICENSE-author: Don Stewart+author: Don Stewart 2004-2008 maintainer: Don Stewart <dons@galois.com> cabal-version: >= 1.2 build-type: Configure
+ scripts/Setup-with-ghc.lhs view
@@ -0,0 +1,20 @@+#!/usr/bin/env runhaskell+> module Main where+> import Distribution.Simple+> import Distribution.Setup ( ConfigFlags (..) )+> import System.Directory ( findExecutable )+> +> main :: IO ()+> main = defaultMainWithHooks (defaultUserHooks { postConf = defaultPostConf })+> where defaultPostConf args flags lbi {- xx -}+> = do args' <- fmap (args++) (configToArgs flags)+> (postConf defaultUserHooks) args' flags lbi {- xx -}+> +> -- need to pass with-ghc arg onto ./configure for non-standard ghcs+> configToArgs :: ConfigFlags -> IO [String]+> configToArgs (ConfigFlags { configHcPath = Just hcPath })+> = do exec <- findExecutable hcPath+> case exec of+> Just realPath -> return ["--with-ghc="++realPath]+> Nothing -> return ["--with-ghc="++hcPath]+> configToArgs _ = return []
+ scripts/mkrelease.sh view
@@ -0,0 +1,11 @@+#!/bin/sh++cd /tmp+rm -rf hs-plugins-0.9.10*++darcs get --partial --set-scripts-executable /home/dons/hs-plugins+cd hs-plugins+rm -rf _darcs+cd ..+mv hs-plugins hs-plugins-0.9.10+tar czf hs-plugins-0.9.10.tar.gz hs-plugins-0.9.10
+ scripts/openbsd-port/Makefile view
@@ -0,0 +1,21 @@+# $OpenBSD$++COMMENT= "dynamic link library for Haskell"++V= 0.9.10+DISTNAME= hs-plugins-${V}+CATEGORIES= devel+MAINTAINER= Don Stewart <dons@openbsd.org>+HOMEPAGE= http://www.cse.unsw.edu.au/~dons/hs-plugins/+MASTER_SITES= ${HOMEPAGE}++MODULES= ghc+CONFIGURE_STYLE= gnu dest++# LGPL+PERMIT_PACKAGE_CDROM= Yes+PERMIT_PACKAGE_FTP= Yes+PERMIT_DISTFILES_CDROM= Yes+PERMIT_DISTFILES_FTP= Yes++.include <bsd.port.mk>
+ scripts/openbsd-port/distinfo view
@@ -0,0 +1,3 @@+MD5 (hs-plugins-0.9.4.tar.gz) = 120f38ca532b187ee52798f5c36cc920+RMD160 (hs-plugins-0.9.4.tar.gz) = 219eaf70e4bc0f1abc8a782d1bbd64ad2c5f8e86+SHA1 (hs-plugins-0.9.4.tar.gz) = ad38b9f4e5b90c1361c6c96bd94e2a9270ad3d78
+ scripts/openbsd-port/pkg/DESCR view
@@ -0,0 +1,6 @@+hs-plugins is a library for dynamic loading and compilation of Haskell+code. It provides typesafe "plugins" for Haskell. The interface is+general enough that it can be used to create conventional plugins,+hmake-like Haskell interpreters embedded in applications, or to script+an application with Haskell (or a Haskell EDSL) as the extension+language.
+ scripts/openbsd-port/pkg/PLIST view
@@ -0,0 +1,28 @@+@comment $OpenBSD$+lib/hs-plugins/imports/Plugins.hi+lib/hs-plugins/imports/Plugins/BinIface.hi+lib/hs-plugins/imports/Plugins/Binary.hi+lib/hs-plugins/imports/Plugins/Consts.hi+lib/hs-plugins/imports/Plugins/Env.hi+lib/hs-plugins/imports/Plugins/FastMutInt.hi+lib/hs-plugins/imports/Plugins/FastString.hi+lib/hs-plugins/imports/Plugins/Iface.hi+lib/hs-plugins/imports/Plugins/Load.hi+lib/hs-plugins/imports/Plugins/Make.hi+lib/hs-plugins/imports/Plugins/Package.hi+lib/hs-plugins/imports/Plugins/ParsePkgConfLite.hi+lib/hs-plugins/imports/Plugins/Parser.hi+lib/hs-plugins/imports/Plugins/PrimPacked.hi+lib/hs-plugins/imports/Plugins/Utils.hi+lib/hs-plugins/include/hschooks.h+lib/hs-plugins/libHSplugins.a+lib/hs-plugins/libHSplugins_cbits.a+lib/hs-plugins/plugins.conf.in+@dirrm lib/hs-plugins/include+@dirrm lib/hs-plugins/imports/Plugins+@dirrm lib/hs-plugins/imports+@dirrm lib/hs-plugins+@exec /bin/cat %D/lib/hs-plugins/plugins.conf.in | /usr/bin/env PREFIX=%D %D/bin/ghc-pkg -u+@exec /bin/rm -f %D/lib/ghc-6.2.1/package.conf.old+@unexec %D/bin/ghc-pkg -r plugins+@unexec /bin/rm -f %D/lib/ghc-6.2.1/package.conf.old
src/System/Plugins/Env.hs view
@@ -61,13 +61,14 @@ import Data.IORef ( writeIORef, readIORef, newIORef, IORef() ) import Data.Maybe ( isJust, isNothing, fromMaybe )-import Data.List ( isPrefixOf, nub )+import Data.List ( isPrefixOf, isInfixOf, nub ) import System.IO.Unsafe ( unsafePerformIO )+import System.IO ( hGetContents ) import System.Directory ( doesFileExist )+import System.Process ( waitForProcess, runInteractiveCommand ) #if defined(CYGWIN) || defined(__MINGW32__) import Prelude hiding ( catch, ioError )-import System.Environment ( getEnv ) import System.IO.Error ( catch, ioError, isDoesNotExistError ) #endif @@ -297,9 +298,11 @@ -- grabDefaultPkgConf :: IO PkgEnvs+ grabDefaultPkgConf = do- pkgs <- readPackageConf $ ghcLibraryPath </> sysPkgConf- return $ union [] pkgs+ pkg_confs <- get_ghc_configs+ packages <- mapM readPackageConf pkg_confs+ return $ foldl union [] packages -- -- parse a source file, expanding any $libdir we see.@@ -514,3 +517,26 @@ (</>) :: FilePath -> FilePath -> FilePath [] </> b = b a </> b = a ++ "/" ++ b++-------------------------------------------------------------------------+--+-- 'run_cmd' executes command and returns it's standard output+-- as 'String'++run_cmd :: String -> IO String+run_cmd cmd = do (_hI, hO, _hE, hProcess) <- runInteractiveCommand cmd+ output <- hGetContents hO+ _exitCode <- waitForProcess hProcess+ return output+--+-- 'get_ghc_configs' returns list of strings of packages.conf files in system++get_ghc_configs :: IO [String]+get_ghc_configs = do ghc_out <- run_cmd "ghc-pkg list"+ let configs = map (reverse.strip_trash.reverse) $+ filter (isInfixOf sysPkgConf) $ lines ghc_out+ return configs+ -- | strip ":\r?" from string head+ where strip_trash [] = []+ strip_trash xs@(x:xs') | x `elem` ":\r" = strip_trash xs'+ | otherwise = xs
src/System/Plugins/Load.hs view
@@ -661,7 +661,7 @@ -- now, try to generate a path to the actual .o file -- fix up hierachical names let mods_ = map (\s -> (s, map (\c -> - if c == '.' then '/' else c) $ decode s)) ds'+ if c == '.' then '/' else c) $ s)) ds' -- construct a list of possible dependent modules to load let mods = concatMap (\p -> @@ -691,7 +691,7 @@ #if DEBUG when (not (null ps')) $ putStrLn "done" putStr "Loading object" - mapM_ (\(m,_) -> putStr (" "++(decode m)) >> hFlush stdout) mods''+ mapM_ (\(m,_) -> putStr (" "++ m) >> hFlush stdout) mods'' #endif moduleDeps <- mapM (\(hi,m) -> loadObject m (Object hi)) mods'' return (hiface,moduleDeps)
+ src/System/Plugins/ParsePkgConfCabal.y_in view
@@ -0,0 +1,218 @@+-- +-- Copyright (C) 2005 Sean Seefried - http://www.cse.unsw.edu.au/~sseefried+-- +-- This library is free software; you can redistribute it and/or+-- modify it under the terms of the GNU Lesser General Public+-- License as published by the Free Software Foundation; either+-- version 2.1 of the License, or (at your option) any later version.+-- +-- This library is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU+-- Lesser General Public License for more details.+-- +-- You should have received a copy of the GNU Lesser General Public+-- License along with this library; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307+-- USA+-- ++-- +-- Taken (apart from the most minor of alterations) from+-- ghc/utils/ghc-pkg/ParsePkgConfLite.hs from GHC 6.2.2 source tree+-- and then modified to mimic the behaviour of the parser within+-- ghc/compiler/main/ParsePkgConf.y in GHC 6.4, without importing+-- heavy-weight infrastructure from the GHC source tree such as module+-- FastString, Lexer, etc.+--+-- (c) Copyright 2002, The University Court of the University of Glasgow. +--++{+{-# OPTIONS -w #-}++module System.Plugins.ParsePkgConfCabal ( + parsePkgConf, parseOnePkgConf+ ) where++import Distribution.InstalledPackageInfo+import Distribution.Package+import Distribution.Version++import Data.Char ( isSpace, isAlpha, isAlphaNum, isUpper, isDigit )+import Data.List ( break )++}++%token+ '{' { ITocurly }+ '}' { ITccurly }+ '[' { ITobrack }+ ']' { ITcbrack }+ ',' { ITcomma }+ '=' { ITequal }+ VARID { ITvarid $$ }+ CONID { ITconid $$ }+ STRING { ITstring $$ }+ INT { ITinteger $$ }++%name parse pkgconf+%name parseOne pkg+%tokentype { Token }+%%++pkgconf :: { [ PackageConfig ] }+ : '[' ']' { [] }+ | '[' pkgs ']' { reverse $2 }++pkgs :: { [ PackageConfig ] }+ : pkg { [ $1 ] }+ | pkgs ',' pkg { $3 : $1 }++pkg :: { PackageConfig }+ : CONID '{' fields '}' { $3 defaultPackageConfig }++fields :: { PackageConfig -> PackageConfig }+ : field { \p -> $1 p }+ | fields ',' field { \p -> $1 ($3 p) }++field :: { PackageConfig -> PackageConfig }+ : VARID '=' pkgid+ {\p -> case $1 of+ "package" -> p {package = $3}+ _ -> error "unknown key in config file" }+ + | VARID '=' STRING { id }+ -- we aren't interested in the string fields, they're all+ -- boring (copyright, maintainer etc.)++ | VARID '=' CONID+ { case $1 of {+ "exposed" -> + case $3 of {+ "True" -> (\p -> p {exposed=True});+ "False" -> (\p -> p {exposed=False});+ _ -> error "exposed must be either True or False" };+ "license" -> id; -- not interested+ _ -> error "unknown constructor" }+ }++ | VARID '=' CONID STRING { id }+ -- another case of license++ | VARID '=' strlist+ {\p -> case $1 of+ "exposedModules" -> p{exposedModules = $3}+ "hiddenModules" -> p{hiddenModules = $3}+ "importDirs" -> p{importDirs = $3}+ "libraryDirs" -> p{libraryDirs = $3}+ "hsLibraries" -> p{hsLibraries = $3}+ "extraLibraries" -> p{extraLibraries = $3}+ "includeDirs" -> p{includeDirs = $3}+ "includes" -> p{includes = $3}+ "hugsOptions" -> p{hugsOptions = $3}+ "ccOptions" -> p{ccOptions = $3}+ "ldOptions" -> p{ldOptions = $3}+ "frameworkDirs" -> p{frameworkDirs = $3}+ "frameworks" -> p{frameworks = $3}+ "haddockInterfaces" -> p{haddockInterfaces = $3}+ "haddockHTMLs" -> p{haddockHTMLs = $3}+ "depends" -> p{depends = []}+ -- empty list only, non-empty handled below+ other -> p+ }+ | VARID '=' pkgidlist+ { case $1 of+ "depends" -> (\p -> p{depends = $3})+ _other -> error "unknown key in config file"+ }+++pkgid :: { PackageIdentifier }+ : CONID '{' VARID '=' STRING ',' VARID '=' version '}'+ { PackageIdentifier{ pkgName = $5, + pkgVersion = $9 } }++version :: { Version }+ : CONID '{' VARID '=' intlist ',' VARID '=' strlist '}'+ { Version{ versionBranch=$5, versionTags=$9 } }++pkgidlist :: { [PackageIdentifier] }+ : '[' pkgids ']' { $2 }+ -- empty list case is covered by strlist, to avoid conflicts++pkgids :: { [PackageIdentifier] }+ : pkgid { [ $1 ] }+ | pkgid ',' pkgids { $1 : $3 }++intlist :: { [Int] }+ : '[' ']' { [] }+ | '[' ints ']' { $2 }++ints :: { [Int] }+ : INT { [ fromIntegral $1 ] }+ | INT ',' ints { fromIntegral $1 : $3 }++strlist :: { [String] }+ : '[' ']' { [] }+ | '[' strs ']' { reverse $2 }++strs :: { [String] }+ : STRING { [ $1 ] }+ | strs ',' STRING { $3 : $1 }++{++type PackageConfig = InstalledPackageInfo++defaultPackageConfig = emptyInstalledPackageInfo++data Token + = ITocurly+ | ITccurly+ | ITobrack+ | ITcbrack+ | ITcomma+ | ITequal+ | ITvarid String+ | ITconid String+ | ITstring String+ | ITinteger Int++lexer :: String -> [Token]++lexer [] = []+lexer ('{':cs) = ITocurly : lexer cs+lexer ('}':cs) = ITccurly : lexer cs+lexer ('[':cs) = ITobrack : lexer cs+lexer (']':cs) = ITcbrack : lexer cs+lexer (',':cs) = ITcomma : lexer cs+lexer ('=':cs) = ITequal : lexer cs+lexer ('"':cs) = lexString cs ""+lexer (c:cs)+ | isSpace c = lexer cs+ | isAlpha c = lexID (c:cs) + | isDigit c = lexInt (c:cs)+lexer _ = error ( "Unexpected token")++lexID cs = (if isUpper (head cs) then ITconid else ITvarid) id : lexer rest+ where+ (id,rest) = break (\c -> c /= '_' && not (isAlphaNum c)) cs++lexInt cs = let (intStr, rest) = span isDigit cs+ in ITinteger (read intStr) : lexer rest+++lexString ('"':cs) s = ITstring (reverse s) : lexer cs+lexString ('\\':c:cs) s = lexString cs (c:s)+lexString (c:cs) s = lexString cs (c:s)++happyError _ = error "Couldn't parse package configuration."++parsePkgConf :: String -> [PackageConfig]+parsePkgConf = parse . lexer++parseOnePkgConf :: String -> PackageConfig+parseOnePkgConf = parseOne . lexer++}
+ src/System/Plugins/ParsePkgConfLite.hs view
@@ -0,0 +1,616 @@+{-# OPTIONS -fglasgow-exts #-}+{-# OPTIONS -w #-}++module System.Plugins.ParsePkgConfLite ( + parsePkgConf, parseOnePkgConf+ ) where++import System.Plugins.Package ( PackageConfig(..), defaultPackageConfig )++import Char ( isSpace, isAlpha, isAlphaNum, isUpper )+import List ( break )+import Array+#if __GLASGOW_HASKELL__ >= 503+import GHC.Exts+#else+import GlaExts+#endif++-- parser produced by Happy Version 1.15++newtype HappyAbsSyn = HappyAbsSyn (() -> ())+happyIn5 :: ([ PackageConfig ]) -> (HappyAbsSyn )+happyIn5 x = unsafeCoerce# x+{-# INLINE happyIn5 #-}+happyOut5 :: (HappyAbsSyn ) -> ([ PackageConfig ])+happyOut5 x = unsafeCoerce# x+{-# INLINE happyOut5 #-}+happyIn6 :: ([ PackageConfig ]) -> (HappyAbsSyn )+happyIn6 x = unsafeCoerce# x+{-# INLINE happyIn6 #-}+happyOut6 :: (HappyAbsSyn ) -> ([ PackageConfig ])+happyOut6 x = unsafeCoerce# x+{-# INLINE happyOut6 #-}+happyIn7 :: (PackageConfig) -> (HappyAbsSyn )+happyIn7 x = unsafeCoerce# x+{-# INLINE happyIn7 #-}+happyOut7 :: (HappyAbsSyn ) -> (PackageConfig)+happyOut7 x = unsafeCoerce# x+{-# INLINE happyOut7 #-}+happyIn8 :: (PackageConfig -> PackageConfig) -> (HappyAbsSyn )+happyIn8 x = unsafeCoerce# x+{-# INLINE happyIn8 #-}+happyOut8 :: (HappyAbsSyn ) -> (PackageConfig -> PackageConfig)+happyOut8 x = unsafeCoerce# x+{-# INLINE happyOut8 #-}+happyIn9 :: (PackageConfig -> PackageConfig) -> (HappyAbsSyn )+happyIn9 x = unsafeCoerce# x+{-# INLINE happyIn9 #-}+happyOut9 :: (HappyAbsSyn ) -> (PackageConfig -> PackageConfig)+happyOut9 x = unsafeCoerce# x+{-# INLINE happyOut9 #-}+happyIn10 :: ([String]) -> (HappyAbsSyn )+happyIn10 x = unsafeCoerce# x+{-# INLINE happyIn10 #-}+happyOut10 :: (HappyAbsSyn ) -> ([String])+happyOut10 x = unsafeCoerce# x+{-# INLINE happyOut10 #-}+happyIn11 :: ([String]) -> (HappyAbsSyn )+happyIn11 x = unsafeCoerce# x+{-# INLINE happyIn11 #-}+happyOut11 :: (HappyAbsSyn ) -> ([String])+happyOut11 x = unsafeCoerce# x+{-# INLINE happyOut11 #-}+happyIn12 :: (Bool) -> (HappyAbsSyn )+happyIn12 x = unsafeCoerce# x+{-# INLINE happyIn12 #-}+happyOut12 :: (HappyAbsSyn ) -> (Bool)+happyOut12 x = unsafeCoerce# x+{-# INLINE happyOut12 #-}+happyInTok :: Token -> (HappyAbsSyn )+happyInTok x = unsafeCoerce# x+{-# INLINE happyInTok #-}+happyOutTok :: (HappyAbsSyn ) -> Token+happyOutTok x = unsafeCoerce# x+{-# INLINE happyOutTok #-}++happyActOffsets :: HappyAddr+happyActOffsets = HappyA# "\x1f\x00\x1e\x00\x1d\x00\x1b\x00\x1a\x00\x1c\x00\x19\x00\x01\x00\x0e\x00\x00\x00\x00\x00\x17\x00\x08\x00\x00\x00\x16\x00\x00\x00\x13\x00\x00\x00\xfe\xff\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\xff\xff\x00\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x11\x00\x00\x00\x00\x00"#++happyGotoOffsets :: HappyAddr+happyGotoOffsets = HappyA# "\x18\x00\x15\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14\x00\x00\x00\xfd\xff\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"#++happyDefActions :: HappyAddr+happyDefActions = HappyA# "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfb\xff\xfd\xff\x00\x00\x00\x00\xf8\xff\x00\x00\xfc\xff\x00\x00\xfa\xff\x00\x00\xf9\xff\x00\x00\xf7\xff\xf4\xff\xf5\xff\x00\x00\xef\xff\xf6\xff\x00\x00\xf3\xff\xf1\xff\xf2\xff\x00\x00\xf0\xff"#++happyCheck :: HappyAddr+happyCheck = HappyA# "\xff\xff\x03\x00\x05\x00\x04\x00\x07\x00\x04\x00\x08\x00\x09\x00\x09\x00\x08\x00\x02\x00\x01\x00\x02\x00\x05\x00\x03\x00\x04\x00\x04\x00\x05\x00\x04\x00\x05\x00\x04\x00\x06\x00\x02\x00\x02\x00\x00\x00\x07\x00\x09\x00\x08\x00\x06\x00\x01\x00\x07\x00\x04\x00\x03\x00\xff\xff\x03\x00\x0a\x00\x0a\x00\xff\xff\x08\x00\xff\xff\xff\xff\xff\xff"#++happyTable :: HappyAddr+happyTable = HappyA# "\x00\x00\x19\x00\x16\x00\x1d\x00\x17\x00\x0b\x00\x1a\x00\x1b\x00\x1e\x00\x06\x00\x14\x00\x08\x00\x09\x00\x15\x00\x0c\x00\x0d\x00\x1f\x00\x20\x00\x10\x00\x11\x00\x15\x00\x1b\x00\x11\x00\x04\x00\x06\x00\x0f\x00\x21\x00\x06\x00\x13\x00\x0c\x00\x0f\x00\x0b\x00\x04\x00\x00\x00\x08\x00\xff\xff\xff\xff\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00"#++happyReduceArr = array (2, 16) [+ (2 , happyReduce_2),+ (3 , happyReduce_3),+ (4 , happyReduce_4),+ (5 , happyReduce_5),+ (6 , happyReduce_6),+ (7 , happyReduce_7),+ (8 , happyReduce_8),+ (9 , happyReduce_9),+ (10 , happyReduce_10),+ (11 , happyReduce_11),+ (12 , happyReduce_12),+ (13 , happyReduce_13),+ (14 , happyReduce_14),+ (15 , happyReduce_15),+ (16 , happyReduce_16)+ ]++happy_n_terms = 11 :: Int+happy_n_nonterms = 8 :: Int++happyReduce_2 = happySpecReduce_2 0# happyReduction_2+happyReduction_2 happy_x_2+ happy_x_1+ = happyIn5+ ([]+ )++happyReduce_3 = happySpecReduce_3 0# happyReduction_3+happyReduction_3 happy_x_3+ happy_x_2+ happy_x_1+ = case happyOut6 happy_x_2 of { happy_var_2 -> + happyIn5+ (reverse happy_var_2+ )}++happyReduce_4 = happySpecReduce_1 1# happyReduction_4+happyReduction_4 happy_x_1+ = case happyOut7 happy_x_1 of { happy_var_1 -> + happyIn6+ ([ happy_var_1 ]+ )}++happyReduce_5 = happySpecReduce_3 1# happyReduction_5+happyReduction_5 happy_x_3+ happy_x_2+ happy_x_1+ = case happyOut6 happy_x_1 of { happy_var_1 -> + case happyOut7 happy_x_3 of { happy_var_3 -> + happyIn6+ (happy_var_3 : happy_var_1+ )}}++happyReduce_6 = happyReduce 4# 2# happyReduction_6+happyReduction_6 (happy_x_4 `HappyStk`+ happy_x_3 `HappyStk`+ happy_x_2 `HappyStk`+ happy_x_1 `HappyStk`+ happyRest)+ = case happyOut8 happy_x_3 of { happy_var_3 -> + happyIn7+ (happy_var_3 defaultPackageConfig+ ) `HappyStk` happyRest}++happyReduce_7 = happySpecReduce_1 3# happyReduction_7+happyReduction_7 happy_x_1+ = case happyOut9 happy_x_1 of { happy_var_1 -> + happyIn8+ (\p -> happy_var_1 p+ )}++happyReduce_8 = happySpecReduce_3 3# happyReduction_8+happyReduction_8 happy_x_3+ happy_x_2+ happy_x_1+ = case happyOut8 happy_x_1 of { happy_var_1 -> + case happyOut9 happy_x_3 of { happy_var_3 -> + happyIn8+ (\p -> happy_var_1 (happy_var_3 p)+ )}}++happyReduce_9 = happySpecReduce_3 4# happyReduction_9+happyReduction_9 happy_x_3+ happy_x_2+ happy_x_1+ = case happyOutTok happy_x_1 of { (ITvarid happy_var_1) -> + case happyOutTok happy_x_3 of { (ITstring happy_var_3) -> + happyIn9+ (\p -> case happy_var_1 of+ "name" -> p{name = happy_var_3}+ _ -> error "unknown key in config file"+ )}}++happyReduce_10 = happySpecReduce_3 4# happyReduction_10+happyReduction_10 happy_x_3+ happy_x_2+ happy_x_1+ = case happyOutTok happy_x_1 of { (ITvarid happy_var_1) -> + case happyOut12 happy_x_3 of { happy_var_3 -> + happyIn9+ (\p -> case happy_var_1 of {+ "auto" -> p{auto = happy_var_3};+ _ -> p }+ )}}++happyReduce_11 = happySpecReduce_3 4# happyReduction_11+happyReduction_11 happy_x_3+ happy_x_2+ happy_x_1+ = case happyOutTok happy_x_1 of { (ITvarid happy_var_1) -> + case happyOut10 happy_x_3 of { happy_var_3 -> + happyIn9+ (\p -> case happy_var_1 of+ "import_dirs" -> p{import_dirs = happy_var_3}+ "library_dirs" -> p{library_dirs = happy_var_3}+ "hs_libraries" -> p{hs_libraries = happy_var_3}+ "extra_libraries" -> p{extra_libraries = happy_var_3}+ "include_dirs" -> p{include_dirs = happy_var_3}+ "c_includes" -> p{c_includes = happy_var_3}+ "package_deps" -> p{package_deps = happy_var_3}+ "extra_ghc_opts" -> p{extra_ghc_opts = happy_var_3}+ "extra_cc_opts" -> p{extra_cc_opts = happy_var_3}+ "extra_ld_opts" -> p{extra_ld_opts = happy_var_3}+ "framework_dirs" -> p{framework_dirs = happy_var_3}+ "extra_frameworks"-> p{extra_frameworks= happy_var_3}+ _other -> p+ )}}++happyReduce_12 = happySpecReduce_2 5# happyReduction_12+happyReduction_12 happy_x_2+ happy_x_1+ = happyIn10+ ([]+ )++happyReduce_13 = happySpecReduce_3 5# happyReduction_13+happyReduction_13 happy_x_3+ happy_x_2+ happy_x_1+ = case happyOut11 happy_x_2 of { happy_var_2 -> + happyIn10+ (reverse happy_var_2+ )}++happyReduce_14 = happySpecReduce_1 6# happyReduction_14+happyReduction_14 happy_x_1+ = case happyOutTok happy_x_1 of { (ITstring happy_var_1) -> + happyIn11+ ([ happy_var_1 ]+ )}++happyReduce_15 = happySpecReduce_3 6# happyReduction_15+happyReduction_15 happy_x_3+ happy_x_2+ happy_x_1+ = case happyOut11 happy_x_1 of { happy_var_1 -> + case happyOutTok happy_x_3 of { (ITstring happy_var_3) -> + happyIn11+ (happy_var_3 : happy_var_1+ )}}++happyReduce_16 = happySpecReduce_1 7# happyReduction_16+happyReduction_16 happy_x_1+ = case happyOutTok happy_x_1 of { (ITconid happy_var_1) -> + happyIn12+ ( case happy_var_1 of {+ "True" -> True;+ "False" -> False;+ _ -> error ("unknown constructor in config file: " ++ happy_var_1) }+ )}++happyNewToken action sts stk [] =+ happyDoAction 10# (error "reading EOF!") action sts stk []++happyNewToken action sts stk (tk:tks) =+ let cont i = happyDoAction i tk action sts stk tks in+ case tk of {+ ITocurly -> cont 1#;+ ITccurly -> cont 2#;+ ITobrack -> cont 3#;+ ITcbrack -> cont 4#;+ ITcomma -> cont 5#;+ ITequal -> cont 6#;+ ITvarid happy_dollar_dollar -> cont 7#;+ ITconid happy_dollar_dollar -> cont 8#;+ ITstring happy_dollar_dollar -> cont 9#;+ _ -> happyError' (tk:tks)+ }++happyError_ tk tks = happyError' (tk:tks)++newtype HappyIdentity a = HappyIdentity a+happyIdentity = HappyIdentity+happyRunIdentity (HappyIdentity a) = a++instance Monad HappyIdentity where+ return = HappyIdentity+ (HappyIdentity p) >>= q = q p++happyThen :: () => HappyIdentity a -> (a -> HappyIdentity b) -> HappyIdentity b+happyThen = (>>=)+happyReturn :: () => a -> HappyIdentity a+happyReturn = (return)+happyThen1 m k tks = (>>=) m (\a -> k a tks)+happyReturn1 :: () => a -> b -> HappyIdentity a+happyReturn1 = \a tks -> (return) a+happyError' :: () => [Token] -> HappyIdentity a+happyError' = HappyIdentity . happyError++parse tks = happyRunIdentity happySomeParser where+ happySomeParser = happyThen (happyParse 0# tks) (\x -> happyReturn (happyOut5 x))++parseOne tks = happyRunIdentity happySomeParser where+ happySomeParser = happyThen (happyParse 1# tks) (\x -> happyReturn (happyOut7 x))++happySeq = happyDontSeq++data Token + = ITocurly+ | ITccurly+ | ITobrack+ | ITcbrack+ | ITcomma+ | ITequal+ | ITvarid String+ | ITconid String+ | ITstring String++lexer :: String -> [Token]++lexer [] = []+lexer ('{':cs) = ITocurly : lexer cs+lexer ('}':cs) = ITccurly : lexer cs+lexer ('[':cs) = ITobrack : lexer cs+lexer (']':cs) = ITcbrack : lexer cs+lexer (',':cs) = ITcomma : lexer cs+lexer ('=':cs) = ITequal : lexer cs+lexer ('"':cs) = lexString cs ""+lexer (c:cs)+ | isSpace c = lexer cs+ | isAlpha c = lexID (c:cs) where+lexer _ = error "Unexpected token"++lexID cs = (if isUpper (head cs) then ITconid else ITvarid) id : lexer rest+ where+ (id,rest) = break (\c -> c /= '_' && not (isAlphaNum c)) cs++lexString ('"':cs) s = ITstring (reverse s) : lexer cs+lexString ('\\':c:cs) s = lexString cs (c:s)+lexString (c:cs) s = lexString cs (c:s)++happyError _ = error "Couldn't parse package configuration."++parsePkgConf :: String -> [PackageConfig]+parsePkgConf = parse . lexer++parseOnePkgConf :: String -> PackageConfig+parseOnePkgConf = parseOne . lexer+{-# LINE 1 "GenericTemplate.hs" #-}+{-# LINE 1 "<built-in>" #-}+{-# LINE 1 "<command line>" #-}+{-# LINE 1 "GenericTemplate.hs" #-}+-- $Id$+++{-# LINE 28 "GenericTemplate.hs" #-}+++data Happy_IntList = HappyCons Int# Happy_IntList+++++++{-# LINE 49 "GenericTemplate.hs" #-}+++{-# LINE 59 "GenericTemplate.hs" #-}+++++++++++infixr 9 `HappyStk`+data HappyStk a = HappyStk a (HappyStk a)++-----------------------------------------------------------------------------+-- starting the parse++happyParse start_state = happyNewToken start_state notHappyAtAll notHappyAtAll++-----------------------------------------------------------------------------+-- Accepting the parse++-- If the current token is 0#, it means we've just accepted a partial+-- parse (a %partial parser). We must ignore the saved token on the top of+-- the stack in this case.+happyAccept 0# tk st sts (_ `HappyStk` ans `HappyStk` _) =+ happyReturn1 ans+happyAccept j tk st sts (HappyStk ans _) = + (happyTcHack j (happyTcHack st)) (happyReturn1 ans)++-----------------------------------------------------------------------------+-- Arrays only: do the next action++++happyDoAction i tk st+ = {- nothing -}+++ case action of+ 0# -> {- nothing -}+ happyFail i tk st+ -1# -> {- nothing -}+ happyAccept i tk st+ n | (n <# (0# :: Int#)) -> {- nothing -}++ (happyReduceArr ! rule) i tk st+ where rule = (I# ((negateInt# ((n +# (1# :: Int#))))))+ n -> {- nothing -}+++ happyShift new_state i tk st+ where new_state = (n -# (1# :: Int#))+ where off = indexShortOffAddr happyActOffsets st+ off_i = (off +# i)+ check = if (off_i >=# (0# :: Int#))+ then (indexShortOffAddr happyCheck off_i ==# i)+ else False+ action | check = indexShortOffAddr happyTable off_i+ | otherwise = indexShortOffAddr happyDefActions st++++++++++++indexShortOffAddr (HappyA# arr) off =+#if __GLASGOW_HASKELL__ > 500+ narrow16Int# i+#elif __GLASGOW_HASKELL__ == 500+ intToInt16# i+#else+ (i `iShiftL#` 16#) `iShiftRA#` 16#+#endif+ where+#if __GLASGOW_HASKELL__ >= 503+ i = word2Int# ((high `uncheckedShiftL#` 8#) `or#` low)+#else+ i = word2Int# ((high `shiftL#` 8#) `or#` low)+#endif+ high = int2Word# (ord# (indexCharOffAddr# arr (off' +# 1#)))+ low = int2Word# (ord# (indexCharOffAddr# arr off'))+ off' = off *# 2#++++++data HappyAddr = HappyA# Addr#+++++-----------------------------------------------------------------------------+-- HappyState data type (not arrays)++{-# LINE 170 "GenericTemplate.hs" #-}++-----------------------------------------------------------------------------+-- Shifting a token++happyShift new_state 0# tk st sts stk@(x `HappyStk` _) =+ let i = (case unsafeCoerce# x of { (I# (i)) -> i }) in+-- trace "shifting the error token" $+ happyDoAction i tk new_state (HappyCons (st) (sts)) (stk)++happyShift new_state i tk st sts stk =+ happyNewToken new_state (HappyCons (st) (sts)) ((happyInTok (tk))`HappyStk`stk)++-- happyReduce is specialised for the common cases.++happySpecReduce_0 i fn 0# tk st sts stk+ = happyFail 0# tk st sts stk+happySpecReduce_0 nt fn j tk st@((action)) sts stk+ = happyGoto nt j tk st (HappyCons (st) (sts)) (fn `HappyStk` stk)++happySpecReduce_1 i fn 0# tk st sts stk+ = happyFail 0# tk st sts stk+happySpecReduce_1 nt fn j tk _ sts@((HappyCons (st@(action)) (_))) (v1`HappyStk`stk')+ = let r = fn v1 in+ happySeq r (happyGoto nt j tk st sts (r `HappyStk` stk'))++happySpecReduce_2 i fn 0# tk st sts stk+ = happyFail 0# tk st sts stk+happySpecReduce_2 nt fn j tk _ (HappyCons (_) (sts@((HappyCons (st@(action)) (_))))) (v1`HappyStk`v2`HappyStk`stk')+ = let r = fn v1 v2 in+ happySeq r (happyGoto nt j tk st sts (r `HappyStk` stk'))++happySpecReduce_3 i fn 0# tk st sts stk+ = happyFail 0# tk st sts stk+happySpecReduce_3 nt fn j tk _ (HappyCons (_) ((HappyCons (_) (sts@((HappyCons (st@(action)) (_))))))) (v1`HappyStk`v2`HappyStk`v3`HappyStk`stk')+ = let r = fn v1 v2 v3 in+ happySeq r (happyGoto nt j tk st sts (r `HappyStk` stk'))++happyReduce k i fn 0# tk st sts stk+ = happyFail 0# tk st sts stk+happyReduce k nt fn j tk st sts stk+ = case happyDrop (k -# (1# :: Int#)) sts of+ sts1@((HappyCons (st1@(action)) (_))) ->+ let r = fn stk in -- it doesn't hurt to always seq here...+ happyDoSeq r (happyGoto nt j tk st1 sts1 r)++happyMonadReduce k nt fn 0# tk st sts stk+ = happyFail 0# tk st sts stk+happyMonadReduce k nt fn j tk st sts stk =+ happyThen1 (fn stk) (\r -> happyGoto nt j tk st1 sts1 (r `HappyStk` drop_stk))+ where sts1@((HappyCons (st1@(action)) (_))) = happyDrop k (HappyCons (st) (sts))+ drop_stk = happyDropStk k stk++happyDrop 0# l = l+happyDrop n (HappyCons (_) (t)) = happyDrop (n -# (1# :: Int#)) t++happyDropStk 0# l = l+happyDropStk n (x `HappyStk` xs) = happyDropStk (n -# (1#::Int#)) xs++-----------------------------------------------------------------------------+-- Moving to a new state after a reduction+++happyGoto nt j tk st = + {- nothing -}+ happyDoAction j tk new_state+ where off = indexShortOffAddr happyGotoOffsets st+ off_i = (off +# nt)+ new_state = indexShortOffAddr happyTable off_i+++++-----------------------------------------------------------------------------+-- Error recovery (0# is the error token)++-- parse error if we are in recovery and we fail again+happyFail 0# tk old_st _ stk =+-- trace "failing" $ + happyError_ tk++{- We don't need state discarding for our restricted implementation of+ "error". In fact, it can cause some bogus parses, so I've disabled it+ for now --SDM++-- discard a state+happyFail 0# tk old_st (HappyCons ((action)) (sts)) + (saved_tok `HappyStk` _ `HappyStk` stk) =+-- trace ("discarding state, depth " ++ show (length stk)) $+ happyDoAction 0# tk action sts ((saved_tok`HappyStk`stk))+-}++-- Enter error recovery: generate an error token,+-- save the old token and carry on.+happyFail i tk (action) sts stk =+-- trace "entering error recovery" $+ happyDoAction 0# tk action sts ( (unsafeCoerce# (I# (i))) `HappyStk` stk)++-- Internal happy errors:++notHappyAtAll = error "Internal Happy error\n"++-----------------------------------------------------------------------------+-- Hack to get the typechecker to accept our action functions+++happyTcHack :: Int# -> a -> a+happyTcHack x y = y+{-# INLINE happyTcHack #-}+++-----------------------------------------------------------------------------+-- Seq-ing. If the --strict flag is given, then Happy emits +-- happySeq = happyDoSeq+-- otherwise it emits+-- happySeq = happyDontSeq++happyDoSeq, happyDontSeq :: a -> b -> b+happyDoSeq a b = a `seq` b+happyDontSeq a b = b++-----------------------------------------------------------------------------+-- Don't inline any functions from the template. GHC has a nasty habit+-- of deciding to inline happyGoto everywhere, which increases the size of+-- the generated parser quite a bit.+++{-# NOINLINE happyDoAction #-}+{-# NOINLINE happyTable #-}+{-# NOINLINE happyCheck #-}+{-# NOINLINE happyActOffsets #-}+{-# NOINLINE happyGotoOffsets #-}+{-# NOINLINE happyDefActions #-}++{-# NOINLINE happyShift #-}+{-# NOINLINE happySpecReduce_0 #-}+{-# NOINLINE happySpecReduce_1 #-}+{-# NOINLINE happySpecReduce_2 #-}+{-# NOINLINE happySpecReduce_3 #-}+{-# NOINLINE happyReduce #-}+{-# NOINLINE happyMonadReduce #-}+{-# NOINLINE happyGoto #-}+{-# NOINLINE happyFail #-}++-- end of Happy Template.
+ src/System/Plugins/ParsePkgConfLite.y view
@@ -0,0 +1,159 @@+-- +-- Copyright (C) 2004 Sean Seefried - http://www.cse.unsw.edu.au/~sseefried+-- +-- This library is free software; you can redistribute it and/or+-- modify it under the terms of the GNU Lesser General Public+-- License as published by the Free Software Foundation; either+-- version 2.1 of the License, or (at your option) any later version.+-- +-- This library is distributed in the hope that it will be useful,+-- but WITHOUT ANY WARRANTY; without even the implied warranty of+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU+-- Lesser General Public License for more details.+-- +-- You should have received a copy of the GNU Lesser General Public+-- License along with this library; if not, write to the Free Software+-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307+-- USA+-- ++-- +-- Taken (apart from the most minor of alterations) from +-- ghc/utils/ghc-pkg/ParsePkgConfLite.hs:+--+-- (c) Copyright 2002, The University Court of the University of Glasgow. +--++{++{-# OPTIONS -w #-}++module System.Plugins.ParsePkgConfLite ( + parsePkgConf, parseOnePkgConf+ ) where++import System.Plugins.Package ( PackageConfig(..), defaultPackageConfig )++import Char ( isSpace, isAlpha, isAlphaNum, isUpper )+import List ( break )++}++%token+ '{' { ITocurly }+ '}' { ITccurly }+ '[' { ITobrack }+ ']' { ITcbrack }+ ',' { ITcomma }+ '=' { ITequal }+ VARID { ITvarid $$ }+ CONID { ITconid $$ }+ STRING { ITstring $$ }++%name parse pkgconf+%name parseOne pkg+%tokentype { Token }+%%++pkgconf :: { [ PackageConfig ] }+ : '[' ']' { [] }+ | '[' pkgs ']' { reverse $2 }++pkgs :: { [ PackageConfig ] }+ : pkg { [ $1 ] }+ | pkgs ',' pkg { $3 : $1 }++pkg :: { PackageConfig }+ : CONID '{' fields '}' { $3 defaultPackageConfig }++fields :: { PackageConfig -> PackageConfig }+ : field { \p -> $1 p }+ | fields ',' field { \p -> $1 ($3 p) }++field :: { PackageConfig -> PackageConfig }+ : VARID '=' STRING + {\p -> case $1 of+ "name" -> p{name = $3}+ _ -> error "unknown key in config file" }+ + | VARID '=' bool+ {\p -> case $1 of {+ "auto" -> p{auto = $3};+ _ -> p } }++ | VARID '=' strlist + {\p -> case $1 of+ "import_dirs" -> p{import_dirs = $3}+ "library_dirs" -> p{library_dirs = $3}+ "hs_libraries" -> p{hs_libraries = $3}+ "extra_libraries" -> p{extra_libraries = $3}+ "include_dirs" -> p{include_dirs = $3}+ "c_includes" -> p{c_includes = $3}+ "package_deps" -> p{package_deps = $3}+ "extra_ghc_opts" -> p{extra_ghc_opts = $3}+ "extra_cc_opts" -> p{extra_cc_opts = $3}+ "extra_ld_opts" -> p{extra_ld_opts = $3}+ "framework_dirs" -> p{framework_dirs = $3}+ "extra_frameworks"-> p{extra_frameworks= $3}+ _other -> p+ }++strlist :: { [String] }+ : '[' ']' { [] }+ | '[' strs ']' { reverse $2 }++strs :: { [String] }+ : STRING { [ $1 ] }+ | strs ',' STRING { $3 : $1 }++bool :: { Bool }+ : CONID {% case $1 of {+ "True" -> True;+ "False" -> False;+ _ -> error ("unknown constructor in config file: " ++ $1) } }++{++data Token + = ITocurly+ | ITccurly+ | ITobrack+ | ITcbrack+ | ITcomma+ | ITequal+ | ITvarid String+ | ITconid String+ | ITstring String++lexer :: String -> [Token]++lexer [] = []+lexer ('{':cs) = ITocurly : lexer cs+lexer ('}':cs) = ITccurly : lexer cs+lexer ('[':cs) = ITobrack : lexer cs+lexer (']':cs) = ITcbrack : lexer cs+lexer (',':cs) = ITcomma : lexer cs+lexer ('=':cs) = ITequal : lexer cs+lexer ('"':cs) = lexString cs ""+lexer (c:cs)+ | isSpace c = lexer cs+ | isAlpha c = lexID (c:cs) where+lexer _ = error "Unexpected token"++lexID cs = (if isUpper (head cs) then ITconid else ITvarid) id : lexer rest+ where+ (id,rest) = break (\c -> c /= '_' && not (isAlphaNum c)) cs++lexString ('"':cs) s = ITstring (reverse s) : lexer cs+lexString ('\\':c:cs) s = lexString cs (c:s)+lexString (c:cs) s = lexString cs (c:s)++happyError _ = error "Couldn't parse package configuration."++parsePkgConf :: String -> [PackageConfig]+parsePkgConf = parse . lexer++parseOnePkgConf :: String -> PackageConfig+parseOnePkgConf = parseOne . lexer++}
+ testsuite/README view
@@ -0,0 +1,17 @@+These examples illustrate the various uses of hs-plugins.++conf a configuration file edsl using plugins+dynload dynamically typed load+eval runtime evaluation of haskell strings, from Haskell and C+hmake the 'plugs' haskell interpreter+iface test the interface file parser+load load a plugin+make build a Haskell file+makewith merge and build a Haskell file+multi load multiple plugins at once+objc load Haskell plugins into object C programs+pkgconf test package.conf parsing+popen test popen+reload reload a plugin when it changes+shell a simple string filter+unload test unloading of plugins
+ testsuite/TIMINGS view
@@ -0,0 +1,45 @@+Method:+ * "pdynload" + comes from pdynload/small+ * "load + ghc" + comes from pdynload/null, with lines 13-14+ uncommented from prog/Main.hs+ * "dynload" + from dynload/simple+ * "load, no check"+ from pdynload/null, with lines 13-14 of prog/Main.hs+ commented out++For example, to run the "pdynload" test:+ $ cd pdynload/small+ $ make+ $ make check # to prime caches, etc.+ $ time make check+ $ time make check+ $ time make check # run 'time make check' until value converges++The converged value is entered into the "Raw" timings, and then the+scaled timing is calculated for each machine. These scaled values were+then averaged over the number of machines, yielding the final+"Average" scores -- the average over a number of machines and os.++Raw timing:+pdynload load+ghc dynload load, no check++0.33 0.25 0.22 0.21 -- P4 2.6 , OpenBSD+0.38 0.31 0.29 0.27 -- P4 2.66, Linux+0.84 0.77 0.64 0.55 -- Quad P4 2.4, Linux+0.76 0.60 0.52 0.50 -- AMD 1.1G, Linux+0.95 0.83 0.75 0.72 -- G5 2.0G, Mac OS X+ -- Quad Itanium 1,Linux++Scaled:+1.57 1.19 1.05 1+1.40 1.15 1.07+1.52 1.4 1.16+1.52 1.2 1.04+1.32 1.15 1.04++Average:+=1.46 = 1.218 = 1.07+
+ testsuite/build.mk view
@@ -0,0 +1,40 @@+# how to build the default projects++include $(TOP)/config.mk+include $(TOP)/testsuite/check.mk++BIN= prog/Main+OBJ= prog/Main.o+SRC= prog/Main.hs++BINDIR= prog+REALBIN= ./Main++API_OBJ= api/API.o++INCLUDES= -i$(TOP)/testsuite/$(TEST)/api+GHCFLAGS= -Onot -cpp -fglasgow-exts++.SUFFIXES : .o .hs .hi .lhs .hc .s++all: $(BIN)++$(BIN) : $(PRIOR_OBJS) $(API_OBJ) $(SRC) $(EXTRA_OBJS)+ @rm -f $@+ @$(GHC) --make -o $@ $(INCLUDES) $(PKGFLAGS) $(GHCFLAGS) $(EXTRAFLAGS) $(API) $(SRC)++# Standard suffix rules+.o.hi:+ @:+.hs.o:+ @$(GHC) $(INCLUDES) $(PKGFLAGS) $(GHCFLAGS) $(EXTRAFLAGS) -c $<++clean:+ find . -name '*~' -exec rm {} \;+ rm -rf *.{o,hi,dep}+ rm -rf */*.{hi,o,old} */Main+ rm -rf */*core+ rm -rf */*.a+ rm -rf */package.conf+ rm -rf *.a+
+ testsuite/check.mk view
@@ -0,0 +1,24 @@+include $(TOP)/config.mk++check: $(BIN)+ @(cd $(BINDIR) ;\+ expected="expected" ;\+ if [ -f "expected" -o -f "expected.$(GLASGOW_HASKELL)" ] ;\+ then \+ actual_out="/tmp/hs-plugins-actual.out.$$$$" ;\+ diff_out="/tmp/hs-plugins.diff.$$$$" ;\+ $(REALBIN) > $$actual_out 2>&1 || true ;\+ if [ -f "expected.$(GLASGOW_HASKELL)" ] ; then \+ expected="expected.$(GLASGOW_HASKELL)" ;\+ fi ;\+ diff -u $$expected $$actual_out > $$diff_out || true ;\+ if [ -s "$$diff_out" ] ; then \+ echo "failed with:" ;\+ cat "$$diff_out" | sed '1,3d' ;\+ else \+ echo "ok." ;\+ fi ;\+ rm $$actual_out $$diff_out ;\+ else \+ $(REALBIN) 2>&1 || true ;\+ fi)
+ testsuite/conf/simple/Mailrc.conf view
@@ -0,0 +1,11 @@+import System.Directory++resource = mail { +-- editor = do b <- doesFileExist "/usr/bin/emacs"+-- return $ if b then "emacs" else "vi" ,+ editor = do b <- doesFileExist "/bin/sh"+ return "sh",++ attribution = \name -> "Today, "++name++" wrote :"+}+
+ testsuite/conf/simple/Mailrc.stub view
@@ -0,0 +1,28 @@+module Mailrc ( resource ) where++import API++resource :: Interface+resource = mail++++++++++++++++++++++
+ testsuite/conf/simple/Makefile view
@@ -0,0 +1,4 @@+TEST= conf/simple++TOP=../../..+include ../../build.mk
+ testsuite/conf/simple/api/API.hs view
@@ -0,0 +1,27 @@+--+-- the configuration file interface.+--++module API where++data Color = Black | Grey | Green | Cyan | Yellow | Magenta | Red++data Interface = Interface {+ editor :: IO String,+ attribution :: String -> String,+ header_color :: Color,+ colorize :: [String],+ include :: Bool+ }++-- Default settings+mail :: Interface+mail = Interface { + editor = return "vi",++ attribution = (\user -> user ++ " wrote:"),+ header_color = Grey,+ colorize = [],+ include = True+ }+
+ testsuite/conf/simple/prog/Main.hs view
@@ -0,0 +1,22 @@++import System.Plugins+import API++conf = "../Mailrc.conf"+stub = "../Mailrc.stub"+apipath = "../api"++main = do+ status <- makeWith conf stub ["-i"++apipath]+ o <- case status of+ MakeFailure e -> mapM_ putStrLn e >> error "failed"+ MakeSuccess _ o -> return o+ status <- load o [apipath] [] "resource"+ v <- case status of+ LoadFailure err -> mapM_ putStrLn err >> error "no"+ LoadSuccess _ v -> return v+ + user_editor <- editor v+ putStrLn user_editor+ makeCleaner o+
+ testsuite/conf/simple/prog/expected view
@@ -0,0 +1,1 @@+sh
+ testsuite/dynload/io/Makefile view
@@ -0,0 +1,6 @@+TEST=dynload/io++EXTRA_OBJS=TestIO.o++TOP=../../..+include ../../build.mk
+ testsuite/dynload/io/TestIO.hs view
@@ -0,0 +1,86 @@+{-# OPTIONS -fglasgow-exts -cpp #-}+--+-- Copyright (c) 2004 Don Stewart - http://www.cse.unsw.edu.au/~dons+-- LGPL version 2.1 or later (see http://www.gnu.org/copyleft/lesser.html)+--++module TestIO ( resource_dyn ) where++import API+import AltData.Dynamic++import System.IO+import System.Posix.Types ( ProcessID, Fd )+import System.Posix.Process ( forkProcess, executeFile, getProcessID )+import System.Posix.IO ( createPipe, stdInput, + stdOutput, fdToHandle, closeFd, dupTo )++resource_dyn :: Dynamic+resource_dyn = toDyn resource++resource :: TestIO+resource = testio { field = date }+++--+-- call a shell command , returning it's output+--+date :: IO String+date = do (hdl,_,_) <- catch (popen "/bin/date") (\_->error "popen failed")+ hGetLine hdl ++------------------------------------------------------------------------+--+-- my implementation of $val = `cmd`; (if this was perl)+--+-- provide similar functionality to popen(3), +-- along with bidirectional ipc via pipes+-- return's the pid of the child process+--+-- there are two different forkProcess functions. the pre-620 was a+-- unix-fork style function, and the modern function has semantics more+-- like the Awkward-Squad paper. We provide implementations of popen+-- using both versions, depending on which GHC the user wants to try.+-- ++popen :: FilePath -> IO (Handle, Handle, ProcessID)+popen cmd = do+ (pr, pw) <- createPipe+ (cr, cw) <- createPipe ++ -- parent --+ let parent = do closeFd cw+ closeFd pr+ -- child --+ let child = do closeFd pw+ closeFd cr + exec cmd (pr,cw)+ error "exec cmd failed!" -- typing only++-- if the parser front end understood cpp, this would work+-- #if __GLASGOW_HASKELL__ >= 601+ pid <- forkProcess child -- fork child+ parent -- and run parent code+-- #else+-- p <- forkProcess+-- pid <- case p of+-- Just pid -> parent >> return pid+-- Nothing -> child+-- #endif++ hcr <- fdToHandle cr+ hpw <- fdToHandle pw++ return (hcr,hpw,pid)++--+-- execve cmd in the child process, dup'ing the file descriptors passed+-- as arguments to become the child's stdin and stdout.+--+exec :: FilePath -> (Fd,Fd) -> IO ()+exec cmd (pr,cw) = do+ dupTo pr stdInput+ dupTo cw stdOutput+ executeFile cmd False [] Nothing++------------------------------------------------------------------------
+ testsuite/dynload/io/api/API.hs view
@@ -0,0 +1,19 @@+{-# OPTIONS -fglasgow-exts #-}++module API where++import AltData.Typeable++data TestIO = TestIO { + field :: IO String + }++instance Typeable TestIO where+#if __GLASGOW_HASKELL__ >= 603+ typeOf i = mkTyConApp (mkTyCon "API.TestIO") []+#else+ typeOf i = mkAppTy (mkTyCon "API.TestIO") []+#endif++testio :: TestIO+testio = TestIO { field = return "default value" }
+ testsuite/dynload/io/prog/Main.hs view
@@ -0,0 +1,12 @@++import System.Plugins+import API++main = do+ m_v <- dynload "../TestIO.o" ["../api"] + [] "resource_dyn"+ case m_v of+ LoadFailure _ -> error "couldn't compile"+ LoadSuccess _ v -> do + s <- field v+ if s /= [] then print True else print False
+ testsuite/dynload/io/prog/expected view
@@ -0,0 +1,1 @@+True
+ testsuite/dynload/poly/Makefile view
@@ -0,0 +1,4 @@+TEST=dynload/poly+EXTRA_OBJS=Plugin.o+TOP=../../..+include ../../build.mk
+ testsuite/dynload/poly/Plugin.hs view
@@ -0,0 +1,12 @@+module Plugin where++import API+import AltData.Dynamic++my_fun = plugin { + equals = \x y -> (x /= y) -- a strange equals function :)+ }++resource_dyn :: Dynamic+resource_dyn = toDyn my_fun+
+ testsuite/dynload/poly/api/API.hs view
@@ -0,0 +1,24 @@+{-# OPTIONS -cpp #-}++module API where++import AltData.Typeable++data Interface = Interface { + equals :: forall t. Eq t => t -> t -> Bool+ }++--+-- see how it hides the internal type.. but to compile GHC still checks+-- the type.+--+instance Typeable Interface where+#if __GLASGOW_HASKELL__ >= 603+ typeOf i = mkTyConApp (mkTyCon "API.Interface") []+#else+ typeOf i = mkAppTy (mkTyCon "API.Interface") []+#endif++plugin :: Interface+plugin = Interface { equals = (==) }+
+ testsuite/dynload/poly/prog/Main.hs view
@@ -0,0 +1,17 @@+{-# OPTIONS -cpp #-}++#include "../../../../config.h"++import System.Plugins+import API++main = do + m_v <- dynload "../Plugin.o" ["../api"]+ [] + "resource_dyn"+ case m_v of+ LoadFailure _ -> error "didn't compile"+ LoadSuccess _ (Interface eq) -> do+ putStrLn $ show $ 1 `eq` 2+ putStrLn $ show $ 'a' `eq` 'b'+
+ testsuite/dynload/poly/prog/expected view
@@ -0,0 +1,2 @@+True+True
+ testsuite/dynload/should_fail/Makefile view
@@ -0,0 +1,4 @@+TEST= dynload/should_fail+EXTRA_OBJS=Plugin.o+TOP=../../..+include ../../build.mk
+ testsuite/dynload/should_fail/Plugin.hs view
@@ -0,0 +1,12 @@+{-# OPTIONS -fglasgow-exts #-}+module Plugin where++import API+import AltData.Dynamic++v :: Int+v = 0xdeadbeef++resource_dyn :: Dynamic+resource_dyn = toDyn v+
+ testsuite/dynload/should_fail/api/API.hs view
@@ -0,0 +1,20 @@+{-# OPTIONS -fglasgow-exts #-}++module API where++import AltData.Typeable++data Interface = Interface { + function :: String+ }++instance Typeable Interface where+#if __GLASGOW_HASKELL__ >= 603+ typeOf i = mkTyConApp (mkTyCon "API.Interface") []+#else+ typeOf i = mkAppTy (mkTyCon "API.Interface") []+#endif++plugin :: Interface+plugin = Interface { function = "goodbye" }+
+ testsuite/dynload/should_fail/prog/Main.hs view
@@ -0,0 +1,14 @@++import System.Plugins+import API++main = do + m_v <- dynload "../Plugin.o" + ["../api"] + [] + "resource_dyn"++ case m_v of+ LoadFailure _ -> putStrLn "didn't compile"+ LoadSuccess _ v -> putStrLn $ function v+
+ testsuite/dynload/should_fail/prog/expected view
@@ -0,0 +1,4 @@+Couldn't match `API.Interface' against `Int'+ Expected type: API.Interface+ Inferred type: Int+didn't compile
+ testsuite/dynload/should_fail_1/Makefile view
@@ -0,0 +1,4 @@+TEST= dynload/should_fail_1+EXTRA_OBJS=Plugin.o+TOP=../../..+include ../../build.mk
+ testsuite/dynload/should_fail_1/Plugin.hs view
@@ -0,0 +1,15 @@+--+-- trying to be really mean.+--++module Plugin where++import API+import AltData.Dynamic++v :: Int -> Int+v = \x -> 0xdeadbeef++resource_dyn :: Dynamic+resource_dyn = toDyn v+
+ testsuite/dynload/should_fail_1/api/API.hs view
@@ -0,0 +1,20 @@+{-# OPTIONS -fglasgow-exts #-}++module API where++import AltData.Typeable++data Interface = Interface { + function :: String+ }++instance Typeable Interface where+#if __GLASGOW_HASKELL__ >= 603+ typeOf i = mkTyConApp (mkTyCon "API.Interface") []+#else+ typeOf i = mkAppTy (mkTyCon "API.Interface") []+#endif++plugin :: Interface+plugin = Interface { function = "goodbye" }+
+ testsuite/dynload/should_fail_1/prog/Main.hs view
@@ -0,0 +1,11 @@++import System.Plugins+import API++main = do + m_v <- dynload "../Plugin.o" ["../api"] + [] "resource_dyn"+ case m_v of+ LoadFailure _ -> putStrLn "didn't compile"+ LoadSuccess _ v -> putStrLn $ (function v)+
+ testsuite/dynload/should_fail_1/prog/expected view
@@ -0,0 +1,4 @@+Couldn't match `API.Interface' against `Int -> Int'+ Expected type: API.Interface+ Inferred type: Int -> Int+didn't compile
+ testsuite/dynload/should_fail_2/Makefile view
@@ -0,0 +1,4 @@+TEST= dynload/should_fail_2++TOP=../../..+include ../../build.mk
+ testsuite/dynload/should_fail_2/Plugin.in view
@@ -0,0 +1,19 @@+--+-- the plugin doesn't even make the resource_dyn a Dynamic.+--+-- let's hope that makeWith strips out the invalid declarations+--++{-# OPTIONS -fglasgow-exts #-}++module Plugin where++import API+import AltData.Typeable+import GHC.Base++v :: Int+v = 0xdeadbeef++resource_dyn = (typeOf v, unsafeCoerce v)+
+ testsuite/dynload/should_fail_2/Plugin.stub view
@@ -0,0 +1,12 @@+{-# OPTIONS -fglasgow-exts #-}++module Plugin ( resource_dyn ) where++import API+import AltData.Dynamic++resource = plugin++resource_dyn :: Dynamic+resource_dyn = toDyn resource+
+ testsuite/dynload/should_fail_2/api/API.hs view
@@ -0,0 +1,22 @@+{-# OPTIONS -fglasgow-exts #-}++module API where++import AltData.Typeable+import GHC.Base++data Interface = Interface { + function :: String+ }+ +instance Typeable Interface where+#if __GLASGOW_HASKELL__ >= 603+ typeOf i = mkTyConApp (mkTyCon "API.Interface") []+#else+ typeOf i = mkAppTy (mkTyCon "API.Interface") []+#endif++plugin :: Interface+plugin = Interface { function = "goodbye" }++unsafeCoerce = unsafeCoerce#
+ testsuite/dynload/should_fail_2/prog/Main.hs view
@@ -0,0 +1,19 @@++import System.Plugins+import API++conf = "../Plugin.in"+stub = "../Plugin.stub"++main = do + status <- makeWith conf stub ["-i../api", "-i../../../../src/altdata/"]+ case status of+ MakeFailure e -> mapM_ putStrLn e >> putStrLn "failed"+ MakeSuccess _ o -> do {+ ; m_v <- dynload o ["../api"] [] "resource_dyn"+ ; makeCleaner o+ ; case m_v of+ LoadFailure _ -> putStrLn "didn't load"+ LoadSuccess _ v -> putStrLn $ (function v)+ }+
+ testsuite/dynload/should_fail_2/prog/expected view
@@ -0,0 +1,8 @@++../Plugin.in:18:+ Couldn't match `Dynamic' against `(t, t1)'+ Expected type: Dynamic+ Inferred type: (t, t1)+ In the definition of `resource_dyn':+ resource_dyn = (typeOf v, unsafeCoerce v)+failed
+ testsuite/dynload/should_fail_2/prog/expected.604 view
@@ -0,0 +1,7 @@++../Plugin.in:18:15:+ Couldn't match `Dynamic' against `(a, b)'+ Expected type: Dynamic+ Inferred type: (a, b)+ In the definition of `resource_dyn': resource_dyn = (typeOf v, unsafeCoerce v)+failed
+ testsuite/dynload/should_fail_2/prog/expected.605 view
@@ -0,0 +1,7 @@++../Plugin.in:18:15:+ Couldn't match `Dynamic' against `(a, b)'+ Expected type: Dynamic+ Inferred type: (a, b)+ In the definition of `resource_dyn': resource_dyn = (typeOf v, unsafeCoerce v)+failed
+ testsuite/dynload/should_fail_3/Makefile view
@@ -0,0 +1,4 @@+TEST= dynload/should_fail_3++TOP=../../..+include ../../build.mk
+ testsuite/dynload/should_fail_3/Plugin.in view
@@ -0,0 +1,19 @@+--+-- the plugin doesn't even make the resource_dyn a Dynamic.+-- let's hope that makeWith strips out the invalid declarations+--++{-# OPTIONS -fglasgow-exts #-}++module Plugin where++import API++import AltData.Typeable+import GHC.Base++v :: Int+v = 0xdeadbeef++resource_dyn = (typeOf plugin, unsafeCoerce v)+
+ testsuite/dynload/should_fail_3/Plugin.stub view
@@ -0,0 +1,12 @@+{-# OPTIONS -fglasgow-exts #-}++module Plugin ( resource_dyn ) where++import API+import AltData.Dynamic++resource = plugin++resource_dyn :: Dynamic+resource_dyn = toDyn resource+
+ testsuite/dynload/should_fail_3/api/API.hs view
@@ -0,0 +1,22 @@+{-# OPTIONS -cpp -fglasgow-exts #-}++module API where++import AltData.Typeable+import GHC.Base++data Interface = Interface { + function :: String+ }++instance Typeable Interface where+#if __GLASGOW_HASKELL__ >= 603+ typeOf _ = mkTyConApp (mkTyCon "API.Interface") []+#else+ typeOf _ = mkAppTy (mkTyCon "API.Interface") []+#endif++plugin :: Interface+plugin = Interface { function = "goodbye" }++unsafeCoerce = unsafeCoerce#
+ testsuite/dynload/should_fail_3/prog/Main.hs view
@@ -0,0 +1,18 @@++import System.Plugins+import API++conf = "../Plugin.in"+stub = "../Plugin.stub"++main = do + status <- makeWith conf stub ["-i../api", "-i../../../../src/altdata"]+ o <- case status of+ MakeFailure e -> mapM_ putStrLn e >> error "failed"+ MakeSuccess _ o -> return o+ m_v <- dynload o ["../api"] [] "resource_dyn"+ case m_v of+ LoadFailure _ -> error "didn't compile"+ LoadSuccess _ v -> do putStrLn $ (function v)+ makeCleaner o+
+ testsuite/dynload/should_fail_3/prog/expected view
@@ -0,0 +1,9 @@++../Plugin.in:18:+ Couldn't match `Dynamic' against `(t, t1)'+ Expected type: Dynamic+ Inferred type: (t, t1)+ In the definition of `resource_dyn':+ resource_dyn = (typeOf plugin, unsafeCoerce v)++Fail: failed
+ testsuite/dynload/should_fail_3/prog/expected.604 view
@@ -0,0 +1,8 @@++../Plugin.in:18:15:+ Couldn't match `Dynamic' against `(a, b)'+ Expected type: Dynamic+ Inferred type: (a, b)+ In the definition of `resource_dyn':+ resource_dyn = (typeOf plugin, unsafeCoerce v)+a.out: failed
+ testsuite/dynload/should_fail_3/prog/expected.605 view
@@ -0,0 +1,8 @@++../Plugin.in:18:15:+ Couldn't match `Dynamic' against `(a, b)'+ Expected type: Dynamic+ Inferred type: (a, b)+ In the definition of `resource_dyn':+ resource_dyn = (typeOf plugin, unsafeCoerce v)+a.out: failed
+ testsuite/dynload/simple/Makefile view
@@ -0,0 +1,4 @@+TEST=dynload/simple+EXTRA_OBJS=Plugin.o+TOP=../../..+include ../../build.mk
+ testsuite/dynload/simple/Plugin.hs view
@@ -0,0 +1,11 @@+{-# OPTIONS -fglasgow-exts #-}+module Plugin where++import API+import AltData.Dynamic++my_fun = plugin { function = "plugin says \"hello\"" }++resource_dyn :: Dynamic+resource_dyn = toDyn my_fun+
+ testsuite/dynload/simple/api/API.hs view
@@ -0,0 +1,20 @@+{-# OPTIONS -cpp #-}++module API where++import AltData.Typeable++data Interface = Interface { + function :: String+ }++instance Typeable Interface where+#if __GLASGOW_HASKELL__ >= 603+ typeOf i = mkTyConApp (mkTyCon "API.Interface") []+#else+ typeOf i = mkAppTy (mkTyCon "API.Interface") []+#endif++plugin :: Interface+plugin = Interface { function = "goodbye" }+
+ testsuite/dynload/simple/prog/Main.hs view
@@ -0,0 +1,15 @@+{-# OPTIONS -cpp #-}++#include "../../../../config.h"++import System.Plugins+import API++main = do + m_v <- dynload "../Plugin.o" ["../api"]+ []+ "resource_dyn"+ case m_v of+ LoadFailure _ -> error "didn't compile"+ LoadSuccess _ v -> putStrLn $ (function v)+
+ testsuite/dynload/simple/prog/expected view
@@ -0,0 +1,1 @@+plugin says "hello"
+ testsuite/eval.mk view
@@ -0,0 +1,25 @@+include $(TOP)/config.mk+include $(TOP)/testsuite/check.mk++BIN=Main+SRC=Main.hs++BINDIR= "."+REALBIN= ./$(BIN)++.SUFFIXES : .o .hs .hi .lhs .hc .s++all: $(BIN)++$(BIN): $(SRC) $(OBJS)+ @rm -f $@+ @$(GHC) --make -fglasgow-exts $(GHCFLAGS) $(PKGFLAGS) $(EXTRAFLAGS) $(SRC)++# Standard suffix rules+.o.hi:+ @:+.hs.o:+ @$(GHC) $(INCLUDES) $(PKGFLAGS) $(GHCFLAGS) $(EXTRAFLAGS) -c $<++clean: + @rm -rf *.hi *.o *~ $(BIN)
+ testsuite/eval/eval1/Main.hs view
@@ -0,0 +1,5 @@++import System.Eval.Haskell++main = do i <- eval "1 + 6 :: Int" [] :: IO (Maybe Int)+ if isJust i then putStrLn $ show (fromJust i) else return ()
+ testsuite/eval/eval1/Makefile view
@@ -0,0 +1,2 @@+TOP=../../..+include ../../eval.mk
+ testsuite/eval/eval1/expected view
@@ -0,0 +1,1 @@+7
+ testsuite/eval/eval2/Main.hs view
@@ -0,0 +1,6 @@+import System.Eval.Haskell++main = do m_s <- eval "map toUpper \"haskell\"" ["Data.Char"]+ case m_s of+ Nothing -> putStrLn "typechecking failed"+ Just s -> putStrLn s
+ testsuite/eval/eval2/Makefile view
@@ -0,0 +1,2 @@+TOP=../../..+include ../../eval.mk
+ testsuite/eval/eval2/expected view
@@ -0,0 +1,1 @@+HASKELL
+ testsuite/eval/eval3/Main.hs view
@@ -0,0 +1,38 @@+{-# OPTIONS -cpp #-}+--+-- Should evaluate to '3', unless something goes wrong.+--+-- Not so bad to use AltData, as it is already derived for all the basic+-- types. Then, just replace deriving Typeable, with hand-derived+-- instance of Typeable (see hs-plugins/testsuite/eval/eval_fn1/Poly.hs+--+--++#include "../../../config.h"++import System.Eval+import Data.Dynamic++main = do+ a <- return $ toDyn (3::Integer)++ -- so, we try to compile a function that takes a dyn.+ -- looks like with GHC 6.4, we need to make sure the package.confs work:+ m_b <- unsafeEval_ "\\dyn -> fromDyn dyn (7 :: Integer)"+ ["Data.Dynamic"]+ [ ]+ [ ]+ []++ case m_b of + Left s -> mapM_ putStrLn s+ Right b -> putStrLn $ show (b a :: Integer) -- now apply it+ +{-+-- should work, but doesn't. type check fails +-- (due to static vs dynamic typing issue)++ m_b <- unsafeEval_ "\\dyn -> fromMaybe (7 :: Int) (fromDynamic dyn)"+ ["Data.Dynamic","Data.Maybe"] [] []+-}+
+ testsuite/eval/eval3/Makefile view
@@ -0,0 +1,2 @@+TOP=../../..+include ../../eval.mk
+ testsuite/eval/eval3/expected view
@@ -0,0 +1,1 @@+3
+ testsuite/eval/eval_/Main.hs view
@@ -0,0 +1,9 @@++import System.Eval.Haskell++main = do i <- eval_ "Just (7 :: Int)" + ["Data.Maybe"] + ["-fglasgow-exts"] + []+ [] :: IO (Either [String] (Maybe (Maybe Int)))+ print i
+ testsuite/eval/eval_/Makefile view
@@ -0,0 +1,2 @@+TOP=../../..+include ../../eval.mk
+ testsuite/eval/eval_/expected view
@@ -0,0 +1,1 @@+Right (Just (Just 7))
+ testsuite/eval/eval_fn/Main.hs view
@@ -0,0 +1,10 @@+--+-- lambda abstraction!+--+--+-- needs unsafeEval because eval has a broken Dynamic check+--+import System.Eval.Haskell++main = do fn <- unsafeEval "(\\x -> (x,x::Int))" [] :: IO (Maybe (Int -> (Int,Int)))+ when (isJust fn) $ putStrLn $ show $ (fromJust fn) 7
+ testsuite/eval/eval_fn/Makefile view
@@ -0,0 +1,2 @@+TOP=../../..+include ../../eval.mk
+ testsuite/eval/eval_fn/expected view
@@ -0,0 +1,1 @@+(7,7)
+ testsuite/eval/eval_fn1/Main.hs view
@@ -0,0 +1,15 @@+{-# OPTIONS -fglasgow-exts #-}+--+-- polymorphic eval!+--++module Main where++import Poly+import System.Eval.Haskell++main = do m_f <- eval "Fn (\\x y -> x == y)" ["Poly"]+ when (isJust m_f) $ do+ let (Fn f) = fromJust m_f+ putStrLn $ show (f True True)+ putStrLn $ show (f 1 2)
+ testsuite/eval/eval_fn1/Makefile view
@@ -0,0 +1,2 @@+TOP=../../..+include ../../eval.mk
+ testsuite/eval/eval_fn1/Poly.hs view
@@ -0,0 +1,16 @@+{-# OPTIONS -cpp -fglasgow-exts #-} +module Poly where++import AltData.Typeable++data Fn = Fn {fn :: forall t. Eq t => t -> t -> Bool}++--+-- ignore type inside the Fn... is this correct?+--+instance Typeable Fn where+#if __GLASGOW_HASKELL__ >= 603+ typeOf _ = mkTyConApp (mkTyCon "Poly.Fn") []+#else+ typeOf _ = mkAppTy (mkTyCon "Poly.Fn") []+#endif
+ testsuite/eval/eval_fn1/expected view
@@ -0,0 +1,2 @@+True+False
+ testsuite/eval/foreign_eval/Makefile view
@@ -0,0 +1,2 @@+TOP=../../..+include ../../foreign.mk
+ testsuite/eval/foreign_eval/README view
@@ -0,0 +1,1 @@+run a string of Haskell code from a C program.
+ testsuite/eval/foreign_eval/dont_test view
+ testsuite/eval/foreign_eval/expected view
@@ -0,0 +1,1 @@+10946
+ testsuite/eval/foreign_eval/main.c view
@@ -0,0 +1,16 @@+#include <stdio.h>++#include "EvalHaskell.h"++int main(int argc, char *argv[])+{+ int *p;+ hs_init(&argc, &argv);+ p = hs_eval_i("let fibs = 1:1:zipWith (+) fibs (tail fibs) in fibs !! 20 :: Int");+ if (p == NULL)+ printf("failed!\n");+ else+ printf("%d\n",*p);+ hs_exit();+ return 0;+}
+ testsuite/eval/foreign_eval1/Makefile view
@@ -0,0 +1,2 @@+TOP=../../..+include ../../foreign.mk
+ testsuite/eval/foreign_eval1/dont_test view
+ testsuite/eval/foreign_eval1/expected view
@@ -0,0 +1,1 @@+10946
+ testsuite/eval/foreign_eval1/main.c view
@@ -0,0 +1,16 @@+#include <stdio.h>++#include "EvalHaskell.h"++int main(int argc, char *argv[])+{+ char *p;+ hs_init(&argc, &argv);+ p = hs_eval_s("show $ let fibs = 1:1:zipWith (+) fibs (tail fibs) in fibs !! 20");+ if (p == NULL)+ printf("failed!\n");+ else+ printf("%s\n",p);+ hs_exit();+ return 0;+}
+ testsuite/eval/foreign_should_fail/Makefile view
@@ -0,0 +1,2 @@+TOP=../../..+include ../../foreign.mk
+ testsuite/eval/foreign_should_fail/dont_test view
+ testsuite/eval/foreign_should_fail/expected view
@@ -0,0 +1,2 @@+<eval>:1: parse error on input `in'+failed!
+ testsuite/eval/foreign_should_fail/expected.604 view
@@ -0,0 +1,1 @@+failed!
+ testsuite/eval/foreign_should_fail/expected.605 view
@@ -0,0 +1,1 @@+failed!
+ testsuite/eval/foreign_should_fail/main.c view
@@ -0,0 +1,16 @@+#include <stdio.h>++#include "EvalHaskell.h"++int main(int argc, char *argv[])+{+ int *p;+ hs_init(&argc, &argv);+ p = hs_eval_i("show $ case 1 + 2 in{-wrong-} x -> x");+ if (p == NULL)+ printf("failed!\n");+ else+ printf("%d\n",*p);+ hs_exit();+ return 0;+}
+ testsuite/eval/foreign_should_fail_illtyped/Makefile view
@@ -0,0 +1,2 @@+TOP=../../..+include ../../foreign.mk
+ testsuite/eval/foreign_should_fail_illtyped/dont_test view
+ testsuite/eval/foreign_should_fail_illtyped/expected view
@@ -0,0 +1,4 @@+Couldn't match `Int' against `[Char]'+ Expected type: Int+ Inferred type: [Char]+failed!
+ testsuite/eval/foreign_should_fail_illtyped/expected.604 view
@@ -0,0 +1,1 @@+failed!
+ testsuite/eval/foreign_should_fail_illtyped/expected.605 view
@@ -0,0 +1,1 @@+failed!
+ testsuite/eval/foreign_should_fail_illtyped/main.c view
@@ -0,0 +1,16 @@+#include <stdio.h>++#include "EvalHaskell.h"++int main(int argc, char *argv[])+{+ int *p;+ hs_init(&argc, &argv);+ p = hs_eval_i("\"an ill-typed string\"");+ if (p == NULL)+ printf("failed!\n");+ else+ printf("%d\n",*p);+ hs_exit();+ return 0;+}
+ testsuite/eval/unsafeidir/Main.hs view
@@ -0,0 +1,16 @@++import System.Plugins.Make+import System.Eval.Haskell++main = do make "a/Extra.hs" []+ + i <- unsafeEval_ "show (Just (1 + 6 :: Int)) ++ extra" + ["Data.Maybe", "Extra"] + ["-ia"] -- no make flags+ [] -- no package.confs+ ["a"] -- include paths to load from+ :: IO (Either [String] String)+ + case i of+ Right i -> putStrLn $ show i+ Left es -> mapM_ putStrLn es
+ testsuite/eval/unsafeidir/Makefile view
@@ -0,0 +1,2 @@+TOP=../../..+include ../../eval.mk
+ testsuite/eval/unsafeidir/a/Extra.hs view
@@ -0,0 +1,3 @@+module Extra where++extra = "an extra value"
+ testsuite/eval/unsafeidir/expected view
@@ -0,0 +1,1 @@+"Just 7an extra value"
+ testsuite/foreign.mk view
@@ -0,0 +1,22 @@+include $(TOP)/config.mk+include $(TOP)/testsuite/check.mk+++INCLUDES= -I$(TOP)++# compile with GHC to save us setting all the necessary include and+# lib flags. use ghc -v to find out what these are if you wish to go+# via gcc.+BIN=./Main+SRC=main.c++BINDIR= "."+REALBIN= $(BIN)++all: $(BIN)++$(BIN): $(SRC)+ $(GHC) -package plugins $(INCLUDES) $(PKGFLAGS) $(SRC)++clean: + rm -rf *.hi *.o *~ $(BIN)
+ testsuite/hier/hier1/Makefile view
@@ -0,0 +1,8 @@+TEST= hier/hier1++EXTRA_OBJS=Plugin.o+PRIOR_OBJS=Modules/Flags.o+EXTRAFLAGS=++TOP=../../..+include ../../build.mk
+ testsuite/hier/hier1/Modules/Flags.hs view
@@ -0,0 +1,15 @@+--+-- A simple module+--++module Modules.Flags where+++data FlagRec = FlagRec {+ f1 :: Int,+ f2 :: Int+}+++foo :: FlagRec -> Int+foo x = f1 x
+ testsuite/hier/hier1/Modules/Makefile view
@@ -0,0 +1,6 @@++all:+ ghc -O -c Flags.hs++clean:+ rm -f *.hi *.o
+ testsuite/hier/hier1/Plugin.hs view
@@ -0,0 +1,14 @@+--+-- Plugin+--++module Plugin where++import API+import Modules.Flags as Flags+++resource = plugin {+ dbFunc = (\x -> Flags.f1 x)+}+
+ testsuite/hier/hier1/api/API.hs view
@@ -0,0 +1,16 @@+--+-- API for plugin test+--++module API where++import Modules.Flags as Flags++data Interface = Interface {+ dbFunc :: Flags.FlagRec -> Int+}+++plugin :: Interface+plugin = Interface { dbFunc = (\x -> 1) }+
+ testsuite/hier/hier1/prog/Main.hs view
@@ -0,0 +1,21 @@+--+-- Test multiple plugins+--+++module Main where++import System.Plugins+import API+import Modules.Flags as Flags+++rec = Flags.FlagRec { Flags.f1 = 4, Flags.f2 = 10 }+++main = do+ status <- load "../Plugin.o" ["../api",".."] [] "resource"+ case status of+ LoadFailure _ -> error "load failed"+ LoadSuccess _ v -> do let func = dbFunc v+ print (func rec)
+ testsuite/hier/hier1/prog/expected view
@@ -0,0 +1,1 @@+4
+ testsuite/hier/hier2/A/B/C/Module.hs view
@@ -0,0 +1,8 @@+--+-- A simple module+--++module A.B.C.Module where++symbol = "You found me"+
+ testsuite/hier/hier2/A/Makefile view
@@ -0,0 +1,7 @@++all:+ ghc -c B/C/Module.hs+++clean:+ rm -f B/C/*.hi B/C/*.o
+ testsuite/hier/hier2/Makefile view
@@ -0,0 +1,7 @@+TEST= hier/hier2++PRIOR_OBJS=A/B/C/Module.o+EXTRAFLAGS=++TOP=../../..+include ../../build.mk
+ testsuite/hier/hier2/api/API.hs view
@@ -0,0 +1,4 @@+module API where++-- just a dummy for the build system+
+ testsuite/hier/hier2/prog/Main.hs view
@@ -0,0 +1,15 @@+--+-- Test if we can load a module with a hierarchical name from some weird+-- path. Tests our the module name handling in the .hi file parser.+--+++module Main where++import System.Plugins++main = do+ status <- load "../A/B/C/Module.o" [".."] [] "symbol"+ case status of+ LoadFailure ers -> mapM_ putStrLn ers+ LoadSuccess _ v -> print (v :: String)
+ testsuite/hier/hier2/prog/expected view
@@ -0,0 +1,1 @@+"You found me"
+ testsuite/hier/hier3/Main.hs view
@@ -0,0 +1,25 @@+module Main where++import System.Plugins++main = do++ makeAll "One.hs" []++ load2 "Two.o"++ load2 "./Two.o" -- shouldn't load+ load2 "../hier3/Two.o" -- shouldn't load+ load2 "././././Two.o" -- shouldn't load++ -- and this one pulls in "../hier3/Two.o" as a dep+ y <- load "One.o" ["../hier3"] [] "resource"+ case y of+ LoadSuccess _ s -> putStrLn $ "One plugin: " ++ s+ LoadFailure _ -> putStrLn "Failure: y"++load2 f = do+ x <- load f [".", "../hier3", ""] [] "resource" -- depend on One.o+ case x of+ LoadSuccess _ s -> putStrLn $ "Two plugin: " ++ s+ LoadFailure _ -> putStrLn "Failure: x"
+ testsuite/hier/hier3/Makefile view
@@ -0,0 +1,7 @@+TEST= hier/hier3++EXTRA_OBJS=One.o Two.o+EXTRAFLAGS=++TOP=../../..+include ../../eval.mk
+ testsuite/hier/hier3/One.hs view
@@ -0,0 +1,7 @@++module One where++import qualified Two++resource = "This is the sub-plugin of (" ++ Two.resource ++ ")"+
+ testsuite/hier/hier3/Two.hs view
@@ -0,0 +1,4 @@+module Two where++resource = "This is the top plugin"+
+ testsuite/hier/hier3/expected view
@@ -0,0 +1,5 @@+Two plugin: This is the top plugin+Two plugin: This is the top plugin+Two plugin: This is the top plugin+Two plugin: This is the top plugin+One plugin: This is the sub-plugin of (This is the top plugin)
+ testsuite/hier/hier4/A.hs view
@@ -0,0 +1,11 @@++-- now, the question is: is it possible to not depend on a module or+-- package, but nonetheless have an orphan to it? this could cause+-- problems....++module A where++import B++u :: Int+u = undefined
+ testsuite/hier/hier4/B.hs view
@@ -0,0 +1,4 @@+module B where++import C () -- instances, to make available to those who use B+
+ testsuite/hier/hier4/C.hs view
@@ -0,0 +1,12 @@++-- try to construct an orphan module == an instance decl-only module,+-- that uses classes and types not defined in this module++module C (C) where++import D++instance C a => D (T a) where++class C a where+
+ testsuite/hier/hier4/D.hs view
@@ -0,0 +1,6 @@++module D where++class D a where++data T a = T
+ testsuite/hier/hier4/Main.hs view
@@ -0,0 +1,12 @@+module Main where++import System.Plugins++main = do++ makeAll "A.hs" []++ y <- load "A.o" ["."] [] "u"+ case y of+ LoadSuccess _ _ -> putStrLn $ "YES"+ LoadFailure e -> mapM_ putStrLn e
+ testsuite/hier/hier4/Makefile view
@@ -0,0 +1,4 @@+TEST= hier/hier4++TOP=../../..+include ../../eval.mk
+ testsuite/hier/hier4/expected view
@@ -0,0 +1,1 @@+YES
+ testsuite/iface/null/A.hs view
@@ -0,0 +1,1 @@+module A where
+ testsuite/iface/null/B.hs view
@@ -0,0 +1,1 @@+module B where
+ testsuite/iface/null/Main.hs view
@@ -0,0 +1,9 @@+module Main ( main ) where++import Language.Hi.Parser++import A+import B++main = do iface <- readIface "Main.hi"+ putStrLn (showIface iface)
+ testsuite/iface/null/Makefile view
@@ -0,0 +1,2 @@+TOP=../../..+include ../../eval.mk
+ testsuite/iface/null/expected view
@@ -0,0 +1,4 @@+interface "main" Main+module dependencies: A, B+package dependencies: base, plugins-1.0+
+ testsuite/iface/null/expected.604 view
@@ -0,0 +1,5 @@+interface "unknown" Main+module dependencies: A, B+package dependencies: base-1.0, plugins-1.0+import B+import A
+ testsuite/iface/null/expected.605 view
@@ -0,0 +1,5 @@+interface "unknown" Main+module dependencies: A, B+package dependencies: base-1.0, plugins-1.0+import B+import A
+ testsuite/load/io/Makefile view
@@ -0,0 +1,6 @@+TEST= load/io++EXTRA_OBJS=TestIO.o++TOP=../../..+include ../../build.mk
+ testsuite/load/io/TestIO.hs view
@@ -0,0 +1,88 @@+{-# OPTIONS -cpp #-}+--+-- Copyright (c) 2004 Don Stewart - http://www.cse.unsw.edu.au/~dons+-- LGPL version 2.1 or later (see http://www.gnu.org/copyleft/lesser.html)+--++module TestIO ( resource, resource_dyn ) where++import API+import Data.Dynamic++import Distribution.Package+import Language.Haskell.Parser+import Network.HxWeb++import System.IO+import System.Posix.Types ( ProcessID, Fd )+import System.Posix.Process ( forkProcess, executeFile, getProcessID )+import System.Posix.IO ( createPipe, stdInput, + stdOutput, fdToHandle, closeFd, dupTo )++resource = testio { field = date }++resource_dyn :: Dynamic+resource_dyn = toDyn resource++--+-- call a shell command , returning it's output+--+date :: IO String+date = do (hdl,_,_) <- catch (popen "/bin/date") (\_->error "popen failed")+ hGetLine hdl ++------------------------------------------------------------------------+--+-- my implementation of $val = `cmd`; (if this was perl)+--+-- provide similar functionality to popen(3), +-- along with bidirectional ipc via pipes+-- return's the pid of the child process+--+-- there are two different forkProcess functions. the pre-620 was a+-- unix-fork style function, and the modern function has semantics more+-- like the Awkward-Squad paper. We provide implementations of popen+-- using both versions, depending on which GHC the user wants to try.+-- ++popen :: FilePath -> IO (Handle, Handle, ProcessID)+popen cmd = do+ (pr, pw) <- createPipe+ (cr, cw) <- createPipe ++ -- parent --+ let parent = do closeFd cw+ closeFd pr+ -- child --+ let child = do closeFd pw+ closeFd cr + exec cmd (pr,cw)+ error "exec cmd failed!" -- typing only++-- if the parser front end understood cpp, this would work+-- #if __GLASGOW_HASKELL__ >= 601+ pid <- forkProcess child -- fork child+ parent -- and run parent code+-- #else+-- p <- forkProcess+-- pid <- case p of+-- Just pid -> parent >> return pid+-- Nothing -> child+-- #endif++ hcr <- fdToHandle cr+ hpw <- fdToHandle pw++ return (hcr,hpw,pid)++--+-- execve cmd in the child process, dup'ing the file descriptors passed+-- as arguments to become the child's stdin and stdout.+--+exec :: FilePath -> (Fd,Fd) -> IO ()+exec cmd (pr,cw) = do+ dupTo pr stdInput+ dupTo cw stdOutput+ executeFile cmd False [] Nothing++------------------------------------------------------------------------
+ testsuite/load/io/api/API.hs view
@@ -0,0 +1,16 @@+{-# OPTIONS -fglasgow-exts #-}++module API where++import Data.Dynamic++data TestIO = TestIO { + field :: IO String + }+ deriving (Typeable, Show)++instance Show (IO String) where+ show _ = "<<io action>>"++testio :: TestIO+testio = TestIO { field = return "default value" }
+ testsuite/load/io/prog/Main.hs view
@@ -0,0 +1,15 @@+{-# OPTIONS -cpp #-}++#include "../../../../config.h"++import System.Plugins+import API++main :: IO ()+main = do+ m_v <- load "../TestIO.o" ["../api"] [] "resource"+ v <- case m_v of+ LoadFailure _ -> error "load failed"+ LoadSuccess _ v -> return v+ s <- field v+ if null s then print False else print True
+ testsuite/load/io/prog/expected view
@@ -0,0 +1,1 @@+True
+ testsuite/load/load_0/Makefile view
@@ -0,0 +1,6 @@+TEST= load/load_0++EXTRA_OBJS=Test.o++TOP=../../..+include ../../build.mk
+ testsuite/load/load_0/Test.hs view
@@ -0,0 +1,6 @@++module Test where++import API++resource = test { field = "success" }
+ testsuite/load/load_0/api/API.hs view
@@ -0,0 +1,8 @@+module API where++data Test = Test { + field :: String + }++test :: Test+test = Test { field = "default value" }
+ testsuite/load/load_0/prog/Main.hs view
@@ -0,0 +1,11 @@++import System.Plugins+import API++main = do+ m_v <- load_ "../Test.o" ["../api"] "resource"+ v <- case m_v of+ LoadFailure _ -> error "load failed"+ LoadSuccess _ v -> return v+ let s = field v+ print s
+ testsuite/load/load_0/prog/expected view
@@ -0,0 +1,1 @@+"success"
+ testsuite/load/loadpkg/Main.hs view
@@ -0,0 +1,4 @@++import System.Plugins++main = loadPackageWith "posix" []
+ testsuite/load/loadpkg/Makefile view
@@ -0,0 +1,4 @@+TEST= load/loadpkg++TOP=../../..+include ../../eval.mk
+ testsuite/load/loadpkg/expected view
+ testsuite/load/null/Makefile view
@@ -0,0 +1,4 @@+TEST= load/null+EXTRA_OBJS=Null.o+TOP=../../..+include ../../build.mk
+ testsuite/load/null/Null.hs view
@@ -0,0 +1,11 @@+module Null ( resource, resource_dyn ) where++import API+import Data.Dynamic+import Prelude hiding (null)++resource = null++-- ! this has to be special: it can't be overridden by the user.+resource_dyn :: Dynamic+resource_dyn = toDyn resource
+ testsuite/load/null/api/API.hs view
@@ -0,0 +1,12 @@+{-# OPTIONS -fglasgow-exts #-}++module API where++import Data.Dynamic++data Null = Null { a, b :: Int }+ deriving (Typeable, Show)++null :: Null+null = Null { a = 42 , b = 1 }+
+ testsuite/load/null/prog/Main.hs view
@@ -0,0 +1,17 @@+{-# OPTIONS -cpp #-}++#include "../../../../config.h"++import System.Plugins+import API++-- an example where we just want to load an object and run it++main = do + let includes = [TOP ++ "/testsuite/load/null/api"]+ m_v <- load "../Null.o" includes [] "resource"+ v <- case m_v of+ LoadSuccess _ v -> return v+ _ -> error "load failed"+ + putStrLn ( show (a v) )
+ testsuite/load/null/prog/expected view
@@ -0,0 +1,1 @@+42
+ testsuite/load/thiemann0/Makefile view
@@ -0,0 +1,6 @@+TEST= load/thiemann0++#EXTRA_OBJS=Test.o++TOP=../../..+include ../../build.mk
+ testsuite/load/thiemann0/Test.hs view
@@ -0,0 +1,11 @@++-- P.Thiemann reports that 'import Char' leads to undefined symbol for+-- __stginit_Char_.++module Test where++import API+import Char++resource = test { field = map toUpper "success" }+
+ testsuite/load/thiemann0/api/API.hs view
@@ -0,0 +1,8 @@+module API where++data Test = Test { + field :: String + }++test :: Test+test = Test { field = "default value" }
+ testsuite/load/thiemann0/prog/Main.hs view
@@ -0,0 +1,16 @@++import System.Plugins+import API++main = do+ status <- make "../Test.hs" ["-i../api"]+ obj <- case status of+ MakeSuccess _ o -> return o+ MakeFailure e -> mapM_ putStrLn e >> error "failed"++ m_v <- load_ obj ["../api"] "resource"+ v <- case m_v of+ LoadFailure _ -> error "load failed"+ LoadSuccess _ v -> return v+ let s = field v+ print s
+ testsuite/load/thiemann0/prog/expected view
@@ -0,0 +1,1 @@+"SUCCESS"
+ testsuite/load/thiemann2/C.hs view
@@ -0,0 +1,6 @@+module C where++import API+import qualified A++resource = let Test s = A.resource in Test { field = s }
+ testsuite/load/thiemann2/Makefile view
@@ -0,0 +1,6 @@+TEST= load/thiemann2+EXTRAFLAGS+=-iprog++TOP=../../..+include ../../build.mk+
+ testsuite/load/thiemann2/api/API.hs view
@@ -0,0 +1,8 @@+module API where++data Test = Test { + field :: String + }++test :: Test+test = Test { field = "default value" }
+ testsuite/load/thiemann2/prog/A.hs view
@@ -0,0 +1,8 @@+module A where++import API++import qualified B++resource = Test { field = B.resource }+
+ testsuite/load/thiemann2/prog/B.hs view
@@ -0,0 +1,3 @@+module B where++resource = "i'm in b"
+ testsuite/load/thiemann2/prog/Main.hs view
@@ -0,0 +1,20 @@++import System.Plugins+import API++import A++main = do+ -- compile C (A and B are already compiled)+ status <- makeAll "../C.hs" ["-i../api"]+ obj <- case status of+ MakeSuccess _ o -> return o+ MakeFailure e -> mapM_ putStrLn e >> error "failed"++ -- should load C+ m_v <- load_ obj ["../api","."] "resource"+ v <- case m_v of+ LoadFailure _ -> error "load failed"+ LoadSuccess _ v -> return v+ let s = field v+ print s
+ testsuite/load/thiemann2/prog/expected view
@@ -0,0 +1,1 @@+"i'm in b"
+ testsuite/load/unloadpkg/Main.hs view
@@ -0,0 +1,6 @@++import System.Plugins++main = do loadPackage "posix"+ unloadPackage "posix"+ loadPackage "posix"
+ testsuite/load/unloadpkg/Makefile view
@@ -0,0 +1,4 @@+TEST= load/unloadpkg++TOP=../../..+include ../../eval.mk
+ testsuite/load/unloadpkg/expected view
+ testsuite/loadCLib/null/Makefile view
@@ -0,0 +1,4 @@+TEST= loadCLib/null+EXTRA_OBJS=Null.o+TOP=../../..+include ../../build.mk
+ testsuite/loadCLib/null/Null.hs view
@@ -0,0 +1,12 @@+module Null ( resource ) where++import API+import Data.Dynamic+import Prelude hiding (null)+import Graphics.Rendering.OpenGL++resource = null++-- ! this has to be special: it can't be overridden by the user.+resource_dyn :: Dynamic+resource_dyn = toDyn resource
+ testsuite/loadCLib/null/api/API.hs view
@@ -0,0 +1,12 @@+{-# OPTIONS -fglasgow-exts #-}++module API where++import Data.Dynamic++data Null = Null { a, b :: Int }+ deriving (Typeable, Show)++null :: Null+null = Null { a = 42 , b = 1 }+
+ testsuite/loadCLib/null/prog/Main.hs view
@@ -0,0 +1,11 @@++import System.Plugins+import API++-- an example where we just want to load an object and run it++main = do + m_v <- load_ "../Null.o" ["../api",".."] "resource"+ case m_v of+ LoadFailure err -> error (unlines err)+ LoadSuccess m v -> do putStrLn ( show (a v) ) ; unload m
+ testsuite/loadCLib/null/prog/expected view
@@ -0,0 +1,1 @@+42
+ testsuite/make/makeall001/A.hs view
@@ -0,0 +1,3 @@+module A where++a = "a"
+ testsuite/make/makeall001/B.hs view
@@ -0,0 +1,3 @@+module B where++b = "b"
+ testsuite/make/makeall001/C.hs view
@@ -0,0 +1,3 @@+module C where++c = "c"
+ testsuite/make/makeall001/Makefile view
@@ -0,0 +1,3 @@+TEST= make/makeall001+TOP=../../..+include ../../build.mk
+ testsuite/make/makeall001/Tiny.hs view
@@ -0,0 +1,13 @@+module Tiny ( resource ) where++import API++import A+import B+import C++resource = tiny { ++ field = a ++ b ++ c+ +}
+ testsuite/make/makeall001/api/API.hs view
@@ -0,0 +1,13 @@+{-# OPTIONS -fglasgow-exts #-}+-- ^ needed to derive Typeable++module API where++import Data.Dynamic++data Tiny = Tiny { field :: String }+ deriving (Typeable, Show)++tiny :: Tiny+tiny = Tiny { field = "default value" }+
+ testsuite/make/makeall001/prog/Main.hs view
@@ -0,0 +1,18 @@++-- little more complex. use the path to the obj file we get back from+-- 'make'. load() uses this to find the .hi file++import System.Plugins+import API++main = do+ status <- makeAll "../Tiny.hs" ["-i../api"]+ o <- case status of+ MakeSuccess _ o -> return o+ MakeFailure e -> mapM_ putStrLn e >> error "failed"+ m_v <- load o [".."] [] "resource"+ v <- case m_v of+ LoadSuccess _ v -> return v+ _ -> error "load failed"+ putStrLn $ field v +
+ testsuite/make/makeall001/prog/expected view
@@ -0,0 +1,1 @@+abc
+ testsuite/make/null/Makefile view
@@ -0,0 +1,4 @@+TEST= make/null++TOP=../../..+include ../../build.mk
+ testsuite/make/null/Null.hs view
@@ -0,0 +1,11 @@+module Null ( resource, resource_dyn ) where++import API+import Data.Dynamic+import Prelude hiding (null)++resource = null++-- ! this has to be special: it can't be overridden by the user.+resource_dyn :: Dynamic+resource_dyn = toDyn resource
+ testsuite/make/null/api/API.hs view
@@ -0,0 +1,12 @@+{-# OPTIONS -fglasgow-exts #-}++module API where++import Data.Dynamic++data Null = Null { a, b :: Int }+ deriving (Typeable, Show)++null :: Null+null = Null { a = 42 , b = 1 }+
+ testsuite/make/null/prog/Main.hs view
@@ -0,0 +1,13 @@++-- an example where we want to compile and load a file++import System.Plugins+import API++main = do + make "../Null.hs" ["-i../api"]+ m_v <- load "../Null.o" ["../api"] [] "resource"+ v <- case m_v of+ LoadSuccess _ v -> return v+ _ -> error "load failed"+ putStrLn ( show (a v) )
+ testsuite/make/null/prog/expected view
@@ -0,0 +1,1 @@+42
+ testsuite/make/o/Makefile view
@@ -0,0 +1,3 @@+TEST=make/o+TOP =../../..+include ../../build.mk
+ testsuite/make/o/Plugin.hs view
@@ -0,0 +1,7 @@+module Plugin ( resource ) where++import API++resource = plugin { + field = "hello out there"+}
+ testsuite/make/o/api/API.hs view
@@ -0,0 +1,8 @@+module API where++data Interface = Interface {+ field :: String +}++plugin :: Interface+plugin = Interface { field = undefined }
+ testsuite/make/o/prog/Main.hs view
@@ -0,0 +1,28 @@+import System.Plugins+import API++import System.Directory++-- note: the name of the original *source* module is used to find+-- symbols in the *object* file. load works out what the source file+-- name was by looking at the object file name, i.e. it assumes they+-- have the same name. so, if you are going to store objects in a+-- tmpdir, you should make a tmp directory, and store them inside that,+-- rather than mkstemp'ing the name of the object file yourself.+--+-- this should go away once we can read .hi files.++main = do+#if __GLASGOW_HASKELL__ >= 604+ tmpDir <- getTemporaryDirectory+#else+ let tmpDir = "/tmp"+#endif+ make "../Plugin.hs" [ "-i../api", "-o", (tmpDir ++ "/Plugin.o") ]+ m_v <- load (tmpDir ++ "/Plugin.o") ["../api"] [] "resource"+ v <- case m_v of+ LoadSuccess _ v -> return v+ _ -> error "load failed"+ putStrLn $ field v ++ mapM_ removeFile [ (tmpDir ++ "/Plugin.hi"), (tmpDir ++ "/Plugin.o") ]
+ testsuite/make/o/prog/expected view
@@ -0,0 +1,1 @@+hello out there
+ testsuite/make/odir/Makefile view
@@ -0,0 +1,3 @@+TEST= make/odir+TOP=../../..+include ../../build.mk
+ testsuite/make/odir/Plugin.hs view
@@ -0,0 +1,7 @@+module Plugin ( resource ) where++import API++resource = plugin { + field = "hello out there"+}
+ testsuite/make/odir/api/API.hs view
@@ -0,0 +1,8 @@+module API where++data Interface = Interface {+ field :: String +}++plugin :: Interface+plugin = Interface { field = undefined }
+ testsuite/make/odir/prog/Main.hs view
@@ -0,0 +1,21 @@+import System.Plugins+import API+import System.Directory++main = do+#if __GLASGOW_HASKELL__ >= 604+ tmpDir <- getTemporaryDirectory+#else+ let tmpDir = "/tmp"+#endif+ status <- make "../Plugin.hs" [ "-i../api", "-odir", tmpDir ]+ o <- case status of+ MakeSuccess _ o -> return o+ MakeFailure e -> mapM_ putStrLn e >> error "didn't compile"+ m_v <- load o ["../api"] [] "resource"+ v <- case m_v of+ LoadSuccess _ v -> return v+ _ -> error "load failed"+ putStrLn $ field v + mapM_ removeFile [(tmpDir ++ "/Plugin.hi"), (tmpDir ++ "/Plugin.o") ]+
+ testsuite/make/odir/prog/expected view
@@ -0,0 +1,1 @@+hello out there
+ testsuite/make/remake001/Bar.hs view
@@ -0,0 +1,3 @@+module Bar where++bar = undefined
+ testsuite/make/remake001/Foo.hs view
@@ -0,0 +1,3 @@+module Foo where++foo = undefined
+ testsuite/make/remake001/Main.hs view
@@ -0,0 +1,36 @@+--+-- expected output:+-- $ ./a.out +-- True+-- False+-- True+-- False+--++import System.Plugins+import System.Directory+ +main = do+ status <- make "Foo.hs" [] -- should make+ print status++ status <- make "Foo.hs" [] -- shouldn't make+ print status+ + status <- merge "Foo.hs" "Bar.hs"+ case status of+ MergeFailure e -> error $ show e+ MergeSuccess _ _ fp -> do {++ ;status <- make fp [] -- should make+ ;() <- case status of + MakeSuccess c _ -> print c+ MakeFailure e -> error $ show e++ ;status <- make fp [] -- shouldn't make+ ;case status of + MakeSuccess c _ -> print c+ MakeFailure e -> error $ show e+ ;removeFile "Foo.o"+ }+
+ testsuite/make/remake001/Makefile view
@@ -0,0 +1,4 @@+TEST= merge/remake001++TOP=../../..+include ../../eval.mk
+ testsuite/make/remake001/expected view
@@ -0,0 +1,4 @@+MakeSuccess ReComp "Foo.o"+MakeSuccess NotReq "Foo.o"+ReComp+NotReq
+ testsuite/make/remake001_should_fail/Bar.hs view
@@ -0,0 +1,3 @@+module Bar where++bar = undef {- error -}
+ testsuite/make/remake001_should_fail/Foo.hs view
@@ -0,0 +1,3 @@+module Foo where++foo = undefined
+ testsuite/make/remake001_should_fail/Main.hs view
@@ -0,0 +1,31 @@++import System.Plugins++import System.Directory+ +main = do+ status <- make "Foo.hs" [] -- should make+ print status++ status <- make "Foo.hs" [] -- shouldn't make+ print status+ + status <- merge "Foo.hs" "Bar.hs"+ case status of+ MergeFailure e -> error $ show e+ MergeSuccess _ _ fp -> do {++ ;status <- make fp [] -- should make+ ;() <- case status of + MakeSuccess c _ -> print c+ MakeFailure _ -> print "make failure"++ ;status <- make fp [] -- shouldn't make+ ;case status of + MakeSuccess c _ -> print c+ MakeFailure _ -> print "make failure"++ ;removeFile "Foo.o" -- make test deterministic+ }++
+ testsuite/make/remake001_should_fail/Makefile view
@@ -0,0 +1,4 @@+TEST= make/remake001_should_fail++TOP=../../..+include ../../eval.mk
+ testsuite/make/remake001_should_fail/expected view
@@ -0,0 +1,4 @@+MakeSuccess ReComp "Foo.o"+MakeSuccess NotReq "Foo.o"+"make failure"+"make failure"
+ testsuite/make/simple/Makefile view
@@ -0,0 +1,3 @@+TEST= make/simple+TOP=../../..+include ../../build.mk
+ testsuite/make/simple/Tiny.hs view
@@ -0,0 +1,14 @@+module Tiny ( resource, resource_dyn ) where++import API+import Data.Dynamic++resource = tiny { ++ field = "hello strange world"+ +}++resource_dyn :: Dynamic+resource_dyn = toDyn resource+
+ testsuite/make/simple/api/API.hs view
@@ -0,0 +1,13 @@+{-# OPTIONS -fglasgow-exts #-}+-- ^ needed to derive Typeable++module API where++import Data.Dynamic++data Tiny = Tiny { field :: String }+ deriving (Typeable, Show)++tiny :: Tiny+tiny = Tiny { field = "default value" }+
+ testsuite/make/simple/prog/Main.hs view
@@ -0,0 +1,19 @@++-- little more complex. use the path to the obj file we get back from+-- 'make'. load() uses this to find the .hi file++import System.Plugins+import API++main = do+ status <- make "../Tiny.hs" ["-i../api"]+ o <- case status of+ MakeSuccess _ o -> return o+ MakeFailure e -> mapM_ putStrLn e >> error "failed"++ m_v <- load o ["../api"] [] "resource"+ v <- case m_v of+ LoadSuccess _ v -> return v+ _ -> error "load failed"+ putStrLn $ field v +
+ testsuite/make/simple/prog/expected view
@@ -0,0 +1,1 @@+hello strange world
+ testsuite/makewith/global_pragma/Makefile view
@@ -0,0 +1,5 @@++TEST=makewith/global_pragma++TOP=../../..+include ../../build.mk
+ testsuite/makewith/global_pragma/Plugin.hs view
@@ -0,0 +1,17 @@+{-# GLOBALOPTIONS -package mtl #-}++module M ( resource ) where++import API+import System.IO.Unsafe+import System.Process+import System.IO++resource = tiny { field = date }++date :: String+date = unsafePerformIO $ do+ (_,outh,_,proc) <- runInteractiveProcess "echo" ["hello"] Nothing Nothing + waitForProcess proc+ s <- hGetContents outh+ return s
+ testsuite/makewith/global_pragma/api/API.hs view
@@ -0,0 +1,8 @@++module API where++data Tiny = Tiny { field :: String }++tiny :: Tiny+tiny = Tiny { field = "default value" }+
+ testsuite/makewith/global_pragma/prog/Main.hs view
@@ -0,0 +1,19 @@++import System.Plugins+import API++conf = "../Plugin.hs"+apipath = "../api"++main = do+ status <- makeWith conf conf ["-i"++apipath]+ o <- case status of+ MakeFailure e -> mapM_ putStrLn e >> error "compile failed"+ MakeSuccess _ o -> return o+ m_v <- load o [apipath] [] "resource"+ v <- case m_v of+ LoadSuccess _ v -> return v+ LoadFailure ers -> mapM_ putStrLn ers >> error "load failed"+ putStr $ field v + makeCleaner o+
+ testsuite/makewith/global_pragma/prog/expected view
@@ -0,0 +1,1 @@+hello
+ testsuite/makewith/io/Makefile view
@@ -0,0 +1,4 @@+TEST=makewith/io++TOP=../../..+include ../../build.mk
+ testsuite/makewith/io/README view
@@ -0,0 +1,2 @@+An example using IO monad fields in the .conf file.+
+ testsuite/makewith/io/TestIO.stub view
@@ -0,0 +1,10 @@++module TestIO ( resource, resource_dyn ) where++import API+import Data.Dynamic++resource = testio++resource_dyn :: Dynamic+resource_dyn = toDyn resource
+ testsuite/makewith/io/api/API.hs view
@@ -0,0 +1,16 @@+{-# OPTIONS -fglasgow-exts #-}++module API where++import Data.Dynamic++data TestIO = TestIO { + field :: IO String + }+ deriving (Typeable, Show)++instance Show (IO String) where+ show _ = "<<io action>>"++testio :: TestIO+testio = TestIO { field = return "default value" }
+ testsuite/makewith/io/prog/Main.hs view
@@ -0,0 +1,21 @@++import System.Plugins+import API++conf = "../TestIO.conf"+stub = "../TestIO.stub"+apipath = "../api"++main = do+ status <- makeWith conf stub ["-i"++apipath]+ o <- case status of+ MakeFailure e -> mapM_ putStrLn e >> error "failed"+ MakeSuccess _ o -> return o+ m_v <- load o [apipath] [] "resource"+ v <- case m_v of+ LoadSuccess _ v -> return v+ _ -> error "load failed"+ s <- field v++ makeCleaner o+ if null s then print False else print True
+ testsuite/makewith/io/prog/expected view
@@ -0,0 +1,6 @@+merge failed:++parse error in ../TestIO.conf+line: 17, col: 1++Main: failed
+ testsuite/makewith/merge00/Bar.hs view
@@ -0,0 +1,3 @@+module Bar where++resource :: Int
+ testsuite/makewith/merge00/Foo.hs view
@@ -0,0 +1,4 @@+module Foo where++resource :: Integer+resource = 0xBAD
+ testsuite/makewith/merge00/Main.hs view
@@ -0,0 +1,38 @@++import System.Plugins++import System.Directory++a = "Foo.hs" -- uesr code+b = "Bar.hs" -- trusted code. Result is "Bar.o"++main = do+ status <- merge a b + f <- case status of+ MergeFailure e -> error "merge failure"+ MergeSuccess _ _ f -> return f++ status <- merge a b + f' <- case status of+ MergeFailure e -> error "merge failure"+ MergeSuccess ReComp _ f -> error "unnec. merge"+ MergeSuccess NotReq _ f -> return f++ print ( f == f' )++ status <- make f' []+ o <- case status of+ MakeFailure e -> error "make failed"+ MakeSuccess _ o -> return o++ m_v <- load o [] [] "resource"+ v <- case m_v of+ LoadSuccess _ v -> return v+ _ -> error "load failed"+ putStrLn $ show $ (v :: Int)++ removeFile o+ return ()++ makeCleaner f+
+ testsuite/makewith/merge00/Makefile view
@@ -0,0 +1,4 @@+TEST=makewith/merge00++TOP=../../..+include ../../eval.mk
+ testsuite/makewith/merge00/expected view
@@ -0,0 +1,2 @@+True+2989
+ testsuite/makewith/mergeto0/Bar.hs view
@@ -0,0 +1,3 @@+module Bar where++resource :: Int
+ testsuite/makewith/mergeto0/Foo.hs view
@@ -0,0 +1,4 @@+module Foo where++resource :: Integer+resource = 0xBAD
+ testsuite/makewith/mergeto0/Main.hs view
@@ -0,0 +1,37 @@++import System.Plugins++import System.Directory++a = "Foo.hs" -- uesr code+b = "Bar.hs" -- trusted code. Result is "Bar.o"+c = "Out.hs"++main = do+ status <- mergeTo a b c+ f <- case status of+ MergeFailure e -> error "mergeto failure"+ MergeSuccess _ _ f -> return f+ print $ f == c++ status <- mergeTo a b c+ f' <- case status of+ MergeFailure e -> error "mergeto failure"+ MergeSuccess ReComp _ f -> error "unnec. mergeto"+ MergeSuccess NotReq _ f -> return f -- good, not req++ print $ f == f' && f == c++ status <- make f' []+ o <- case status of+ MakeFailure e -> error "make failed"+ MakeSuccess _ o -> return o++ m_v <- load o [] [] "resource"+ v <- case m_v of+ LoadSuccess _ v -> return v+ _ -> error "load failed"+ putStrLn $ show $ (v :: Int)++ makeCleaner c+
+ testsuite/makewith/mergeto0/Makefile view
@@ -0,0 +1,4 @@+TEST=makewith/mergeto0++TOP=../../..+include ../../eval.mk
+ testsuite/makewith/mergeto0/expected view
@@ -0,0 +1,3 @@+True+True+2989
+ testsuite/makewith/module_name/Bar.hs view
@@ -0,0 +1,3 @@+module Bar where++resource :: Int
+ testsuite/makewith/module_name/Foo.hs view
@@ -0,0 +1,4 @@+module Foo where++resource :: Integer+resource = 1
+ testsuite/makewith/module_name/Main.hs view
@@ -0,0 +1,33 @@++import System.Plugins++import System.Directory++a = "Foo.hs" -- uesr code+b = "Bar.hs" -- trusted code. Result is "Bar.o"++main = do+ status <- makeWith a b []+ s <- case status of+ MakeFailure e -> mapM_ putStrLn e >> error "failed"+ MakeSuccess n s -> print n >> return s++ status <- makeWith a b []+ s' <- case status of+ MakeFailure e -> mapM_ putStrLn e >> error "failed"+ MakeSuccess n s -> print n >> return s++ status <- makeWith a b []+ s'' <- case status of+ MakeFailure e -> mapM_ putStrLn e >> error "failed"+ MakeSuccess n s -> print n >> return s++ print $ (s == s') && (s' == s'')++ m_v <- load s [] [] "resource"+ v <- case m_v of+ LoadSuccess _ v -> return v+ _ -> error "load failed"+ putStrLn $ show $ (v :: Int)++ makeCleaner s''
+ testsuite/makewith/module_name/Makefile view
@@ -0,0 +1,4 @@+TEST=makewith/module_name++TOP=../../..+include ../../eval.mk
+ testsuite/makewith/module_name/expected view
@@ -0,0 +1,5 @@+ReComp+NotReq+NotReq+True+1
+ testsuite/makewith/multi_make/Bar.hs view
@@ -0,0 +1,4 @@+module Bar where++resource :: Int+resource = 2
+ testsuite/makewith/multi_make/Foo.hs view
@@ -0,0 +1,4 @@+module Foo where++resource :: Integer+resource = 1
+ testsuite/makewith/multi_make/Main.hs view
@@ -0,0 +1,37 @@++import System.Plugins++import System.Directory++a = "Foo.hs" -- user code+b = "Bar.hs" -- more user code+z = "Stub.hs" -- and a stub++main = do+ status <- makeWith a z []+ s <- case status of+ MakeFailure e -> mapM_ putStrLn e >> error "failed"+ MakeSuccess n s -> print n >> return s++ status <- makeWith b z []+ s' <- case status of+ MakeFailure e -> mapM_ putStrLn e >> error "failed"+ MakeSuccess n s -> print n >> return s++ -- shouldn't need to remerge (a,z)+ status <- makeWith a z []+ t <- case status of+ MakeFailure e -> mapM_ putStrLn e >> error "failed"+ MakeSuccess n s -> print n >> return s++ -- shouldn't need to remerge (b,z)+ status <- makeWith b z []+ t' <- case status of+ MakeFailure e -> mapM_ putStrLn e >> error "failed"+ MakeSuccess n s -> print n >> return s++ print $ s /= s' -- test we got unique modules+ print $ t /= t' -- test we got unique modules++ mapM_ makeCleaner [s,s']+
+ testsuite/makewith/multi_make/Makefile view
@@ -0,0 +1,4 @@+TEST=makewith/multi_make++TOP=../../..+include ../../eval.mk
+ testsuite/makewith/multi_make/Stub.hs view
@@ -0,0 +1,4 @@+module Stub where++resource :: Int+
+ testsuite/makewith/multi_make/expected view
@@ -0,0 +1,6 @@+ReComp+ReComp+NotReq+NotReq+True+True
+ testsuite/makewith/should_fail_0/Makefile view
@@ -0,0 +1,4 @@+TEST=makewith/should_fail_0++TOP=../../..+include ../../build.mk
+ testsuite/makewith/should_fail_0/Plugin.in view
@@ -0,0 +1,3 @@+module Plugin where++resource = 0xBAD :: Int
+ testsuite/makewith/should_fail_0/Plugin.stub view
@@ -0,0 +1,6 @@+module Plugin ( resource ) where++import API++resource :: Interface+resource = plugin
+ testsuite/makewith/should_fail_0/api/API.hs view
@@ -0,0 +1,10 @@++module API where++data Interface = Interface { + function :: String+ }++plugin :: Interface+plugin = Interface { function = "goodbye" }+
+ testsuite/makewith/should_fail_0/prog/Main.hs view
@@ -0,0 +1,19 @@++import System.Plugins+import API++conf = "../Plugin.in"+stub = "../Plugin.stub"++main = do + status <- makeWith conf stub ["-i../api"]+ case status of+ MakeFailure e -> putStrLn "make failed"+ MakeSuccess _ o -> do+ m_v <- load o ["../api"] [] "resource"+ v <- case m_v of+ LoadSuccess _ v -> return v+ _ -> error "load failed"+ putStrLn $ (function v)+ makeCleaner o+
+ testsuite/makewith/should_fail_0/prog/expected view
@@ -0,0 +1,1 @@+make failed
+ testsuite/makewith/tiny/Makefile view
@@ -0,0 +1,5 @@++TEST=makewith/tiny++TOP=../../..+include ../../build.mk
+ testsuite/makewith/tiny/Tiny.conf view
@@ -0,0 +1,8 @@+resource = tiny { ++ field = "hello strange world"+ +}+++
+ testsuite/makewith/tiny/Tiny.stub view
@@ -0,0 +1,31 @@+module Tiny ( resource, resource_dyn ) where++import API+import Data.Dynamic++resource = tiny++resource_dyn :: Dynamic+resource_dyn = toDyn resource++++++++++++++++++++++
+ testsuite/makewith/tiny/api/API.hs view
@@ -0,0 +1,13 @@+{-# OPTIONS -fglasgow-exts #-}+-- ^ needed to derive Typeable++module API where++import Data.Dynamic++data Tiny = Tiny { field :: String }+ deriving (Typeable, Show)++tiny :: Tiny+tiny = Tiny { field = "default value" }+
+ testsuite/makewith/tiny/prog/Main.hs view
@@ -0,0 +1,21 @@++import System.Plugins+import API+import Data.Either++conf = "../Tiny.conf"+stub = "../Tiny.stub"+apipath = "../api"++main = do+ status <- makeWith conf stub ["-i"++apipath]+ o <- case status of+ MakeFailure e -> mapM_ putStrLn e >> error "failed"+ MakeSuccess _ o -> return o+ m_v <- load o [apipath] [] "resource"+ v <- case m_v of+ LoadSuccess _ v -> return v+ _ -> error "load failed"+ putStrLn $ field v + makeCleaner o+
+ testsuite/makewith/tiny/prog/expected view
@@ -0,0 +1,1 @@+hello strange world
+ testsuite/makewith/unsafeio/Makefile view
@@ -0,0 +1,5 @@++TEST=makewith/unsafeio++TOP=../../..+include ../../build.mk
+ testsuite/makewith/unsafeio/README view
@@ -0,0 +1,3 @@+hmm. on 6.3 we need to add 'mtl' to a package dependency, other+HSlang complains of a missing symbol. Is this a bug in the+package.conf for HSlang?
+ testsuite/makewith/unsafeio/Unsafe.stub view
@@ -0,0 +1,13 @@++module Unsafe ( resource, resource_dyn ) where++import API+import Data.Dynamic++resource = unsafe++--+-- special+--+resource_dyn :: Dynamic+resource_dyn = toDyn resource
+ testsuite/makewith/unsafeio/api/API.hs view
@@ -0,0 +1,13 @@+{-# OPTIONS -fglasgow-exts #-}++module API where++import Data.Dynamic++data Unsafe = Unsafe { + field :: String + }+ deriving (Typeable, Show)++unsafe :: Unsafe+unsafe = Unsafe { field = "default value" }
+ testsuite/makewith/unsafeio/prog/Main.hs view
@@ -0,0 +1,20 @@+import System.Plugins+import API+import Data.Either++conf = "../Unsafe.conf"+stub = "../Unsafe.stub"+apipath = "../api"++main = do+ status <- makeWith conf stub ["-i"++apipath]+ o <- case status of+ MakeFailure e -> mapM_ putStrLn e >> error "failed"+ MakeSuccess _ o -> return o+ m_v <- load o [apipath] [] "resource"+ v <- case m_v of+ LoadSuccess _ v -> return v+ _ -> error "load failed"+ let s = field v+ makeCleaner o+ if null s then print False else print True
+ testsuite/makewith/unsafeio/prog/README view
@@ -0,0 +1,8 @@+this is an example of an application that uses the HSConf library to+dynamically load compiled conf files.++We use the .conf file in the parent directory, and communicate with+the plugin via the API in the api_package/ directory.++The plugin is a .o file+The api is a GHC package archive
+ testsuite/makewith/unsafeio/prog/expected view
@@ -0,0 +1,6 @@+merge failed:++parse error in ../Unsafe.conf+line: 13, col: 1++Main: failed
+ testsuite/misc/mkstemps/Main.hs view
@@ -0,0 +1,69 @@+ +import System.MkTemp++import Data.Maybe++import System.IO+import System.Directory++main = do+ createDirectory "t"++ ------------------------------------------------------------------------+ -- Try mkstemp with simple template+ --+ ts <- mapM (\_ -> mkstemp "t/t.X" ) [0..(26+26)] -- 1+26+26 files+ () <- if (not $ all isJust ts)+ then putStrLn $ "mkstemp couldn't create all expected files"+ else putStrLn $ "created "++(show $ length $ catMaybes ts)++" files"+ closeAll ts++ -- next one shouldn't be possible+ t <- mkstemp "t/t.X"+ () <- if (not $ isNothing t)+ then putStrLn $ "shouldn't have been able to create this file"+ else putStrLn $ "correctly ran out of permutations"+ closeAll [t]++ rmAll (t:ts)++ ------------------------------------------------------------------------+ -- Try again with large tmp+ --+ ts <- mapM (\_->do v <- mkstemp "t/t.XXXXXXXXXX" + case v of Just (t,h) -> hClose h >> return v+ _ -> return v ) [1..10000]++ () <- if (not $ all isJust ts)+ then putStrLn $ "mkstemp couldn't create all expected files"+ else putStrLn $ "mkstemp: created "++(show $ length $ catMaybes ts)++" files"+ rmAll ts++ ------------------------------------------------------------------------+ -- test mkstemps+ --+ ts <- mapM (\_->do v <- mkstemps "t/t.XXXXXXXXXX.hs" 3+ case v of Just (t,h) -> hClose h >> return v+ _ -> return v ) [1..2000]+ () <- if (not $ all isJust ts)+ then putStrLn $ "mkstemps couldn't create all expected files"+ else putStrLn $ "mkstemps: created "++(show $ length $ catMaybes ts)++" files"+ rmAll ts++ ------------------------------------------------------------------------+ -- mkdtemp+ --+ ts <- mapM (\_ -> mkdtemp "t/XXXXXXXXXX") [1..2000]+ () <- if (not $ all isJust ts)+ then putStrLn $ "mkdtemp: couldn't create all expected directories"+ else putStrLn $ "mkdtemp: created "++(show $ length $ catMaybes ts)++" directories"+ rmAllDirs ts+ + ------------------------------------------------------------------------++ removeDirectory "t"++ where+ closeAll ts = mapM_ hClose $ map snd $ catMaybes ts+ rmAll ts = mapM_ removeFile $ map fst $ catMaybes ts+ rmAllDirs ts = mapM_ removeDirectory $ catMaybes ts
+ testsuite/misc/mkstemps/Makefile view
@@ -0,0 +1,2 @@+TOP=../../..+include ../../eval.mk
+ testsuite/misc/mkstemps/expected view
@@ -0,0 +1,5 @@+created 53 files+correctly ran out of permutations+mkstemp: created 10000 files+mkstemps: created 2000 files+mkdtemp: created 2000 directories
+ testsuite/multi/3plugins/Makefile view
@@ -0,0 +1,6 @@+TEST= multi/3plugins++EXTRA_OBJS=Plugin1.o Plugin2.o Plugin3.o++TOP=../../..+include ../../build.mk
+ testsuite/multi/3plugins/Plugin1.hs view
@@ -0,0 +1,8 @@+module Plugin1 where++import API+import Data.Char++resource = plugin {+ valueOf = map toUpper+}
+ testsuite/multi/3plugins/Plugin2.hs view
@@ -0,0 +1,9 @@+module Plugin2 where++import API+import Data.Char++resource = plugin {+ valueOf = \s -> show $ map ord s+}+
+ testsuite/multi/3plugins/Plugin3.hs view
@@ -0,0 +1,7 @@+module Plugin3 where++import API++resource = plugin {+ valueOf = reverse+}
+ testsuite/multi/3plugins/api/API.hs view
@@ -0,0 +1,9 @@+module API where++data Interface = Interface { + valueOf :: String -> String +}++plugin :: Interface +plugin = Interface { valueOf = id }+
+ testsuite/multi/3plugins/prog/Main.hs view
@@ -0,0 +1,13 @@+import System.Plugins+import API++main = do+ let plist = ["../Plugin1.o", "../Plugin2.o", "../Plugin3.o"]+ plugins <- mapM (\p -> load p ["../api"] [] "resource") plist+ let functions = map (valueOf . fromLoadSuc) plugins++ -- apply the function from each plugin in turn+ mapM_ (\f -> putStrLn $ f "haskell is for hackers") functions++fromLoadSuc (LoadFailure _) = error "load failed"+fromLoadSuc (LoadSuccess _ v) = v
+ testsuite/multi/3plugins/prog/expected view
@@ -0,0 +1,3 @@+HASKELL IS FOR HACKERS+[104,97,115,107,101,108,108,32,105,115,32,102,111,114,32,104,97,99,107,101,114,115]+srekcah rof si lleksah
+ testsuite/objc/expression_parser/ArithmeticExpressionParser.hs view
@@ -0,0 +1,30 @@+module ArithmeticExpressionParser where++import Text.ParserCombinators.Parsec+import Text.ParserCombinators.Parsec.Expr++resource :: String -> IO String+resource text = do+ parsedText <- mapM parseString (lines text)+ return (unlines parsedText)++parseString s = do+ case (parse expr "" s) of+ Left err -> return ("Error " ++ show err)+ Right num -> return (show num)++expr :: Parser Integer+expr = buildExpressionParser table factor <?> "expression"++table = [ [op "*" (*) AssocLeft, op "/" div AssocLeft]+ , [op "+" (+) AssocLeft, op "-" (-) AssocLeft] ]+ where+ op s f assoc = Infix (do { string s; return f }) assoc++factor = do { char '('; x <- expr; char ')'; return x }+ <|> number+ <?> "simple expression"++number :: Parser Integer+number = do { ds <- many1 digit; return (read ds) } <?> "number"+
+ testsuite/objc/expression_parser/English.lproj/Credits.rtf view
@@ -0,0 +1,29 @@+{\rtf0\ansi{\fonttbl\f0\fswiss Helvetica;}+{\colortbl;\red255\green255\blue255;}+\paperw9840\paperh8400+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural++\f0\b\fs24 \cf0 Engineering:+\b0 \+ Some people\+\++\b Human Interface Design:+\b0 \+ Some other people\+\++\b Testing:+\b0 \+ Hopefully not nobody\+\++\b Documentation:+\b0 \+ Whoever\+\++\b With special thanks to:+\b0 \+ Mom\+}
+ testsuite/objc/expression_parser/English.lproj/InfoPlist.strings view
binary file changed (absent → 568 bytes)
+ testsuite/objc/expression_parser/English.lproj/MainMenu.nib/classes.nib view
@@ -0,0 +1,4 @@+{+ IBClasses = ({CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }); + IBVersion = 1; +}
+ testsuite/objc/expression_parser/English.lproj/MainMenu.nib/info.nib view
@@ -0,0 +1,21 @@+<?xml version="1.0" encoding="UTF-8"?>+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">+<plist version="1.0">+<dict>+ <key>IBDocumentLocation</key>+ <string>116 123 356 240 0 0 1600 1178 </string>+ <key>IBEditorPositions</key>+ <dict>+ <key>29</key>+ <string>117 405 318 44 0 0 1600 1178 </string>+ </dict>+ <key>IBFramework Version</key>+ <string>328.0</string>+ <key>IBOpenObjects</key>+ <array>+ <integer>29</integer>+ </array>+ <key>IBSystem Version</key>+ <string>7B8</string>+</dict>+</plist>
+ testsuite/objc/expression_parser/English.lproj/MainMenu.nib/objects.nib view
binary file changed (absent → 5248 bytes)
+ testsuite/objc/expression_parser/English.lproj/MyDocument.nib/classes.nib view
@@ -0,0 +1,13 @@+{+ IBClasses = (+ {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, + {+ ACTIONS = {chooseParser = id; evaluateExpression = id; }; + CLASS = MyDocument; + LANGUAGE = ObjC; + OUTLETS = {evaluation = id; expressionEntry = id; parser = id; }; + SUPERCLASS = NSDocument; + }+ ); + IBVersion = 1; +}
+ testsuite/objc/expression_parser/English.lproj/MyDocument.nib/info.nib view
@@ -0,0 +1,16 @@+<?xml version="1.0" encoding="UTF-8"?>+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">+<plist version="1.0">+<dict>+ <key>IBDocumentLocation</key>+ <string>79 43 356 240 0 0 1280 832 </string>+ <key>IBFramework Version</key>+ <string>349.0</string>+ <key>IBOpenObjects</key>+ <array>+ <integer>21</integer>+ </array>+ <key>IBSystem Version</key>+ <string>7F44</string>+</dict>+</plist>
+ testsuite/objc/expression_parser/English.lproj/MyDocument.nib/keyedobjects.nib view
binary file changed (absent → 7470 bytes)
+ testsuite/objc/expression_parser/English.lproj/MyDocument.nib/objects.nib view
binary file changed (absent → 2952 bytes)
+ testsuite/objc/expression_parser/Info.plist view
@@ -0,0 +1,47 @@+<?xml version="1.0" encoding="UTF-8"?>+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">+<plist version="1.0">+<dict>+ <key>CFBundleDevelopmentRegion</key>+ <string>English</string>+ <key>CFBundleDocumentTypes</key>+ <array>+ <dict>+ <key>CFBundleTypeExtensions</key>+ <array>+ <string>????</string>+ </array>+ <key>CFBundleTypeIconFile</key>+ <string></string>+ <key>CFBundleTypeName</key>+ <string>DocumentType</string>+ <key>CFBundleTypeOSTypes</key>+ <array>+ <string>????</string>+ </array>+ <key>CFBundleTypeRole</key>+ <string>Editor</string>+ <key>NSDocumentClass</key>+ <string>MyDocument</string>+ </dict>+ </array>+ <key>CFBundleExecutable</key>+ <string>PluginExpressionParser</string>+ <key>CFBundleIconFile</key>+ <string></string>+ <key>CFBundleIdentifier</key>+ <string>com.apple.yourCocoaDocApp</string>+ <key>CFBundleInfoDictionaryVersion</key>+ <string>6.0</string>+ <key>CFBundlePackageType</key>+ <string>APPL</string>+ <key>CFBundleSignature</key>+ <string>????</string>+ <key>CFBundleVersion</key>+ <string>0.1</string>+ <key>NSMainNibFile</key>+ <string>MainMenu</string>+ <key>NSPrincipalClass</key>+ <string>NSApplication</string>+</dict>+</plist>
+ testsuite/objc/expression_parser/KeyValueParser.hs view
@@ -0,0 +1,33 @@+module KeyValueParser where++import Text.ParserCombinators.Parsec++parseKeyValue = do+ key <- parseKey+ char '='+ value <- parseValue+ return (key, value)++parseKey = many1 letter++parseValue =+ do+ openQuote <- char '"' <|> char '\''+ value <- many1 letter+ char openQuote+ return value+ <|>+ do+ value <- many1 letter+ return value++parseString s = do+ case (parse parseKeyValue "" s) of+ Left err -> return ("Error " ++ show err)+ Right (key, value) -> return ("Key: " ++ key ++ ", Value: " ++ value)++resource :: String -> IO String+resource text = do+ parsedText <- mapM parseString (lines text)+ return (unlines parsedText)+
+ testsuite/objc/expression_parser/Makefile view
@@ -0,0 +1,67 @@+APP_DIR = build/PluginExpressionParser.app+APP_CONTENTS_DIR = $(APP_DIR)/Contents+APP_ARCH_EXEC_DIR = $(APP_CONTENTS_DIR)/MacOS+APP_RESOURCES_DIR = $(APP_CONTENTS_DIR)/Resources+EXECUTABLE = $(APP_ARCH_EXEC_DIR)/PluginExpressionParser++OBJECT_FILES = main.o MyDocument.o PluginEvalAux.o+BUILD_OBJECT_FILES = $(addprefix build/,$(OBJECT_FILES)) \+ build/PluginEvalAux_stub.o++HOST = $(shell uname)++ifeq ($(HOST),Darwin)+default: app+else+default: no_app+endif++app: $(APP_CONTENTS_DIR) $(APP_RESOURCES_DIR) $(EXECUTABLE)++#++$(EXECUTABLE): $(APP_ARCH_EXEC_DIR) $(BUILD_OBJECT_FILES)+ ghc \+ -o "$(EXECUTABLE)" \+ -framework Cocoa \+ -package-conf ../../../plugins.conf.inplace \+ -package plugins \+ -no-hs-main \+ $(BUILD_OBJECT_FILES)++build/MyDocument.o: MyDocument.m MyDocument.h+ gcc -c -o "$@" -Wall -I`ghc --print-libdir`/include "$<"++build/main.o: main.m+ gcc -c -o "$@" -Wall -I`ghc --print-libdir`/include "$<"++build/PluginEvalAux.o: PluginEvalAux.hs+ ghc --make \+ -package-conf ../../../plugins.conf.inplace \+ -package plugins \+ -odir build/ \+ -hidir build/ \+ "$<"++#++$(APP_DIR):+ mkdir -p "$@"++$(APP_ARCH_EXEC_DIR): $(APP_DIR)+ mkdir -p "$@"++$(APP_CONTENTS_DIR): $(APP_DIR) Info.plist+ mkdir -p "$(APP_CONTENTS_DIR)"+ cp Info.plist "$@"+ echo -n 'APPL????' > "$@"/PkgInfo++$(APP_RESOURCES_DIR): $(APP_DIR) English.lproj+ mkdir -p "$(APP_RESOURCES_DIR)"+ cp -R English.lproj "$@"++#++clean:+ -rm -rf build *_stub.?+
+ testsuite/objc/expression_parser/MyDocument.h view
@@ -0,0 +1,16 @@+/* MyDocument */++#import <Cocoa/Cocoa.h>++#include "RunHaskell.h"++@interface MyDocument : NSDocument+{+ IBOutlet id evaluation;+ IBOutlet id expressionEntry;+ IBOutlet id parser;+}+- (IBAction)chooseParser:(id)sender;+- (IBAction)evaluateExpression:(id)sender;++@end
+ testsuite/objc/expression_parser/MyDocument.m view
@@ -0,0 +1,52 @@+#import "MyDocument.h"++@implementation MyDocument++- (NSString *)windowNibName {+ return @"MyDocument";+}++- (NSData *)dataRepresentationOfType:(NSString *)type {+ return nil;+}++- (BOOL)loadDataRepresentation:(NSData *)data ofType:(NSString *)type {+ return NO;+}+++- (IBAction)chooseParser:(id)sender+{+ int result;+ NSArray *fileTypes = [NSArray arrayWithObject:@"hs"];+ NSOpenPanel *oPanel = [NSOpenPanel openPanel];+ + result = [oPanel runModalForDirectory:nil file:nil types:fileTypes];+ if (result == NSOKButton)+ {+ NSArray *filesToOpen = [oPanel filenames];+ [parser setStringValue:[filesToOpen objectAtIndex:0]];+ }+}++- (IBAction)evaluateExpression:(id)sender+{+ NSLog(@"evaluateExpression");+ NSString *filePathNSS = [parser stringValue];+ char *filePath = [filePathNSS cString];+ + NSString *expressionNSS = [[expressionEntry textStorage] string];+ char *expression = [expressionNSS cString];+ + NSLog (@"filePath:%s expression:%s", filePath, expression);+ + char *result = evalhaskell_CString(filePath, expression);+ NSString *resultNSS = [NSString stringWithCString:result];+ NSAttributedString *resultNSAS = [[NSAttributedString alloc]+ initWithString:resultNSS+ attributes:nil];+ [[evaluation textStorage] setAttributedString:resultNSAS];++}++@end
+ testsuite/objc/expression_parser/PluginEvalAux.hs view
@@ -0,0 +1,43 @@+{-# OPTIONS -fglasgow-exts -fffi #-}++module PluginEvalAux where++import System.Plugins.Make+import System.Plugins.Load+import System.Plugins.Utils++import Foreign.C+import Control.Exception ( evaluate )+import System.IO+import System.Directory ( renameFile, removeFile )++symbol = "resource"++evalWithStringResult :: FilePath -> String -> IO String+evalWithStringResult srcFile s = do+ status <- make srcFile ["-Onot"]+ case status of+ MakeFailure err -> putStrLn "error occured" >> return (show err)+ MakeSuccess _ obj -> load' obj+ where+ load' obj = do+ loadResult <- load obj [] [] symbol+ case loadResult of+ LoadFailure errs -> putStrLn "load error" >> return (show errs)+ LoadSuccess m (rsrc :: String -> IO String) -> do+ v' <- rsrc s+ unload m+ mapM_ removeFile [ obj, replaceSuffix obj ".hi" ]+ return v'++foreign export ccall evalhaskell_CString :: CString -> CString -> IO CString++evalhaskell_CString :: CString -> CString -> IO CString+evalhaskell_CString filePathCS sCS = do+ s <- peekCString sCS+ filePath <- peekCString filePathCS+ retval <- evalWithStringResult filePath s+ newCString retval++-- vi:sw=2 sts=2+
+ testsuite/objc/expression_parser/PluginExpressionParser.xcode/project.pbxproj view
@@ -0,0 +1,602 @@+// !$*UTF8*$!+{+ archiveVersion = 1;+ classes = {+ };+ objectVersion = 39;+ objects = {+ 089C165FFE840EACC02AAC07 = {+ children = (+ 089C1660FE840EACC02AAC07,+ );+ isa = PBXVariantGroup;+ name = InfoPlist.strings;+ refType = 4;+ sourceTree = "<group>";+ };+ 089C1660FE840EACC02AAC07 = {+ fileEncoding = 10;+ isa = PBXFileReference;+ lastKnownFileType = text.plist.strings;+ name = English;+ path = English.lproj/InfoPlist.strings;+ refType = 4;+ sourceTree = "<group>";+ };+//080+//081+//082+//083+//084+//100+//101+//102+//103+//104+ 1058C7A6FEA54F5311CA2CBB = {+ children = (+ 1058C7A7FEA54F5311CA2CBB,+ );+ isa = PBXGroup;+ name = "Linked Frameworks";+ refType = 4;+ sourceTree = "<group>";+ };+ 1058C7A7FEA54F5311CA2CBB = {+ fallbackIsa = PBXFileReference;+ isa = PBXFrameworkReference;+ lastKnownFileType = wrapper.framework;+ name = Cocoa.framework;+ path = /System/Library/Frameworks/Cocoa.framework;+ refType = 0;+ sourceTree = "<absolute>";+ };+ 1058C7A8FEA54F5311CA2CBB = {+ children = (+ 2A37F4C5FDCFA73011CA2CEA,+ 2A37F4C4FDCFA73011CA2CEA,+ );+ isa = PBXGroup;+ name = "Other Frameworks";+ refType = 4;+ sourceTree = "<group>";+ };+//100+//101+//102+//103+//104+//190+//191+//192+//193+//194+ 19C28FB0FE9D524F11CA2CBB = {+ children = (+ 8D15AC370486D014006FF6A4,+ );+ isa = PBXGroup;+ name = Products;+ refType = 4;+ sourceTree = "<group>";+ };+//190+//191+//192+//193+//194+//2A0+//2A1+//2A2+//2A3+//2A4+ 2A37F4A9FDCFA73011CA2CEA = {+ buildSettings = {+ };+ buildStyles = (+ 4A9504D0FFE6A4CB11CA0CBA,+ 4A9504D1FFE6A4CB11CA0CBA,+ );+ hasScannedForEncodings = 1;+ isa = PBXProject;+ mainGroup = 2A37F4AAFDCFA73011CA2CEA;+ projectDirPath = "";+ targets = (+ 8D15AC270486D014006FF6A4,+ 7B5F81A4067389B000AC9FA4,+ );+ };+ 2A37F4AAFDCFA73011CA2CEA = {+ children = (+ 7B5F81A1067383A700AC9FA4,+ 7B5F81980673839D00AC9FA4,+ 2A37F4ABFDCFA73011CA2CEA,+ 2A37F4AFFDCFA73011CA2CEA,+ 2A37F4B8FDCFA73011CA2CEA,+ 2A37F4C3FDCFA73011CA2CEA,+ 19C28FB0FE9D524F11CA2CBB,+ );+ isa = PBXGroup;+ name = PluginExpressionParser;+ path = "";+ refType = 4;+ sourceTree = "<group>";+ };+ 2A37F4ABFDCFA73011CA2CEA = {+ children = (+ 2A37F4AEFDCFA73011CA2CEA,+ 2A37F4ACFDCFA73011CA2CEA,+ );+ isa = PBXGroup;+ name = Classes;+ path = "";+ refType = 4;+ sourceTree = "<group>";+ };+ 2A37F4ACFDCFA73011CA2CEA = {+ fileEncoding = 30;+ isa = PBXFileReference;+ lastKnownFileType = sourcecode.c.objc;+ path = MyDocument.m;+ refType = 4;+ sourceTree = "<group>";+ };+ 2A37F4AEFDCFA73011CA2CEA = {+ fileEncoding = 30;+ isa = PBXFileReference;+ lastKnownFileType = sourcecode.c.h;+ path = MyDocument.h;+ refType = 4;+ sourceTree = "<group>";+ };+ 2A37F4AFFDCFA73011CA2CEA = {+ children = (+ 7B5F81990673839D00AC9FA4,+ 32DBCF750370BD2300C91783,+ 7B5F819506737AAC00AC9FA4,+ 2A37F4B0FDCFA73011CA2CEA,+ );+ isa = PBXGroup;+ name = "Other Sources";+ path = "";+ refType = 4;+ sourceTree = "<group>";+ };+ 2A37F4B0FDCFA73011CA2CEA = {+ fileEncoding = 30;+ isa = PBXFileReference;+ lastKnownFileType = sourcecode.c.objc;+ path = main.m;+ refType = 4;+ sourceTree = "<group>";+ };+ 2A37F4B4FDCFA73011CA2CEA = {+ children = (+ 2A37F4B5FDCFA73011CA2CEA,+ );+ isa = PBXVariantGroup;+ name = MyDocument.nib;+ path = "";+ refType = 4;+ sourceTree = "<group>";+ };+ 2A37F4B5FDCFA73011CA2CEA = {+ isa = PBXFileReference;+ lastKnownFileType = wrapper.nib;+ name = English;+ path = English.lproj/MyDocument.nib;+ refType = 4;+ sourceTree = "<group>";+ };+ 2A37F4B6FDCFA73011CA2CEA = {+ children = (+ 2A37F4B7FDCFA73011CA2CEA,+ );+ isa = PBXVariantGroup;+ name = MainMenu.nib;+ path = "";+ refType = 4;+ sourceTree = "<group>";+ };+ 2A37F4B7FDCFA73011CA2CEA = {+ isa = PBXFileReference;+ lastKnownFileType = wrapper.nib;+ name = English;+ path = English.lproj/MainMenu.nib;+ refType = 4;+ sourceTree = "<group>";+ };+ 2A37F4B8FDCFA73011CA2CEA = {+ children = (+ 2A37F4B9FDCFA73011CA2CEA,+ 2A37F4B6FDCFA73011CA2CEA,+ 2A37F4B4FDCFA73011CA2CEA,+ 8D15AC360486D014006FF6A4,+ 089C165FFE840EACC02AAC07,+ );+ isa = PBXGroup;+ name = Resources;+ path = "";+ refType = 4;+ sourceTree = "<group>";+ };+ 2A37F4B9FDCFA73011CA2CEA = {+ children = (+ 2A37F4BAFDCFA73011CA2CEA,+ );+ isa = PBXVariantGroup;+ name = Credits.rtf;+ path = "";+ refType = 4;+ sourceTree = "<group>";+ };+ 2A37F4BAFDCFA73011CA2CEA = {+ isa = PBXFileReference;+ lastKnownFileType = text.rtf;+ name = English;+ path = English.lproj/Credits.rtf;+ refType = 4;+ sourceTree = "<group>";+ };+ 2A37F4C3FDCFA73011CA2CEA = {+ children = (+ 1058C7A6FEA54F5311CA2CBB,+ 1058C7A8FEA54F5311CA2CBB,+ );+ isa = PBXGroup;+ name = Frameworks;+ path = "";+ refType = 4;+ sourceTree = "<group>";+ };+ 2A37F4C4FDCFA73011CA2CEA = {+ fallbackIsa = PBXFileReference;+ isa = PBXFrameworkReference;+ lastKnownFileType = wrapper.framework;+ name = AppKit.framework;+ path = /System/Library/Frameworks/AppKit.framework;+ refType = 0;+ sourceTree = "<absolute>";+ };+ 2A37F4C5FDCFA73011CA2CEA = {+ fallbackIsa = PBXFileReference;+ isa = PBXFrameworkReference;+ lastKnownFileType = wrapper.framework;+ name = Foundation.framework;+ path = /System/Library/Frameworks/Foundation.framework;+ refType = 0;+ sourceTree = "<absolute>";+ };+//2A0+//2A1+//2A2+//2A3+//2A4+//320+//321+//322+//323+//324+ 32DBCF750370BD2300C91783 = {+ fileEncoding = 4;+ isa = PBXFileReference;+ lastKnownFileType = sourcecode.c.h;+ path = PluginExpressionParser_Prefix.pch;+ refType = 4;+ sourceTree = "<group>";+ };+//320+//321+//322+//323+//324+//4A0+//4A1+//4A2+//4A3+//4A4+ 4A9504D0FFE6A4CB11CA0CBA = {+ buildRules = (+ );+ buildSettings = {+ COPY_PHASE_STRIP = NO;+ DEBUGGING_SYMBOLS = YES;+ GCC_DYNAMIC_NO_PIC = NO;+ GCC_ENABLE_FIX_AND_CONTINUE = YES;+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;+ GCC_OPTIMIZATION_LEVEL = 0;+ OPTIMIZATION_CFLAGS = "-O0";+ ZERO_LINK = YES;+ };+ isa = PBXBuildStyle;+ name = Development;+ };+ 4A9504D1FFE6A4CB11CA0CBA = {+ buildRules = (+ );+ buildSettings = {+ COPY_PHASE_STRIP = YES;+ GCC_ENABLE_FIX_AND_CONTINUE = NO;+ ZERO_LINK = NO;+ };+ isa = PBXBuildStyle;+ name = Deployment;+ };+//4A0+//4A1+//4A2+//4A3+//4A4+//7B0+//7B1+//7B2+//7B3+//7B4+ 7B5F819506737AAC00AC9FA4 = {+ fileEncoding = 30;+ isa = PBXFileReference;+ lastKnownFileType = sourcecode.c.h;+ path = RunHaskell.h;+ refType = 4;+ sourceTree = "<group>";+ };+ 7B5F819606737AAC00AC9FA4 = {+ fileRef = 7B5F819506737AAC00AC9FA4;+ isa = PBXBuildFile;+ settings = {+ };+ };+ 7B5F81970673839D00AC9FA4 = {+ fileEncoding = 30;+ isa = PBXFileReference;+ lastKnownFileType = sourcecode.haskell;+ path = KeyValueParser.hs;+ refType = 4;+ sourceTree = "<group>";+ };+ 7B5F81980673839D00AC9FA4 = {+ fileEncoding = 30;+ isa = PBXFileReference;+ lastKnownFileType = sourcecode.make;+ path = Makefile;+ refType = 4;+ sourceTree = "<group>";+ };+ 7B5F81990673839D00AC9FA4 = {+ fileEncoding = 30;+ isa = PBXFileReference;+ lastKnownFileType = sourcecode.haskell;+ path = PluginEvalAux.hs;+ refType = 4;+ sourceTree = "<group>";+ };+ 7B5F819A0673839D00AC9FA4 = {+ fileRef = 7B5F81970673839D00AC9FA4;+ isa = PBXBuildFile;+ settings = {+ };+ };+ 7B5F819B0673839D00AC9FA4 = {+ fileRef = 7B5F81980673839D00AC9FA4;+ isa = PBXBuildFile;+ settings = {+ };+ };+ 7B5F819C0673839D00AC9FA4 = {+ fileRef = 7B5F81990673839D00AC9FA4;+ isa = PBXBuildFile;+ settings = {+ };+ };+ 7B5F819D067383A400AC9FA4 = {+ fileEncoding = 30;+ isa = PBXFileReference;+ lastKnownFileType = sourcecode.haskell;+ path = ArithmeticExpressionParser.hs;+ refType = 4;+ sourceTree = "<group>";+ };+ 7B5F819E067383A400AC9FA4 = {+ fileRef = 7B5F819D067383A400AC9FA4;+ isa = PBXBuildFile;+ settings = {+ };+ };+ 7B5F81A1067383A700AC9FA4 = {+ children = (+ 7B5F819D067383A400AC9FA4,+ 7B5F81970673839D00AC9FA4,+ );+ isa = PBXGroup;+ name = Parsers;+ refType = 4;+ sourceTree = "<group>";+ };+ 7B5F81A4067389B000AC9FA4 = {+ buildArgumentsString = "$(ACTION)";+ buildPhases = (+ );+ buildSettings = {+ OPTIMIZATION_CFLAGS = "";+ OTHER_CFLAGS = "";+ OTHER_LDFLAGS = "";+ OTHER_REZFLAGS = "";+ PRODUCT_NAME = "PluginExpressionParser (GNU make)";+ SECTORDER_FLAGS = "";+ WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas";+ };+ buildToolPath = /usr/bin/make;+ dependencies = (+ );+ isa = PBXLegacyTarget;+ name = "PluginExpressionParser (GNU make)";+ passBuildSettingsInEnvironment = 1;+ productName = "PluginExpressionParser (GNU make)";+ };+//7B0+//7B1+//7B2+//7B3+//7B4+//8D0+//8D1+//8D2+//8D3+//8D4+ 8D15AC270486D014006FF6A4 = {+ buildPhases = (+ 8D15AC280486D014006FF6A4,+ 8D15AC2B0486D014006FF6A4,+ 8D15AC300486D014006FF6A4,+ 8D15AC330486D014006FF6A4,+ );+ buildRules = (+ );+ buildSettings = {+ FRAMEWORK_SEARCH_PATHS = "";+ GCC_ENABLE_TRIGRAPHS = NO;+ GCC_GENERATE_DEBUGGING_SYMBOLS = NO;+ GCC_PRECOMPILE_PREFIX_HEADER = YES;+ GCC_PREFIX_HEADER = PluginExpressionParser_Prefix.pch;+ GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO;+ GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;+ GCC_WARN_UNKNOWN_PRAGMAS = NO;+ HEADER_SEARCH_PATHS = "";+ INFOPLIST_FILE = Info.plist;+ INSTALL_PATH = "$(HOME)/Applications";+ LIBRARY_SEARCH_PATHS = "";+ OTHER_CFLAGS = "";+ OTHER_LDFLAGS = "";+ PRODUCT_NAME = PluginExpressionParser;+ SECTORDER_FLAGS = "";+ WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas";+ WRAPPER_EXTENSION = app;+ };+ dependencies = (+ );+ isa = PBXNativeTarget;+ name = PluginExpressionParser;+ productInstallPath = "$(HOME)/Applications";+ productName = PluginExpressionParser;+ productReference = 8D15AC370486D014006FF6A4;+ productType = "com.apple.product-type.application";+ };+ 8D15AC280486D014006FF6A4 = {+ buildActionMask = 2147483647;+ files = (+ 8D15AC290486D014006FF6A4,+ 8D15AC2A0486D014006FF6A4,+ 7B5F819606737AAC00AC9FA4,+ );+ isa = PBXHeadersBuildPhase;+ runOnlyForDeploymentPostprocessing = 0;+ };+ 8D15AC290486D014006FF6A4 = {+ fileRef = 32DBCF750370BD2300C91783;+ isa = PBXBuildFile;+ settings = {+ };+ };+ 8D15AC2A0486D014006FF6A4 = {+ fileRef = 2A37F4AEFDCFA73011CA2CEA;+ isa = PBXBuildFile;+ settings = {+ };+ };+ 8D15AC2B0486D014006FF6A4 = {+ buildActionMask = 2147483647;+ files = (+ 8D15AC2C0486D014006FF6A4,+ 8D15AC2D0486D014006FF6A4,+ 8D15AC2E0486D014006FF6A4,+ 8D15AC2F0486D014006FF6A4,+ 7B5F819A0673839D00AC9FA4,+ 7B5F819B0673839D00AC9FA4,+ 7B5F819C0673839D00AC9FA4,+ 7B5F819E067383A400AC9FA4,+ );+ isa = PBXResourcesBuildPhase;+ runOnlyForDeploymentPostprocessing = 0;+ };+ 8D15AC2C0486D014006FF6A4 = {+ fileRef = 2A37F4B9FDCFA73011CA2CEA;+ isa = PBXBuildFile;+ settings = {+ };+ };+ 8D15AC2D0486D014006FF6A4 = {+ fileRef = 2A37F4B6FDCFA73011CA2CEA;+ isa = PBXBuildFile;+ settings = {+ };+ };+ 8D15AC2E0486D014006FF6A4 = {+ fileRef = 2A37F4B4FDCFA73011CA2CEA;+ isa = PBXBuildFile;+ settings = {+ };+ };+ 8D15AC2F0486D014006FF6A4 = {+ fileRef = 089C165FFE840EACC02AAC07;+ isa = PBXBuildFile;+ settings = {+ };+ };+ 8D15AC300486D014006FF6A4 = {+ buildActionMask = 2147483647;+ files = (+ 8D15AC310486D014006FF6A4,+ 8D15AC320486D014006FF6A4,+ );+ isa = PBXSourcesBuildPhase;+ runOnlyForDeploymentPostprocessing = 0;+ };+ 8D15AC310486D014006FF6A4 = {+ fileRef = 2A37F4ACFDCFA73011CA2CEA;+ isa = PBXBuildFile;+ settings = {+ ATTRIBUTES = (+ );+ };+ };+ 8D15AC320486D014006FF6A4 = {+ fileRef = 2A37F4B0FDCFA73011CA2CEA;+ isa = PBXBuildFile;+ settings = {+ ATTRIBUTES = (+ );+ };+ };+ 8D15AC330486D014006FF6A4 = {+ buildActionMask = 2147483647;+ files = (+ 8D15AC340486D014006FF6A4,+ );+ isa = PBXFrameworksBuildPhase;+ runOnlyForDeploymentPostprocessing = 0;+ };+ 8D15AC340486D014006FF6A4 = {+ fileRef = 1058C7A7FEA54F5311CA2CBB;+ isa = PBXBuildFile;+ settings = {+ };+ };+ 8D15AC360486D014006FF6A4 = {+ fileEncoding = 4;+ isa = PBXFileReference;+ lastKnownFileType = text.plist;+ path = Info.plist;+ refType = 4;+ sourceTree = "<group>";+ };+ 8D15AC370486D014006FF6A4 = {+ explicitFileType = wrapper.application;+ includeInIndex = 0;+ isa = PBXFileReference;+ path = PluginExpressionParser.app;+ refType = 3;+ sourceTree = BUILT_PRODUCTS_DIR;+ };+ };+ rootObject = 2A37F4A9FDCFA73011CA2CEA;+}
+ testsuite/objc/expression_parser/PluginExpressionParser_Prefix.pch view
@@ -0,0 +1,7 @@+//+// Prefix header for all source files of the 'PluginExpressionParser' target in the 'PluginExpressionParser' project+//++#ifdef __OBJC__+ #import <Cocoa/Cocoa.h>+#endif
+ testsuite/objc/expression_parser/README view
@@ -0,0 +1,6 @@+This little application is an example of using hs-plugins to embed a Haskell+'interpreter' inside an Objective-C, Cocoa-based program. You will need Mac OS+X for this to be of any use!++To build it, type 'make', which will build a .app bundle in the build/ directory. Or, 'open *.xcode', and hit the build button in there.+
+ testsuite/objc/expression_parser/RunHaskell.h view
@@ -0,0 +1,4 @@+#include "HsFFI.h"++extern HsPtr evalhaskell_CString(HsPtr a1, HsPtr a2);+
+ testsuite/objc/expression_parser/dont_test view
+ testsuite/objc/expression_parser/main.m view
@@ -0,0 +1,26 @@+//+// main.m+// PluginExpressionParser+//+// Created by Andr Pang on Mon Jun 07 2004.+// Copyright (c) 2004 __MyCompanyName__. All rights reserved.+//++#import <Cocoa/Cocoa.h>++#include "HsFFI.h"++extern void __stginit_PluginEvalAux (void);++int main(int argc, char *argv[])+{+ hs_init(&argc, &argv);+ hs_add_root(__stginit_PluginEvalAux);+ const char *c_argv = (const char *) argv;+ int retval = NSApplicationMain(argc, &c_argv);+ hs_exit();+ return retval;+}++/* vi:sw=4 */+
+ testsuite/objc/expression_parser/version.plist view
@@ -0,0 +1,16 @@+<?xml version="1.0" encoding="UTF-8"?>+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">+<plist version="1.0">+<dict>+ <key>BuildVersion</key>+ <string>17</string>+ <key>CFBundleShortVersionString</key>+ <string>0.1</string>+ <key>CFBundleVersion</key>+ <string>0.1</string>+ <key>ProjectName</key>+ <string>NibPBTemplates</string>+ <key>SourceVersion</key>+ <string>1150000</string>+</dict>+</plist>
+ testsuite/pdynload/badint/Makefile view
@@ -0,0 +1,5 @@++TEST=pdynload/badint++TOP=../../..+include ../../build.mk
+ testsuite/pdynload/badint/Plugin.hs view
@@ -0,0 +1,4 @@+module Plugin where++resource :: Num t => t+resource = 0xBAD
+ testsuite/pdynload/badint/api/API.hs view
@@ -0,0 +1,9 @@+module API where++data Interface = Interface { + transform :: String -> String+ }++rsrc :: Interface+rsrc = Interface { transform = id }+
+ testsuite/pdynload/badint/prog/Main.hs view
@@ -0,0 +1,18 @@++import System.Plugins+import API++src = "../Plugin.hs"+wrap = "../Wrapper.hs"+apipath = "../api"++main = do status <- make src ["-i"++apipath]+ case status of+ MakeSuccess _ _ -> f+ MakeFailure e-> mapM_ putStrLn e+ + where f = do v <- pdynload "../Plugin.o" ["../api"] [] "API.Interface" "resource"+ case v of+ LoadSuccess _ a -> putStrLn $ (transform a) "foo"+ _ -> putStrLn "wrong types"+
+ testsuite/pdynload/badint/prog/expected view
@@ -0,0 +1,1 @@+wrong types
+ testsuite/pdynload/bayley1/Load.hs view
@@ -0,0 +1,42 @@+module Load where++import API+import System.Plugins++--+-- load doesn't seem to behave nicely when using dirname on hier names+--+-- make, and maybe other places, use dirname to work out various names+-- from paths, which is invalid when hier names are used..+--++testload = do++ s <- make "../Plugin1.hs" ["-i../api"]+ o1 <- case s of+ MakeSuccess _ o -> return o+ MakeFailure e -> mapM_ putStrLn e >> fail "o1"+ + s <- make "../Sub/Plugin2.hs" ["-i../api","-hidir.."] -- !+ o2 <- case s of+ MakeSuccess _ o -> return o+ MakeFailure e -> mapM_ putStrLn e >> fail "o2"++ fc <- pdynload o1 ["..","../api"] [] "API.PluginAPI" "action"++ case fc of+ LoadFailure msg -> mapM_ putStrLn msg + LoadSuccess modul proc -> do+ let ac :: API.PluginAPI; ac = proc+ let s = proc 42+ print s++ -- will reqeust 'Plugin2', but module is actually 'Sub.Plugin2'+ print o2+ fc <- pdynload (o2) ["..","../api"] [] "API.PluginAPI" "action"+ case fc of+ LoadFailure msg -> mapM_ putStrLn msg + LoadSuccess modul proc -> do+ let ac :: API.PluginAPI; ac = proc+ let s = proc 42+ print s
+ testsuite/pdynload/bayley1/Makefile view
@@ -0,0 +1,5 @@++TEST=pdynload/bayley1++TOP=../../..+include ../../build.mk
+ testsuite/pdynload/bayley1/Plugin1.hs view
@@ -0,0 +1,6 @@+module Plugin1 where++import qualified API+action :: API.PluginAPI+action i = show i+
+ testsuite/pdynload/bayley1/Sub/Plugin2.hs view
@@ -0,0 +1,6 @@+module Sub.Plugin2 where++import qualified API+action :: API.PluginAPI+action i = show i+
+ testsuite/pdynload/bayley1/api/API.hs view
@@ -0,0 +1,6 @@+module API where++type PluginAPI = Int -> String+action :: PluginAPI+action i = show i+
+ testsuite/pdynload/bayley1/prog/Main.hs view
@@ -0,0 +1,4 @@+module Main where+import Load+main = testload+
+ testsuite/pdynload/null/Makefile view
@@ -0,0 +1,4 @@++TEST= pdynload/null+TOP=../../..+include ../../build.mk
+ testsuite/pdynload/null/Plugin.hs view
@@ -0,0 +1,5 @@+module Plugin where++import API++resource = D 1
+ testsuite/pdynload/null/api/API.hs view
@@ -0,0 +1,5 @@++module API where++data Num t => Interface t = D t+
+ testsuite/pdynload/null/prog/Main.hs view
@@ -0,0 +1,19 @@++import System.Plugins+-- import System.Plugins.Utils+import API++src = "../Plugin.hs"+wrap = "../Wrapper.hs"+apipath = "../api"++main = do status <- make src ["-i"++apipath]+ case status of+ MakeSuccess _ _ -> f+ MakeFailure e-> mapM_ putStrLn e++ where f = do v <- load "../Plugin.o" ["../api"] [] "resource"+ -- (i,_) <- exec "ghc" ["--numeric-version"]+ -- mapM_ putStrLn i+ putStrLn "done."+
+ testsuite/pdynload/null/prog/expected view
@@ -0,0 +1,1 @@+done.
+ testsuite/pdynload/numclass/Makefile view
@@ -0,0 +1,4 @@++TEST= pdynload/numclass+TOP=../../..+include ../../build.mk
+ testsuite/pdynload/numclass/Plugin.hs view
@@ -0,0 +1,5 @@+module Plugin where++-- import API++resource = "error"
+ testsuite/pdynload/numclass/api/API.hs view
@@ -0,0 +1,5 @@++module API where++data Num t => Interface t = D t+
+ testsuite/pdynload/numclass/prog/Main.hs view
@@ -0,0 +1,19 @@++import System.Plugins+import API++src = "../Plugin.hs"+wrap = "../Wrapper.hs"+apipath = "../api"++main = do status <- make src ["-i"++apipath]+ case status of+ MakeFailure _ -> putStrLn "make failed"+ MakeSuccess _ _ -> do {++ ;v <- pdynload "../Plugin.o" ["../api"] [] "API.Interface Integer" "resource"+ ;case v of+ LoadSuccess _ a -> let D i = snd a in putStrLn $ show i+ _ -> putStrLn "wrong types"++ }
+ testsuite/pdynload/numclass/prog/expected view
@@ -0,0 +1,1 @@+wrong types
+ testsuite/pdynload/poly/Makefile view
@@ -0,0 +1,5 @@++TEST=pdynload/poly++TOP=../../..+include ../../build.mk
+ testsuite/pdynload/poly/Plugin.hs view
@@ -0,0 +1,9 @@+module Plugin where++import Data.Generics.Schemes++import API++resource = rsrc { + field = id listify+}
+ testsuite/pdynload/poly/api/API.hs view
@@ -0,0 +1,12 @@+{-# OPTIONS -fglasgow-exts #-}+-- a really nasty type:++module API where++import Data.Generics++data Interface = Interface { field :: Typeable r => (r -> Bool) -> GenericQ [r] }++rsrc :: Interface+rsrc = Interface { field = listify }+
+ testsuite/pdynload/poly/prog/Main.hs view
@@ -0,0 +1,17 @@++import System.Plugins+import API++src = "../Plugin.hs"+wrap = "../Wrapper.hs"+apipath = "../api"++main = do status <- make src ["-i"++apipath]+ case status of+ MakeSuccess _ _ -> f+ MakeFailure e -> mapM_ putStrLn e++ where f = do v <- pdynload "../Plugin.o" ["../api"] [] "API.Interface" "resource"+ case v of+ LoadSuccess _ a -> putStrLn "loaded .. yay!"+ _ -> putStrLn "wrong types"
+ testsuite/pdynload/poly/prog/expected view
@@ -0,0 +1,1 @@+loaded .. yay!
+ testsuite/pdynload/poly1/Makefile view
@@ -0,0 +1,4 @@+TEST= pdynload/poly1+EXTRA_OBJS=Plugin.o+TOP=../../..+include ../../build.mk
+ testsuite/pdynload/poly1/Plugin.hs view
@@ -0,0 +1,5 @@+module Plugin where++import API++resource = plugin { function = (+) }
+ testsuite/pdynload/poly1/api/API.hs view
@@ -0,0 +1,9 @@+module API where++data Interface = Interface { + function :: (Num a) => a -> a -> a+}++plugin :: Interface+plugin = Interface { function = error "no function defined" }+
+ testsuite/pdynload/poly1/prog/Main.hs view
@@ -0,0 +1,18 @@++import System.Plugins+import API++src = "../Plugin.hs"+wrap = "../Wrapper.hs"+apipath = "../api"++main = do status <- make src ["-i"++apipath]+ case status of+ MakeSuccess _ _ -> f+ MakeFailure e -> mapM_ putStrLn e++ where f = do v <- pdynload "../Plugin.o" ["../api"] [] "API.Interface" "resource"+ case v of+ LoadSuccess _ a -> let fn = function a in putStrLn $ show $ 1 `fn` 2+ _ -> putStrLn "wrong types"+
+ testsuite/pdynload/poly1/prog/expected view
@@ -0,0 +1,1 @@+3
+ testsuite/pdynload/should_fail0/Makefile view
@@ -0,0 +1,4 @@+TEST= pdynload/should_fail0+EXTRA_OBJS=Plugin.o+TOP=../../..+include ../../build.mk
+ testsuite/pdynload/should_fail0/Plugin.hs view
@@ -0,0 +1,9 @@+module Plugin where++import API++resource = 0xBAD :: Int++-- resource = tiny { +-- field = "hello strange world"+-- }
+ testsuite/pdynload/should_fail0/api/API.hs view
@@ -0,0 +1,13 @@+{-# OPTIONS -fglasgow-exts #-}+-- ^ needed to derive Typeable++module API where++import Data.Dynamic++data Interface = Interface { field :: String }+ deriving (Show)++rsrc :: Interface+rsrc = Interface { field = "default value" }+
+ testsuite/pdynload/should_fail0/prog/Main.hs view
@@ -0,0 +1,18 @@++import System.Plugins+import API++src = "../Plugin.hs"+wrap = "../Wrapper.hs"+apipath = "../api"++main = do status <- make src ["-i"++apipath]+ case status of+ MakeSuccess _ _ -> f+ MakeFailure e -> mapM_ putStrLn e+ where + f = do v <- pdynload "../Plugin.o" ["../api"] [] "API.Interface" "resource"+ case v of+ LoadSuccess _ a -> putStrLn "loaded .. yay!"+ _ -> putStrLn "wrong types"+
+ testsuite/pdynload/should_fail0/prog/expected view
@@ -0,0 +1,1 @@+wrong types
+ testsuite/pdynload/should_fail1/Makefile view
@@ -0,0 +1,5 @@+# Missing class constraint... can't do that in Clean++TEST= pdynload/should_fail1+TOP=../../..+include ../../build.mk
+ testsuite/pdynload/should_fail1/Plugin.hs view
@@ -0,0 +1,5 @@+module Plugin where++data I = I Int++resource = I 1
+ testsuite/pdynload/should_fail1/api/API.hs view
@@ -0,0 +1,8 @@++module API where++newtype Interface = I Int++rsrc :: Interface+rsrc = I 1+
+ testsuite/pdynload/should_fail1/prog/Main.hs view
@@ -0,0 +1,17 @@++import System.Plugins+import API++src = "../Plugin.hs"+wrap = "../Wrapper.hs"+apipath = "../api"++main = do status <- make src ["-i"++apipath]+ case status of+ MakeSuccess _ _ -> f+ MakeFailure e -> mapM_ putStrLn e++ where f = do v <- pdynload "../Plugin.o" ["../api"] [] "API.Interface" "resource"+ case v of+ LoadSuccess _ a -> putStrLn "loaded .. yay!"+ _ -> putStrLn "wrong types"
+ testsuite/pdynload/should_fail1/prog/expected view
@@ -0,0 +1,1 @@+wrong types
+ testsuite/pdynload/small/Makefile view
@@ -0,0 +1,4 @@+TEST= pdynload/small+EXTRA_OBJS=Plugin.o+TOP=../../..+include ../../build.mk
+ testsuite/pdynload/small/Plugin.hs view
@@ -0,0 +1,5 @@+module Plugin where++import API++resource = plugin { function = "good" }
+ testsuite/pdynload/small/api/API.hs view
@@ -0,0 +1,9 @@+module API where++data Interface = Interface { + function :: String+}++plugin :: Interface+plugin = Interface { function = "goodbye" }+
+ testsuite/pdynload/small/prog/Main.hs view
@@ -0,0 +1,18 @@++import System.Plugins+import API++src = "../Plugin.hs"+wrap = "../Wrapper.hs"+apipath = "../api"++main = do status <- make src ["-i"++apipath]+ case status of+ MakeSuccess _ _ -> f+ MakeFailure e -> mapM_ putStrLn e++ where f = do v <- pdynload "../Plugin.o" ["../api"] [] "API.Interface" "resource"+ case v of+ LoadSuccess _ a -> putStrLn "loaded .. yay!"+ _ -> putStrLn "wrong types"+
+ testsuite/pdynload/small/prog/expected view
@@ -0,0 +1,1 @@+loaded .. yay!
+ testsuite/pdynload/spj1/Makefile view
@@ -0,0 +1,5 @@++TEST=pdynload/spj1++TOP=../../..+include ../../build.mk
+ testsuite/pdynload/spj1/Plugin.hs view
@@ -0,0 +1,17 @@+module Plugin where++-- user doesn't import the API+-- and provides a polymorphic value++-- import API+-- resource :: Interface++--+-- should pass type check, and dump core+--+-- resource :: Num a => a++-- import API++resource :: Num a => a+resource = 7
+ testsuite/pdynload/spj1/api/API.hs view
@@ -0,0 +1,9 @@++module API where++-- data Interface = Interface { field :: Int }++-- newtype Interface = Interface Int++type Interface = Int+
+ testsuite/pdynload/spj1/dont_test view
+ testsuite/pdynload/spj1/prog/Main.hs view
@@ -0,0 +1,17 @@++import System.Plugins+import API++src = "../Plugin.hs"+wrap = "../Wrapper.hs"+apipath = "../api"++main = do status <- make src ["-i"++apipath]+ case status of+ MakeSuccess _ _ -> f+ MakeFailure e -> mapM_ putStrLn e++ where f = do v <- pdynload "../Plugin.o" ["../api"] [] "API.Interface" "resource"+ case v of+ LoadSuccess _ (a :: Interface) -> print $ a -- will crash+ LoadFailure es -> putStrLn $ show es
+ testsuite/pdynload/spj1/prog/expected view
+ testsuite/pdynload/spj2/Makefile view
@@ -0,0 +1,5 @@++TEST=pdynload/spj1++TOP=../../..+include ../../build.mk
+ testsuite/pdynload/spj2/Plugin.hs view
@@ -0,0 +1,13 @@+module Plugin where++-- user doesn't import the API+-- and provides a polymorphic value++import API+resource :: Interface++--+-- should pass type check, and dump core+--+-- resource :: Num a => a+resource = 7
+ testsuite/pdynload/spj2/api/API.hs view
@@ -0,0 +1,6 @@++module API where++-- simple type+type Interface = Int+
+ testsuite/pdynload/spj2/prog/Main.hs view
@@ -0,0 +1,17 @@++import System.Plugins+import API++src = "../Plugin.hs"+wrap = "../Wrapper.hs"+apipath = "../api"++main = do status <- make src ["-i"++apipath]+ case status of+ MakeSuccess _ _ -> f+ MakeFailure e -> mapM_ putStrLn e++ where f = do v <- pdynload "../Plugin.o" ["../api"] [] "API.Interface" "resource"+ case v of+ LoadSuccess _ (a :: Interface) -> putStrLn $ show a -- will crash+ LoadFailure es -> putStrLn $ show es
+ testsuite/pdynload/spj2/prog/expected view
@@ -0,0 +1,1 @@+7
+ testsuite/pdynload/spj3/Makefile view
@@ -0,0 +1,3 @@+TEST= pdynload/spj3+TOP=../../..+include ../../build.mk
+ testsuite/pdynload/spj3/Plugin.hs view
@@ -0,0 +1,5 @@+module Plugin where++import API++resource = plugin { function = (+) :: Int -> Int -> Int }
+ testsuite/pdynload/spj3/api/API.hs view
@@ -0,0 +1,9 @@+module API where++data Interface = Interface { + function :: (Num a) => a -> a -> a+}++plugin :: Interface+plugin = Interface { function = error "no function defined" }+
+ testsuite/pdynload/spj3/prog/Main.hs view
@@ -0,0 +1,18 @@++import System.Plugins+import API++src = "../Plugin.hs"+wrap = "../Wrapper.hs"+apipath = "../api"++main = do status <- make src ["-i"++apipath]+ case status of+ MakeSuccess _ _ -> f+ MakeFailure e -> mapM_ putStrLn e++ where f = do v <- pdynload "../Plugin.o" ["../api"] [] "API.Interface" "resource"+ case v of+ LoadSuccess _ a -> let fn = function a in putStrLn $ show $ 1 `fn` 2+ _ -> putStrLn "wrong types"+
+ testsuite/pdynload/spj3/prog/expected view
@@ -0,0 +1,8 @@++../Plugin.hs:5:+ Cannot unify the type-signature variable `a' with the type `Int'+ Expected type: a -> a -> a+ Inferred type: Int -> Int -> Int+ When checking the type signature of the expression:+ (+) :: Int -> Int -> Int+ In the `function' field of a record
+ testsuite/pdynload/spj3/prog/expected.604 view
@@ -0,0 +1,9 @@++../Plugin.hs:5:31:+ Couldn't match the rigid variable `a' against `Int'+ `a' is bound by the polymorphic type `forall a. (Num a) => a -> a -> a'+ at ../Plugin.hs:5:11-56+ Expected type: a -> a -> a+ Inferred type: Int -> Int -> Int+ In the expression: (+) :: Int -> Int -> Int+ In the `function' field of a record
+ testsuite/pdynload/spj3/prog/expected.605 view
@@ -0,0 +1,9 @@++../Plugin.hs:5:31:+ Couldn't match the rigid variable `a' against `Int'+ `a' is bound by the polymorphic type `forall a. (Num a) => a -> a -> a'+ at ../Plugin.hs:5:11-56+ Expected type: a -> a -> a+ Inferred type: Int -> Int -> Int+ In the expression: (+) :: Int -> Int -> Int+ In the `function' field of a record
+ testsuite/pdynload/spj4/Makefile view
@@ -0,0 +1,5 @@++TEST=pdynload/spj4++TOP=../../..+include ../../build.mk
+ testsuite/pdynload/spj4/Plugin.hs view
@@ -0,0 +1,16 @@+module Plugin where++-- user doesn't import the API+-- and provides a polymorphic value++-- import API+-- resource :: Interface++--+-- should pass type check, and dump core+--+-- resource :: Num a => a++import API++resource = Interface { field = 7 :: Num a => a }
+ testsuite/pdynload/spj4/api/API.hs view
@@ -0,0 +1,5 @@++module API where++newtype Interface = Interface { field :: Int }+
+ testsuite/pdynload/spj4/prog/Main.hs view
@@ -0,0 +1,17 @@++import System.Plugins+import API++src = "../Plugin.hs"+wrap = "../Wrapper.hs"+apipath = "../api"++main = do status <- make src ["-i"++apipath]+ case status of+ MakeSuccess _ _ -> f+ MakeFailure e -> error "there was a type error"++ where f = do v <- pdynload "../Plugin.o" ["../api"] [] "API.Interface" "resource"+ case v of+ LoadSuccess _ (a :: Interface) -> print $ field a -- will crash+ LoadFailure es -> mapM_ putStrLn es
+ testsuite/pdynload/spj4/prog/expected view
@@ -0,0 +1,1 @@+7
+ testsuite/pdynload/typealias/Makefile view
@@ -0,0 +1,5 @@+# Missing class constraint... can't do that in Clean++TEST= pdynload/typealias+TOP=../../..+include ../../build.mk
+ testsuite/pdynload/typealias/Plugin.hs view
@@ -0,0 +1,3 @@+module Plugin where++resource = 1 :: Int
+ testsuite/pdynload/typealias/api/API.hs view
@@ -0,0 +1,8 @@++module API where++type Interface = Int++rsrc :: Interface+rsrc = 1+
+ testsuite/pdynload/typealias/prog/Main.hs view
@@ -0,0 +1,19 @@++import System.Plugins+import API++src = "../Plugin.hs"+wrap = "../Wrapper.hs"+apipath = "../api"++main = do status <- make src ["-i"++apipath]+ case status of+ MakeSuccess _ _ -> f+ MakeFailure e -> mapM_ putStrLn e++ where f = do v <- pdynload "../Plugin.o" ["../api"] [] "API.Interface" "resource"+ case v of+ LoadSuccess _ a -> putStrLn "loaded .. yay!"+ _ -> putStrLn "wrong types"++
+ testsuite/pdynload/typealias/prog/expected view
@@ -0,0 +1,1 @@+loaded .. yay!
+ testsuite/pdynload/univquant/Makefile view
@@ -0,0 +1,4 @@+TEST= pdynload/univquant+EXTRA_OBJS=Plugin.o+TOP=../../..+include ../../build.mk
+ testsuite/pdynload/univquant/Plugin.hs view
@@ -0,0 +1,8 @@+module Plugin where++import API++resource = plugin { function = my_id }++my_id :: forall a. a -> a+my_id x = x
+ testsuite/pdynload/univquant/api/API.hs view
@@ -0,0 +1,9 @@+module API where++data Interface = Interface { + function :: forall a. a -> a+}++plugin :: Interface+plugin = Interface { function = id }+
+ testsuite/pdynload/univquant/prog/Main.hs view
@@ -0,0 +1,17 @@++import System.Plugins+import API++src = "../Plugin.hs"+wrap = "../Wrapper.hs"+apipath = "../api"++main = do status <- make src ["-i"++apipath]+ case status of+ MakeSuccess _ _ -> f+ MakeFailure e -> mapM_ putStrLn e++ where f = do v <- pdynload "../Plugin.o" ["../api"] [] "API.Interface" "resource"+ case v of+ LoadSuccess _ a -> putStrLn "loaded .. yay!"+ _ -> putStrLn "wrong types"
+ testsuite/pdynload/univquant/prog/expected view
@@ -0,0 +1,1 @@+loaded .. yay!
+ testsuite/pkgconf/null/Makefile view
@@ -0,0 +1,16 @@+all:+ @echo "test disabled"++#true_api::+# ( cd api ;\+# $(GHC) -Onot $(EXTRAFLAGS) -c $(API).hs ;\+# $(RM) -f libHSapi.a ;\+# $(AR) cq libHSapi.a API.o ;\+# $(RANLIB) libHSapi.a ;\+# $(LD) -r $(LD_X) $(WHOLE_ARCHIVE_FLAG) -o HSapi.o libHSapi.a ;\+# rm API.o ;\+# echo [] > package.conf ;\+# env PREFIX=`pwd` $(GHC_PKG) -f package.conf -u < package.conf.in )+# $(GHC) -package-conf ${TOP}/plugins.conf.inplace -package plugins \+# -package-conf api/package.conf -package api \+# -O $(EXTRAFLAGS) -c Null.hs
+ testsuite/pkgconf/null/Null.hs view
@@ -0,0 +1,6 @@+module Null ( resource ) where++import API++resource = plugin { a = 7 }+
+ testsuite/pkgconf/null/api/API.hs view
@@ -0,0 +1,10 @@+{-# OPTIONS -fglasgow-exts #-}++module API where++data Null = Null { a, b :: Int }+ deriving Show++plugin :: Null+plugin = Null { a = 42 , b = 1 }+
+ testsuite/pkgconf/null/api/package.conf.in view
@@ -0,0 +1,18 @@+Package {+ name = "api",+ auto = False,++ import_dirs = [ "${PREFIX}" ],+ library_dirs = [ "${PREFIX}" ],+ hs_libraries = [ "HSapi" ],++ include_dirs = [],+ c_includes = [],+ source_dirs = [],+ extra_libraries = [],+ package_deps = [],+ extra_ghc_opts = [],+ extra_cc_opts = [],+ extra_ld_opts = []+}+
+ testsuite/pkgconf/null/dont_test view
+ testsuite/pkgconf/null/prog/Main.hs view
@@ -0,0 +1,12 @@+{-# OPTIONS -cpp #-}++#include "../../../../config.h"++import System.Plugins+import API++main = do + let includes = TOP ++ "/testsuite/load/null/api"+ (_,v) <- load "../Null.o" ["."] ["../api/package.conf"] "resource"+ putStrLn ( show (a v) )+
+ testsuite/plugs/plugs/Main.hs view
@@ -0,0 +1,69 @@+--+-- Copyright (c) 2004 Don Stewart - http://www.cse.unsw.edu.au/~dons+-- GPL version 2 or later (see http://www.gnu.org/copyleft/gpl.html)+--++import System.Eval.Haskell+import System.Plugins.Load++import System.Exit ( ExitCode(..), exitWith )+import System.IO+import System.Console.Readline ( readline, addHistory )++symbol = "resource"++main = do+ putStrLn banner + putStr "Loading package base" >> hFlush stdout+ loadPackage "base" + putStr " ... linking ... " >> hFlush stdout+ resolveObjs (return ())+ putStrLn "done"++ shell []++shell :: [String] -> IO ()+shell imps = do + s <- readline "plugs> "+ cmd <- case s of + Nothing -> exitWith ExitSuccess+ Just (':':'q':_) -> exitWith ExitSuccess+ Just s -> addHistory s >> return s+ imps' <- run cmd imps+ shell imps'++run :: String -> [String] -> IO [String]+run "" is = return is+run ":?" is = putStrLn help >> return is++run ":l" _ = return []+run (':':'l':' ':m) is = return (m:is)++run (':':'t':' ':s) is = do + ty <- typeOf s is+ when (not $ null ty) (putStrLn $ s ++ " :: " ++ ty)+ return is++run (':':_) is = putStrLn help >> return is++run s is = do + s <- unsafeEval ("show $ "++s) is+ when (isJust s) (putStrLn (fromJust s))+ return is++banner = "\ +\ __ \n\+\ ____ / /_ ______ ______ \n\+\ / __ \\/ / / / / __ `/ ___/ PLugin User's GHCi System, for Haskell 98\n\+\ / /_/ / / /_/ / /_/ (__ ) http://www.cse.unsw.edu.au/~dons/hs-plugins\n\+\ / .___/_/\\__,_/\\__, /____/ Type :? for help \n\+\/_/ /____/ \n"++help = "\+\Commands :\n\ +\ <expr> evaluate expression\n\ +\ :t <expr> show type of expression (monomorphic only)\n\ +\ :l module bring module in to scope\n\ +\ :l clear module list\n\ +\ :quit quit\n\ +\ :? display this list of commands"
+ testsuite/plugs/plugs/Makefile view
@@ -0,0 +1,28 @@+GHCFLAGS= -O+PKGFLAGS+= -package plugins -package readline++all: build++build:+ @$(GHC) $(GHCFLAGS) $(PKGFLAGS) $(EXTRAFLAGS) Main.hs -o plugs+check: build+ @(if [ -f "expected" ] ;\+ then \+ actual_out="/tmp/hs-plugins-actual.out.$$$$" ;\+ diff_out="/tmp/hs-plugins.diff.$$$$" ;\+ cat test.in | ./plugs > $$actual_out 2>&1 || true ;\+ diff -u expected $$actual_out > $$diff_out || true ;\+ if [ -s "$$diff_out" ] ; then \+ echo "failed with:" ;\+ cat "$$diff_out" | sed '1,3d' ;\+ else \+ echo "ok." ;\+ fi ;\+ rm $$actual_out ;\+ else \+ cat test.in | ./plugs 2>&1 || true ;\+ fi)+clean:+ rm -rf *.hi *.o *~ *.dep ./plugs++include ../../../config.mk
+ testsuite/plugs/plugs/expected view
@@ -0,0 +1,9 @@+ __ + ____ / /_ ______ ______ + / __ \/ / / / / __ `/ ___/ PLugin User's GHCi System, for Haskell 98+ / /_/ / / /_/ / /_/ (__ ) http://www.cse.unsw.edu.au/~dons/hs-plugins+ / .___/_/\__,_/\__, /____/ Type :? for help +/_/ /____/ ++Loading package base ... linking ... plugs> plugs> done+453973694165307953197296969697410619233826
+ testsuite/plugs/plugs/test.in view
@@ -0,0 +1,2 @@+let fibs = 1 : 1 : zipWith (+) fibs (tail fibs) in fibs !! 200+:quit
+ testsuite/plugs/runplugs/Main.hs view
@@ -0,0 +1,57 @@+--+-- Copyright (c) 2004 Don Stewart - http://www.cse.unsw.edu.au/~dons+-- GPL version 2 or later (see http://www.gnu.org/copyleft/gpl.html)+--++--+-- | Runplugs: use hs-plugins to run a Haskell expression under+-- controlled conditions.+--+import System.Eval.Haskell (unsafeEval)++import Data.Char (chr)+import Data.Maybe (isJust, fromJust)+import Control.Monad++import System.Random+import System.Exit (exitWith, ExitCode(ExitSuccess))+import System.IO (getContents, putStrLn)+import System.Posix.Resource (setResourceLimit,+ Resource(ResourceCPUTime), + ResourceLimits(ResourceLimits),+ ResourceLimit(ResourceLimit))++import qualified Control.Exception (catch)++rlimit = ResourceLimit 3++context = prehier ++ datas ++ qualifieds ++ controls++prehier = ["Char", "List", "Maybe", "Numeric", "Random" ]++qualifieds = ["qualified Data.Map as M"+ ,"qualified Data.Set as S"+ ,"qualified Data.IntSet as I"]++datas = map ("Data." ++) [+ "Bits", "Bool", "Char", "Dynamic", "Either", + "Graph", "Int", "Ix", "List",+ "Maybe", "Ratio", "Tree", "Tuple", "Typeable", "Word" + ]++controls = map ("Control." ++) ["Monad", "Monad.Reader", "Monad.Fix", "Arrow"]++main = do+ setResourceLimit ResourceCPUTime (ResourceLimits rlimit rlimit)+ s <- getLine+ when (not . null $ s) $ do+ x <- sequence (take 3 (repeat $ getStdRandom (randomR (97,122)) >>= return . chr))+ s <- unsafeEval ("let { "++x+++ " = \n# 1 \"<irc>\"\n"++s+++ "\n} in take 2048 (show "++x+++ ")") context+ when (isJust s) $ Control.Exception.catch + (putStrLn $ fromJust s)+ (\e -> putStrLn $ "Exception: " ++ show e )+ exitWith ExitSuccess+
+ testsuite/plugs/runplugs/Makefile view
@@ -0,0 +1,30 @@+GHCFLAGS= -Onot $(GHC_EXTRA_OPTS)+PKGFLAGS= -package posix+PKGFLAGS+= -package plugins++all: build++build:+ @$(GHC) $(GHCFLAGS) $(PKGFLAGS) $(EXTRAFLAGS) Main.hs -o runplugs+include ../../../config.mk+check: build+ @(if [ -f "expected" ] ;\+ then \+ actual_out="/tmp/hs-plugins-actual.out.$$$$" ;\+ diff_out="/tmp/hs-plugins.diff.$$$$" ;\+ cat test.in | ./runplugs > $$actual_out 2>&1 || true ;\+ diff -u expected $$actual_out > $$diff_out || true ;\+ if [ -s "$$diff_out" ] ; then \+ echo "failed with:" ;\+ cat "$$diff_out" | sed '1,3d' ;\+ else \+ echo "ok." ;\+ fi ;\+ rm $$actual_out ;\+ else \+ cat test.in | ./runplugs 2>&1 || true ;\+ fi)+clean:+ rm -rf *.hi *.o *~ *.dep ./runplugs++include ../../../config.mk
+ testsuite/plugs/runplugs/expected view
@@ -0,0 +1,1 @@+453973694165307953197296969697410619233826
+ testsuite/plugs/runplugs/test.in view
@@ -0,0 +1,1 @@+let fibs = 1 : 1 : zipWith (+) fibs (tail fibs) in fibs !! 200
+ testsuite/reload/null/Makefile view
@@ -0,0 +1,4 @@+TEST= reload/null+EXTRA_OBJS=Null.o+TOP=../../..+include ../../build.mk
+ testsuite/reload/null/Null.hs view
@@ -0,0 +1,11 @@+module Null ( resource, resource_dyn ) where++import API+import Data.Dynamic+import Prelude hiding (null)++resource = null++-- ! this has to be special: it can't be overridden by the user.+resource_dyn :: Dynamic+resource_dyn = toDyn resource
+ testsuite/reload/null/api/API.hs view
@@ -0,0 +1,12 @@+{-# OPTIONS -fglasgow-exts #-}++module API where++import Data.Dynamic++data Null = Null { a, b :: Int }+ deriving (Typeable, Show)++null :: Null+null = Null { a = 42 , b = 1 }+
+ testsuite/reload/null/prog/Main.hs view
@@ -0,0 +1,19 @@++import System.Plugins+import API++-- an example where we just want to load an object and run it++main = do + m_v <- load "../Null.o" ["../api"] [] "resource"+ (m,v) <- case m_v of+ LoadSuccess m v -> return (m,v)+ _ -> error "load failed"+ putStrLn ( show (a v) )++ m_v <- reload m "resource" -- get a new version+ v' <- case m_v of+ LoadSuccess _ v -> return v+ _ -> error "load failed"+ putStrLn ( show (a v') )+
+ testsuite/reload/null/prog/expected view
@@ -0,0 +1,2 @@+42+42
+ testsuite/shell/shell/API.hs view
@@ -0,0 +1,8 @@+module API where++-- the interface between the app and the plugin+data Interface = Interface { function :: String -> String }++-- default values for the interface+plugin :: Interface+plugin = Interface { function = id }
+ testsuite/shell/shell/Main.hs view
@@ -0,0 +1,85 @@+--+-- a simple shell for loading plugins and evaluating their functions+-- ++import System.Plugins+import API++import Data.Either+import Data.Char+import Control.Monad ( when )+import System.Console.Readline ( readline )+import System.Exit ( ExitCode(..), exitWith )+++source = "Plugin.hs"+stub = "Plugin.stub"++sym = "resource"++main = do+ status <- makeWith source stub []+ p <- case status of+ MakeFailure e -> mapM_ putStrLn e >> error "failed to compile"+ MakeSuccess _ obj -> do+ m_v <- load obj ["."] [] sym+ case m_v of+ LoadSuccess m v -> return (m,v)+ LoadFailure e -> do mapM_ putStrLn e+ error "failed to load"+ shell p++ where+ shell p@(m,v) = do ++ s <- readline "> "+ cmd <- case s of + Nothing -> exitWith ExitSuccess+ Just ":q" -> exitWith ExitSuccess+ Just s -> return (chomp s)++ status <- makeWith source stub [] + case status of + MakeFailure e -> do + mapM_ putStrLn e+ shell p -- print error and back to prompt++ MakeSuccess NotReq o -> do+ p' <- eval cmd p+ shell p' -- eval str again++ MakeSuccess ReComp o -> do+ m_v' <- reload m sym+ case m_v' of+ LoadFailure e -> mapM_ putStrLn e >> error "failed to load"+ LoadSuccess _ v' -> do+ let p' = (m,v')+ p'' <- eval cmd p'+ shell p''++--+-- shell commands+--+eval "" p = return p++eval ":clear" p = do+ let loop i = when (i < 40) (do putStr "\n" ; loop $! i+1)+ loop 0+ return p++eval ":?" p = do+ putStrLn$"\":?\"\n" +++ "\":quit\"\n" +++ "\":clear\"\n" +++ "\"foo\""+ return p++eval s (m,v) = putStrLn ((function v) s) >> return (m,v)++--+-- strip trailing whitespace+--+chomp :: String -> String+chomp [] = []+chomp s | isSpace (last s) = chomp $! init s+ | otherwise = s
+ testsuite/shell/shell/Makefile view
@@ -0,0 +1,2 @@+TOP=../../..+include ../../eval.mk
+ testsuite/shell/shell/Plugin.hs view
@@ -0,0 +1,5 @@++resource = plugin { + function = map toUpper+}+
+ testsuite/shell/shell/Plugin.stub view
@@ -0,0 +1,19 @@+--+-- this is a "stub" file, containing default syntax we don't+-- want the user to have to write+--+-- for example, it constrains the module name and force the API to be+-- imported++module Plugin ( resource ) where++import API+import Data.Char+import Data.List++-- this is a default definition of 'resource'. it will be overridden+-- by anything the user writes. useful for default values++resource :: Interface+resource = plugin+
+ testsuite/shell/shell/README view
@@ -0,0 +1,23 @@+$ make+$ ./a.out +Compiling plugin ... done+Loading package base ... linking ... done+Loading objects API Plugin ... done+> ?+"?"+"quit"+"clear"+"filter foo"+> filter adf adsf+fsda fda+> filter asd faSDFADSF+FSDAFDSaf dsa++-- at this point I edit the plugin and save the source++> filter asfdaSDFASD+Compiling plugin ... done+Reloading Plugin ... done+DSAFDSADFSA++-- it compiled and reloaded it for me. nice.
+ testsuite/shell/shell/dont_test view
+ testsuite/shell/simple/Main.hs view
@@ -0,0 +1,41 @@+import System.Plugins+import StringProcessorAPI+import System.Console.Readline+import System.Exit++source = "Plugin.hs"+stub = "Plugin.stub"+symbol = "resource"++main = do s <- makeWith source stub []+ o <- case s of+ MakeSuccess _ obj -> do+ ls <- load obj ["."] [] symbol+ case ls of LoadSuccess m v -> return (m,v)+ LoadFailure err -> error "load failed"+ MakeFailure e -> mapM_ putStrLn e >> error "compile failed"+ shell o++shell o@(m,plugin) = do + s <- readline "> "+ cmd <- case s of + Nothing -> exitWith ExitSuccess+ Just (':':'q':_) -> exitWith ExitSuccess+ Just s -> addHistory s >> return s++ s <- makeWith source stub [] -- maybe recompile the source+ o' <- case s of+ MakeSuccess ReComp o -> do + ls <- reload m symbol+ case ls of LoadSuccess m' v' -> return (m',v')+ LoadFailure err -> error "reload failed"+ MakeSuccess NotReq _ -> return o+ MakeFailure e -> mapM_ putStrLn e >> shell o+ eval cmd o'+ shell o'++eval ":?" _ = putStrLn ":?\n:q\n<string>"++eval s (_,plugin) = let fn = (stringProcessor plugin) in putStrLn (fn s)++
+ testsuite/shell/simple/Makefile view
@@ -0,0 +1,6 @@+OBJS=StringProcessorAPI.o+TOP=../../..+include ../../eval.mk++#all:+# @echo test disabled
+ testsuite/shell/simple/Plugin.hs view
@@ -0,0 +1,5 @@+import Char++resource = plugin { + stringProcessor = map toUpper+}
+ testsuite/shell/simple/Plugin.stub view
@@ -0,0 +1,19 @@+--+-- this is a "stub" file, containing default syntax we don't+-- want the user to have to write+--+-- for example, it constrains the module name and force the API to be+-- imported++module Plugin ( resource ) where++import StringProcessorAPI+import Data.Char+import Data.List++-- this is a default definition of 'resource'. it will be overridden+-- by anything the user writes. useful for default values++resource :: Interface+resource = plugin+
+ testsuite/shell/simple/README view
@@ -0,0 +1,23 @@+$ make+$ ./a.out +Compiling plugin ... done+Loading package base ... linking ... done+Loading objects API Plugin ... done+> ?+"?"+"quit"+"clear"+"filter foo"+> filter adf adsf+fsda fda+> filter asd faSDFADSF+FSDAFDSaf dsa++-- at this point I edit the plugin and save the source++> filter asfdaSDFASD+Compiling plugin ... done+Reloading Plugin ... done+DSAFDSADFSA++-- it compiled and reloaded it for me. nice.
+ testsuite/shell/simple/StringProcessorAPI.hs view
@@ -0,0 +1,8 @@+module StringProcessorAPI where++data Interface = Interface { + stringProcessor :: String -> String +}++plugin :: Interface+plugin = Interface { stringProcessor = id }
+ testsuite/shell/simple/dont_test view
+ testsuite/unload/null/Makefile view
@@ -0,0 +1,4 @@+TEST= unload/null+EXTRA_OBJS=Null.o+TOP=../../..+include ../../build.mk
+ testsuite/unload/null/Null.hs view
@@ -0,0 +1,11 @@+module Null ( resource, resource_dyn ) where++import API+import Data.Dynamic+import Prelude hiding (null)++resource = null++-- ! this has to be special: it can't be overridden by the user.+resource_dyn :: Dynamic+resource_dyn = toDyn resource
+ testsuite/unload/null/api/API.hs view
@@ -0,0 +1,12 @@+{-# OPTIONS -fglasgow-exts #-}++module API where++import Data.Dynamic++data Null = Null { a, b :: Int }+ deriving (Typeable, Show)++null :: Null+null = Null { a = 42 , b = 1 }+
+ testsuite/unload/null/prog/Main.hs view
@@ -0,0 +1,11 @@++import System.Plugins+import API++-- an example where we just want to load an object and run it++main = do + m_v <- load "../Null.o" ["../api"] [] "resource"+ case m_v of+ LoadFailure _ -> error "load failed"+ LoadSuccess m v -> do putStrLn ( show (a v) ) ; unload m
+ testsuite/unload/null/prog/expected view
@@ -0,0 +1,1 @@+42
+ testsuite/unload/sjwtrap/Makefile view
@@ -0,0 +1,4 @@+TEST= unload/sjwtrap+EXTRA_OBJS=Null.o+TOP=../../..+include ../../build.mk
+ testsuite/unload/sjwtrap/Null.hs view
@@ -0,0 +1,6 @@+module Null where++import qualified Prelude+import API++resource = null
+ testsuite/unload/sjwtrap/api/API.hs view
@@ -0,0 +1,9 @@+{-# OPTIONS -fglasgow-exts #-}++module API where++data Null = Null { a, b :: Int }++null :: Null+null = Null { a = 42 , b = 1 }+
+ testsuite/unload/sjwtrap/prog/Main.hs view
@@ -0,0 +1,15 @@++import System.Plugins+import API++--+-- what happens if we try to use code that has been unloaded?+--++main = do + m_v <- load "../Null.o" ["../api"] [] "resource"+ (m,v) <- case m_v of+ LoadSuccess m v -> return (m,v)+ _ -> error "load failed"+ putStrLn ( show (a v) )+ unload m
+ testsuite/unload/sjwtrap/prog/expected view
@@ -0,0 +1,1 @@+42
+ testsuite/unloadAll/null/Dep.hs view
@@ -0,0 +1,7 @@+module Dep ( resource ) where++import API+import Data.Dynamic+import Prelude hiding (null)++resource = null
+ testsuite/unloadAll/null/Makefile view
@@ -0,0 +1,4 @@+TEST= unloadAll/null+EXTRA_OBJS=Dep.o Null.o+TOP=../../..+include ../../build.mk
+ testsuite/unloadAll/null/Null.hs view
@@ -0,0 +1,12 @@+module Null ( resource ) where++import API+import Data.Dynamic+import Prelude hiding (null)+import qualified Dep++resource = Dep.resource++-- ! this has to be special: it can't be overridden by the user.+resource_dyn :: Dynamic+resource_dyn = toDyn resource
+ testsuite/unloadAll/null/api/API.hs view
@@ -0,0 +1,12 @@+{-# OPTIONS -fglasgow-exts #-}++module API where++import Data.Dynamic++data Null = Null { a, b :: Int }+ deriving (Typeable, Show)++null :: Null+null = Null { a = 42 , b = 1 }+
+ testsuite/unloadAll/null/prog/Main.hs view
@@ -0,0 +1,15 @@++import System.Plugins+import API++-- an example where we just want to load an object and run it++main = do + m_v <- load_ "../Null.o" ["../api",".."] "resource"+ t <- load_ "../Dep.o" ["../api"] "resource"+ case m_v of+ LoadFailure err -> error (unlines err)+ LoadSuccess m v -> do putStrLn ( show (a v) ) ; unloadAll m -- unloads Null.o but not Dep.o since we're still using it.+ case t of+ LoadFailure err -> error (unlines err)+ LoadSuccess m v -> do putStrLn ( show (a v) ) ; unloadAll m
+ testsuite/unloadAll/null/prog/expected view
@@ -0,0 +1,2 @@+42+42