[/] [trunk/] [src/] [urpal.sml] - Blame information for rev 65

Line No. Rev Author Line
1 62 tbourke
(* $Id: urpal.sml 65 2008-08-25 22:47:20Z tbourke $
2
 *
3
 * Copyright (c) 2008 Timothy Bourke (University of NSW and NICTA)
4
 * All rights reserved.
5
 *
6
 * This program is free software; you can redistribute it and/or modify it
7
 * under the terms of the "BSD License" which is distributed with the
8
 * software in the file LICENSE.
9
 *
10
 * This program is distributed in the hope that it will be useful, but
11
 * WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the BSD
13
 * License for more details.
14
 *)
15 4 tbourke
 
16
structure Urpal :
17
sig
18
  val main : string * string list -> OS.Process.status
19
  val run: string -> OS.Process.status
20
end
21
=
22
let structure UP  = UppaalParse
23
          and UXML = UppaalXML
24
          and TIO  = TextIO
25
          and CMD  = Commands
26
in
27
  struct
28
  exception FailedCommand
29
        and NoInputFile
30
 
31
  fun abort ss = let in
32
      TIO.output (TIO.stdErr, String.concat (Settings.progName::":"::ss));
33
      TIO.output (TIO.stdErr, "\n");
34
      raise FailedCommand
35
    end
36
 
37
  fun readNta filename = let
38
      val uri = Uri.String2Uri filename
39
    in case UXML.parse uri
40
       of NONE      => abort [filename,
41
                          " is not a valid XML file or the dtd is invalid."]
42
        | SOME xnta => UP.parse (xnta, filename)
43
    end
44
 
45
  fun writeNta (filename, nta) = let
46
      fun makeStream (s, c) = (TIO.getOutstream s, c)
47
      val (strm, close) = makeStream (case filename of
48
                             NONE   => (TIO.stdOut, fn _=>())
49
                           | SOME n => (TIO.openOut n, TIO.StreamIO.closeOut))
50
    in ParsedNta.output strm nta; close strm end
51
    handle IO.Io {cause,...} => (Util.warn ["failed to write nta (",
52
                                            General.exnMessage cause, ")"])
53
                                before (raise FailedCommand)
54
 
55
  fun tryConfigFiles () = let
56
      fun tryDir (NONE, _, _) = NONE
57
        | tryDir (SOME d, subs, f) = let
58
              val dir=foldl (fn(f,d)=>OS.Path.joinDirFile{dir=d,file=f}) d subs
59
            in SOME (OS.Path.joinDirFile {dir=dir, file=f}) end
60
 
61
      fun loadFile NONE = ()
62
        | loadFile (SOME path) = let
63
          val ()= Util.debugOutline (fn()=>["seeking config file ",path,"..."])
64
 
65
          val inso = SOME (TextIO.getInstream (TextIO.openIn path))
66
                     before Util.debugOutline (fn()=>["found"])
67
                     handle IO.Io {cause, ...} => NONE before
68
                       Util.debugOutline (fn()=>["not found (",
69
                                                 General.exnMessage cause,")"])
70
        in
71
          ignore (Option.map
72
                    (SettingsRW.loadConfigFile TextIO.StreamIO.inputLine) inso)
73
        end
74
 
75
    in
76
      app loadFile [tryDir (Settings.prefix (), ["etc"], "urpalrc"),
77
                    tryDir (OS.Process.getEnv "HOME", [], ".urpalrc"),
78
                    SOME "urpalrc"]
79
    end
80
 
81
  fun testFlip (NONE, _) = abort ["no input file specified"]
82
    | testFlip (SOME inf,NONE) = TestTransFlip.runTest {input=inf,
83
                                                        output=TextIO.stdOut}
84
    | testFlip (SOME inf,SOME outf) = (let
85
           val ostrm = TextIO.openOut outf
86
         in
87
           TestTransFlip.runTest {input=inf, output=ostrm};
88
           TextIO.closeOut ostrm;
89
           OS.Process.success
90
         end
91
         handle IO.Io {cause, ...} => (Util.warn
92
           ["cannot write to '", outf, "': ",
93
            General.exnMessage cause]; OS.Process.failure))
94
 
95
  fun main (name, args) = let
96 65 tbourke
      val _ = Util.debugIndent (Settings.Detailed,fn()=>["try config files..."])
97 4 tbourke
      val _ = tryConfigFiles ()
98 65 tbourke
      val _ = Util.debugOutdent (Settings.Detailed, fn()=>["done."])
99 4 tbourke
      val (cmds, {inputfile, outputfile}) = CMD.processCommands args
100
      val _ = Settings.validate ()
101 18 tbourke
      val freshEnv = SOME (CmdEnv.fromNta ParsedNta.emptyNta)
102 4 tbourke
 
103 18 tbourke
      fun doCmd (a as CMD.ScriptFile _, NONE)       = doCmd (a, freshEnv)
104 4 tbourke
        | doCmd (CMD.ScriptFile filename, SOME env) = let
105
              val ins = TextIO.openIn filename
106
            in
107
              CmdLang.parse TextIO.StreamIO.inputLine
108
                            (env, TextIO.getInstream ins)
109
            end
110
 
111 18 tbourke
        | doCmd (a as CMD.ScriptText _, NONE)       = doCmd (a, freshEnv)
112 4 tbourke
        | doCmd (CMD.ScriptText script, SOME env)   =
113
              CmdLang.parse (fn""=>NONE|s=>SOME(s,"")) (env, script)
114
 
115 18 tbourke
        | doCmd (a as CMD.ScriptTerminal, NONE)     = doCmd (a, freshEnv)
116 4 tbourke
        | doCmd (CMD.ScriptTerminal, SOME env)      = let
117
              fun getLine ins = (TextIO.print "> ";
118
                                 TextIO.StreamIO.inputLine ins)
119
            in
120
              CmdLang.parse getLine (env, TextIO.getInstream TextIO.stdIn)
121
            end
122
 
123
        | doCmd (CMD.ConfigFile p, envo) = (let
124
              val ins = TextIO.getInstream (TextIO.openIn p)
125
            in SettingsRW.loadConfigFile TextIO.StreamIO.inputLine ins;
126
               TextIO.StreamIO.closeIn ins;
127
               envo
128
            end
129
            handle IO.Io {cause, ...} => (Util.warn ["reading ",p," failed (",
130
                                            General.exnMessage cause, ")"];
131
                                          raise FailedCommand))
132
 
133
        | doCmd (CMD.ConfigText t, envo) = envo before
134
                SettingsRW.loadConfigFile (fn""=>NONE|s=>SOME(s,"")) t
135
 
136
        | doCmd (CMD.ShowConfig, envo)   = envo before
137
                                           Settings.saveConfigFile TextIO.stdOut
138
        | doCmd (CMD.TestFlip, _) = (Util.warn
139
                      ["The test flip command must be used by itself."];
140
                      raise FailedCommand)
141
 
142
    in
143
      case cmds of
144 18 tbourke
        [CMD.TestFlip] => testFlip (inputfile, outputfile)
145 4 tbourke
 
146
      | _ => let
147
               val ntao      = Option.mapPartial readNta inputfile
148
               val inputEnvo = Option.map CmdEnv.fromNta ntao
149
               val outputfile= if isSome outputfile then outputfile
150
                                                    else inputfile
151
             in
152
               case foldl doCmd inputEnvo cmds of
153
                 NONE     => OS.Process.success
154
               | SOME env => (writeNta (outputfile, CmdEnv.toNta env);
155
                                        OS.Process.success)
156
             end
157
    end
158
    handle FailedCommand => OS.Process.failure
159 55 tbourke
         | CmdLang.Failure => OS.Process.failure
160 4 tbourke
         | e => Util.abort ["uncaught exception:", General.exnMessage e]
161
 
162
    fun run args = main (Settings.progName, String.tokens Char.isSpace args)
163
 
164
  end
165
end
166