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

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