551 |
551 |
552 *} |
552 *} |
553 |
553 |
554 ML {* OuterSyntax.command *} |
554 ML {* OuterSyntax.command *} |
555 |
555 |
556 section {* New Commands and Keyword Files *} |
556 section {* New Commands and Creating Keyword Files *} |
557 |
557 |
558 text {* |
558 text {* |
559 |
|
560 Often new commands, for example for providing a new definitional principle, |
559 Often new commands, for example for providing a new definitional principle, |
561 need to be programmed. While this is not too difficult to do on the |
560 need to be programmed. While this is not difficult to do on the ML-level, |
562 ML-level, new commands, in order to be useful, need to be recognised by |
561 new commands, in order to be useful, need to be recognised by |
563 ProofGeneral. This results in some subtle configuration issues, which we |
562 ProofGeneral. This results in some subtle configuration issues, which we |
564 will explain in this section. |
563 will explain in this section. |
565 |
564 |
566 |
565 Let us start with a ``silly'' command, below named \isacommand{foo}, which does nothing at all. |
567 Let us start with a silly command, named \isacommand{foo}, which does nothing at all. |
566 On the ML-level it can be defined as |
568 It can be defined as |
|
569 |
567 |
570 @{ML [display] |
568 @{ML [display] |
571 "let |
569 "let |
572 val do_nothing = Scan.succeed (Toplevel.theory (fn x => x)) |
570 val do_nothing = Scan.succeed (Toplevel.theory (fn x => x)) |
573 val flag = OuterKeyword.thy_decl |
571 val flag = OuterKeyword.thy_decl |
574 in |
572 in |
575 OuterSyntax.command \"foo\" \"description of foo\" flag do_nothing |
573 OuterSyntax.command \"foo\" \"description of foo\" flag do_nothing |
576 end"} |
574 end"} |
577 |
575 |
578 The crucial function that makes the command \isacommand{foo} known to |
576 The function @{ML OuterSyntax.command} expects a name for the command, a |
579 Isabelle is @{ML OuterSyntax.command}. It expects a name of a command, a |
577 short description, a flag (which we will explain it later on more thoroughly) and a |
580 short description, a flag (we will explain it later more thoroughly) and a |
|
581 parser for a top-level transition function (its purpose will also explained |
578 parser for a top-level transition function (its purpose will also explained |
582 later on). Lets also assume we packaged this function into a separate |
579 later). |
583 theory named @{text "Command"}, say, and a file named @{text "Command.thy"}. |
580 |
584 |
581 While this is everything we have to do on the ML-level, we need |
585 We now need a keyword file, that can be loaded by ProofGeneral in |
582 now a keyword file that can be loaded by ProofGeneral. This is to enable ProofGeneral |
586 order to recognise \isacommand{foo} as command. Such a keyword file |
583 to recognise \isacommand{foo} as a command. Such a keyword file can be generated with |
587 can be generated with the command-line |
584 the command-line |
588 |
585 |
589 @{text [display] "$ isabelle keywords -k foo some-log-files"} |
586 @{text [display] "$ isabelle keywords -k foo <some-log-files>"} |
590 |
587 |
591 The option @{text "-k foo"} indicates which postfix the keyword file will obtain. In |
588 The option @{text "-k foo"} indicates which postfix the keyword file will obtain. In |
592 the case above the generated file is named @{text "isar-keywords-foo.el"}. This command |
589 the case above the generated file will be named @{text "isar-keywords-foo.el"}. This command |
593 requires log files to be present (in order to extract the keywords from them). For |
590 requires log files to be present (in order to extract the keywords from them). |
|
591 To generate these log files, we first package the code above into a separate theory file |
|
592 named @{text "Command.thy"}, say---see Figure~\ref{fig:commandtheory} for the complete code. |
|
593 |
|
594 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
|
595 \begin{figure}[t] |
|
596 \begin{boxedminipage}{\textwidth} |
|
597 \isacommand{theory}~@{text Command}\\ |
|
598 \isacommand{imports}~@{text Main}\\ |
|
599 \isacommand{begin}\\ |
|
600 \isacommand{ML}~\isa{\isacharverbatimopen}\\ |
|
601 @{ML |
|
602 "let |
|
603 val do_nothing = Scan.succeed (Toplevel.theory (fn x => x)) |
|
604 val flag = OuterKeyword.thy_decl |
|
605 in |
|
606 OuterSyntax.command \"foo\" \"description of foo\" flag do_nothing |
|
607 end"}\\ |
|
608 \isa{\isacharverbatimclose}\\ |
|
609 \isacommand{end} |
|
610 \end{boxedminipage} |
|
611 \caption{The file @{text "Command.thy"} is necessary for generating a log |
|
612 file. This log file enables Isabelle to generate a keyword file containing |
|
613 the command \isacommand{foo}.\label{fig:commandtheory}} |
|
614 \end{figure} |
|
615 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
|
616 |
|
617 For |
594 our purposes it is sufficient to use the log files for the theories @{text "Pure"}, |
618 our purposes it is sufficient to use the log files for the theories @{text "Pure"}, |
595 @{text "HOL"} and @{text "Pure-ProofGeneral"}, as well as the theory @{text "Command.thy"} |
619 @{text "HOL"} and @{text "Pure-ProofGeneral"}, as well as the theory @{text "Command.thy"} |
596 containing the new command. @{text Pure} and @{text HOL} are usually compiled during the |
620 containing the new command. @{text Pure} and @{text HOL} are usually compiled during the |
597 installation of Isabelle, if not this can be done conveniently using build script from |
621 installation of Isabelle. So log files for them are already available. If not, then they |
598 the distribution |
622 can be conveniently compiled using build-script from the distribution |
599 |
623 |
600 @{text [display] |
624 @{text [display] |
601 "$ ./build -m \"Pure\" |
625 "$ ./build -m \"Pure\" |
602 $ ./build -m \"HOL\""} |
626 $ ./build -m \"HOL\""} |
603 |
627 |
604 The @{text "Pure-ProofGeneral"} theory needs to be compiled with |
628 The @{text "Pure-ProofGeneral"} theory needs to be compiled with |
605 |
629 |
606 @{text [display] "$ ./build -m \"Pure-ProofGeneral\" \"Pure\""} |
630 @{text [display] "$ ./build -m \"Pure-ProofGeneral\" \"Pure\""} |
607 |
631 |
608 For the theory containing the new command \isacommand{foo}, we first |
632 For the theory @{text "Command.thy"}, we first create a ``managed'' subdirectory |
609 create a ``managed'' subdirectory by |
633 with |
610 |
634 |
611 |
635 @{text [display] "$ isabelle mkdir FooCommand"} |
612 This creates files @{text "IsaMakefile"} and @{text "./FooCommand/ROOT.ML"}. We |
636 |
613 need to copy the file @{text "Command.thy"} into the directory @{text "FooCommand"} |
637 This creates a directory containing the files |
614 and add @{text "use_thy \"Command\";"} to @{text "./FooCommand/ROOT.ML"}. |
638 |
615 Now we can compile the theory by just typing |
639 @{text [display] |
|
640 "./IsaMakefile |
|
641 ./FooCommand/ROOT.ML |
|
642 ./FooCommand/document |
|
643 ./FooCommand/document/root.tex"} |
|
644 |
|
645 |
|
646 We need to copy the file @{text "Command.thy"} into the directory @{text "FooCommand"} |
|
647 and add the line |
|
648 |
|
649 @{text [display] "use_thy \"Command\";"} |
|
650 |
|
651 to the file @{text "./FooCommand/ROOT.ML"}. Now we can compile the theory by just typing |
616 |
652 |
617 @{text [display] "$ isabelle make"} |
653 @{text [display] "$ isabelle make"} |
618 |
654 |
619 All these compilations created the log files that we are after. They are typically stored |
655 We created now the necessary log files. They are typically stored |
620 under the directory |
656 in the directory |
621 |
657 |
622 @{text [display] "~/.isabelle/heaps/\<dots>\<dots>/\<dots>\<dots>/log"} |
658 @{text [display] "~/.isabelle/heaps/Isabelle2008/polyml-5.2.1_x86-linux/log"} |
623 |
659 |
624 where the dots stand for names of the current Isabelle distribution and |
660 or something similar depending on your Isabelle distribution and architecture. |
625 hardware architecture. In it are the files |
661 Let us assume the name of this directory is stored in the shell variable |
|
662 @{text "ISABELLE_LOGS"}. One way to assign this shell variable is by typing |
|
663 |
|
664 @{text [display] "$ ISABELLE_LOGS=\"$(isabelle getenv -b ISABELLE_OUTPUT)\"/log"} |
|
665 |
|
666 In this directory are the files |
626 |
667 |
627 @{text [display] |
668 @{text [display] |
628 "Pure.gz |
669 "Pure.gz |
629 HOL.gz |
670 HOL.gz |
630 Pure-ProofGeneral.gz |
671 Pure-ProofGeneral.gz |
631 HOL-FooCommand.gz"} |
672 HOL-FooCommand.gz"} |
632 |
673 |
633 Let us assume the directory with these files is stored in the shell variable |
|
634 @{text "ISABELLE_LOGS"}, by typing for example |
|
635 |
|
636 @{text [display] "$ ISABELLE_LOGS=\"$(isabelle getenv -b ISABELLE_OUTPUT)\"/log"} |
|
637 |
|
638 We can now create the keyword file with |
674 We can now create the keyword file with |
639 |
675 |
640 @{text [display] |
676 @{text [display] |
641 "$ isabelle keywords -k foo |
677 "$ isabelle keywords -k foo |
642 `$ISABELLE_LOGS/{Pure.gz,HOL.gz,Pure-ProofGeneral,HOL-FooCommand.gz}`"} |
678 `$ISABELLE_LOGS/{Pure.gz,HOL.gz,Pure-ProofGeneral,HOL-FooCommand.gz}`"} |
643 |
679 |
644 The result is the file @{text "isar-keywords-foo.el"}, which needs to be |
680 The result is the file @{text "isar-keywords-foo.el"}, which needs to be |
645 copied in the directory @{text "~/.isabelle/etc"}. To make Isabelle use |
681 copied to the directory @{text "~/.isabelle/etc"}. To make Isabelle use |
646 this keyword file, we need to start it with the option @{text "-k foo"}: |
682 this keyword file, we need to start it with the option @{text "-k foo"}, i.e. |
647 |
683 |
648 @{text [display] "isabelle -k foo a-theory-file"} |
684 @{text [display] "isabelle -k foo <a-theory-file>"} |
649 |
685 |
650 If we now run the original code creating the command |
686 If we now run the original code |
651 |
687 |
652 @{ML [display] |
688 @{ML [display] |
653 "let |
689 "let |
654 val do_nothing = Scan.succeed (Toplevel.theory (fn x => x)) |
690 val do_nothing = Scan.succeed (Toplevel.theory (fn x => x)) |
655 val flag = OuterKeyword.thy_decl |
691 val flag = OuterKeyword.thy_decl |