diff options
Diffstat (limited to 'src/safePrinter.ml')
-rw-r--r-- | src/safePrinter.ml | 274 |
1 files changed, 274 insertions, 0 deletions
diff --git a/src/safePrinter.ml b/src/safePrinter.ml new file mode 100644 index 0000000..2ca778a --- /dev/null +++ b/src/safePrinter.ml @@ -0,0 +1,274 @@ +(***************************************************************************) +(* Morsmall *) +(* A concise AST for POSIX shell *) +(* *) +(* Copyright (C) 2017,2018,2019 Yann RĂ©gis-Gianas, Ralf Treinen, *) +(* Nicolas Jeannerod *) +(* *) +(* This program 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 3 of the License, or *) +(* (at your option) any later version. *) +(* *) +(* This program 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. *) +(* *) +(* You should have received a copy of the GNU General Public License *) +(* along with this program. If not, see <http://www.gnu.org/licenses/>. *) +(***************************************************************************) + +let fpf = Format.fprintf +open AST + +(* AST.name *) + +let rec pp_name ppf = + fpf ppf "%s" + +(* AST.word_component *) + +and pp_word_component ppf = function (*FIXME*) + | WLiteral literal -> + fpf ppf "%s" literal + | WTildePrefix _ -> + assert false + | WDoubleQuoted _word -> + assert false + | WVariable (variable, attribute) -> + assert (attribute = NoAttribute); + fpf ppf "${%s}" variable + | WSubshell command_list -> + fpf ppf "$(%a)" pp_command'_list command_list + | WGlobAll -> + fpf ppf "*" + | WGlobAny -> + fpf ppf "?" + | WBracketExpression _bracket_expression -> + assert false + +(* AST.word *) + +and pp_word ppf = function + | [] -> assert false + | [e] -> pp_word_component ppf e + | h :: q -> fpf ppf "%a%a" pp_word_component h pp_word q + +and pp_word' ppf word' = + Location.on_located (pp_word ppf) word' + +and pp_words ppf = function + | [] -> () + | [word] -> + pp_word ppf word + | word :: words -> + fpf ppf "%a %a" + pp_word word + pp_words words + +and pp_words' ppf = function + | [] -> () + | [word'] -> + pp_word' ppf word' + | word' :: words' -> + fpf ppf "%a %a" + pp_word' word' + pp_words' words' + +(* AST.pattern *) + +and pp_pattern ppf = function + | [] -> () + | [word] -> + pp_word ppf word + | word :: pattern -> + fpf ppf "%a|%a" + pp_word word + pp_pattern pattern + +and pp_pattern' ppf pattern' = + Location.on_located (pp_pattern ppf) pattern' + +(* AST.assignement *) + +and pp_assignment ppf (variable, word) = + fpf ppf "%a=%a" + pp_name variable + pp_word word + +and pp_assignment' ppf assignment' = + Location.on_located (pp_assignment ppf) assignment' + +and pp_assignments ppf = function + | [] -> () + | [assignment] -> + pp_assignment ppf assignment + | assignment :: assignments -> + fpf ppf "%a %a" + pp_assignment assignment + pp_assignments assignments + +and pp_assignments' ppf = function + | [] -> () + | [assignment'] -> + pp_assignment' ppf assignment' + | assignment' :: assignments' -> + fpf ppf "%a %a" + pp_assignment' assignment' + pp_assignments' assignments' + +and pp_redirection_kind ppf k = + fpf ppf "%s" + (match k with + | Input -> "<" | InputDuplicate -> "<&" + | Output -> ">" | OutputDuplicate -> ">&" | OutputAppend -> ">>" + | InputOutput -> "<>" | OutputClobber -> ">|") + +(* AST.program *) + +and pp_program ppf = function + | [] -> () + | [command'] -> + pp_command' ppf command' + | command' :: program -> + fpf ppf "%a@\n%a" + pp_command' command' + pp_program program + +(* AST.command *) + +and pp_command ppf (command : command) = + fpf ppf "{ "; + ( + match command with + + | Async command -> + pp_command ppf command + + | Seq (command1, command2) -> + fpf ppf "%a;%a" + pp_command' command1 + pp_command' command2 + + | And (command1, command2) -> + fpf ppf "%a&&%a" + pp_command' command1 + pp_command' command2 + + | Or (command1, command2) -> + fpf ppf "%a||%a" + pp_command' command1 + pp_command' command2 + + | Not command -> + fpf ppf "! %a" + pp_command' command + + | Pipe (command1, command2) -> + fpf ppf "%a|%a" + pp_command' command1 + pp_command' command2 + + | Subshell command -> + fpf ppf "(%a)" + pp_command' command + + | If (test, body, None) -> + fpf ppf "if %a;then %a;fi" + pp_command' test + pp_command' body + + | If (test, body, Some rest) -> + fpf ppf "if %a;then %a;else %a;fi" + pp_command' test + pp_command' body + pp_command' rest + + | For (variable, None, body) -> + fpf ppf "for %a;do %a;done" + pp_name variable + pp_command' body + + | For (variable, Some words, body) -> + fpf ppf "for %a in %a;do %a;done" + pp_name variable + pp_words words + pp_command' body + + | Case (word, items) -> + fpf ppf "case %a in" pp_word word; + List.iter + (fun item -> + match item.Location.value with + | (pattern, None) -> + fpf ppf " %a) ;;" pp_pattern' pattern + | (pattern, Some body') -> + fpf ppf " %a) %a;;" pp_pattern' pattern pp_command' body') + items; + fpf ppf " esac" + + | While (test, body) -> + fpf ppf "while %a;do %a;done" + pp_command' test + pp_command' body + + | Until (test, body) -> + fpf ppf "until %a;do %a;done" + pp_command' test + pp_command' body + + | Function (name, body) -> + fpf ppf "%a()%a" + pp_name name + pp_command' body + + | Simple ([], []) -> + failwith "SafePrinter.pp_command': ill-formed command: Simple([], [])" + | Simple ([], words) -> + fpf ppf "%a" pp_words' words + | Simple (assignments, words) -> + fpf ppf "%a %a" + pp_assignments' assignments + pp_words' words + + | Redirection (command, descr, kind, file) -> + (* The space is required because "the [descriptor] must be delimited from any preceding text". *) + fpf ppf "%a %d%a%a" + pp_command' command + descr + pp_redirection_kind kind + pp_word file + + | HereDocument (command, descr, content) -> + (* if content.value.[String.length content.value - 1] <> '\n' then + * failwith "SafePrinter.pp_command': ill-formed here-document: the content must end with a newline"; *) (*FIXME*) + let eof = "EOF" in (*FIXME*) + fpf ppf "%a %d<<%s\n%a%s\n" + pp_command' command + descr + eof + pp_word' content + eof + ); + fpf ppf "%s}" (match command with Async _ -> "&" | HereDocument _ -> "" | _ -> ";") + +and pp_command' ppf command' = + Location.on_located (pp_command ppf) command' + +and pp_command_list ppf = function + | [] -> () + | [command] -> + pp_command ppf command + | command :: command_list -> + fpf ppf "%a@\n%a" + pp_command command + pp_command_list command_list + +and pp_command'_list ppf = function + | [] -> () + | [command'] -> pp_command' ppf command' + | command' :: command'_list -> + fpf ppf "%a@\n%a" + pp_command' command' + pp_command'_list command'_list |