| 1 | (******************************************************************************* |
|---|
| 2 | Copyright 2009 Sun Microsystems, Inc., |
|---|
| 3 | 4150 Network Circle, Santa Clara, California 95054, U.S.A. |
|---|
| 4 | All rights reserved. |
|---|
| 5 | |
|---|
| 6 | U.S. Government Rights - Commercial software. |
|---|
| 7 | Government users are subject to the Sun Microsystems, Inc. standard |
|---|
| 8 | license agreement and applicable provisions of the FAR and its supplements. |
|---|
| 9 | |
|---|
| 10 | Use is subject to license terms. |
|---|
| 11 | |
|---|
| 12 | This distribution may include materials developed by third parties. |
|---|
| 13 | |
|---|
| 14 | Sun, Sun Microsystems, the Sun logo and Java are trademarks or registered |
|---|
| 15 | trademarks of Sun Microsystems, Inc. in the U.S. and other countries. |
|---|
| 16 | ******************************************************************************) |
|---|
| 17 | |
|---|
| 18 | component Cfa |
|---|
| 19 | import List.{...} |
|---|
| 20 | import Map.{...} |
|---|
| 21 | import Set.{...} |
|---|
| 22 | import Syntax.{...} |
|---|
| 23 | import DynamicSemantics.{...} |
|---|
| 24 | import System.{args} |
|---|
| 25 | export Executable |
|---|
| 26 | |
|---|
| 27 | (* Control flow analysis helper table ******************************************) |
|---|
| 28 | (* function name |-> function id *) |
|---|
| 29 | fids : Map[\String, ZZ32\] := {[\String, ZZ32\]} |
|---|
| 30 | (* function id |-> function declaration *) |
|---|
| 31 | fdecls: Map[\ZZ32, FnDecl\] := {[\ZZ32, FnDecl\]} |
|---|
| 32 | (* function id |-> function expression *) |
|---|
| 33 | fexprs: Map[\ZZ32, FnExpr\] := {[\ZZ32, FnExpr\]} |
|---|
| 34 | (* function id |-> function body *) |
|---|
| 35 | bodies: Map[\ZZ32, Expr\] := {[\ZZ32, Expr\]} |
|---|
| 36 | (* function id |-> parameter name *) |
|---|
| 37 | params: Map[\ZZ32, String\] := {[\ZZ32, String\]} |
|---|
| 38 | emptySet: Set[\ZZ32\] = set[\ZZ32\]() |
|---|
| 39 | |
|---|
| 40 | (* For a given function id, |
|---|
| 41 | returns the corresponding function declaration or function expression. |
|---|
| 42 | *) |
|---|
| 43 | fidToFunction(id: ZZ32) = |
|---|
| 44 | if fd <- fdecls.member(id) |
|---|
| 45 | then fd |
|---|
| 46 | else if f <- fexprs.member(id) |
|---|
| 47 | then f |
|---|
| 48 | else throw FailCalled("Function not found: " id) |
|---|
| 49 | end |
|---|
| 50 | end |
|---|
| 51 | |
|---|
| 52 | (* Initialize the helper tables before analyzing the program *******************) |
|---|
| 53 | init() = do |
|---|
| 54 | atomic cfa_eqns := {[\ZZ32, Set[\ZZ32\]\]} |
|---|
| 55 | atomic new_eqn := true |
|---|
| 56 | atomic iteration:= 0 |
|---|
| 57 | atomic fids := {[\String, ZZ32\]} |
|---|
| 58 | atomic fdecls := {[\ZZ32, FnDecl\]} |
|---|
| 59 | atomic fexprs := {[\ZZ32, FnExpr\]} |
|---|
| 60 | atomic bodies := {[\ZZ32, Expr\]} |
|---|
| 61 | atomic params := {[\ZZ32, String\]} |
|---|
| 62 | end |
|---|
| 63 | |
|---|
| 64 | init(p: Program) = do |
|---|
| 65 | init() |
|---|
| 66 | initSyntax() |
|---|
| 67 | initDynamic() |
|---|
| 68 | init(fd), fd <- p.decls |
|---|
| 69 | init(p.expr) |
|---|
| 70 | end |
|---|
| 71 | |
|---|
| 72 | (* For each function declaration, |
|---|
| 73 | add the following mappings to the tables: |
|---|
| 74 | function name |-> function id |
|---|
| 75 | function id |-> function declaration |
|---|
| 76 | function id |-> function body |
|---|
| 77 | function id |-> parameter name |
|---|
| 78 | and initialize the helper tables from the function body |
|---|
| 79 | *) |
|---|
| 80 | init(fd: FnDecl) = do |
|---|
| 81 | id = fd.getId() |
|---|
| 82 | atomic fids := fids.add(fd.name, id) |
|---|
| 83 | atomic fdecls := fdecls.add(id, fd) |
|---|
| 84 | atomic params := params.add(id, fd.param) |
|---|
| 85 | atomic bodies := bodies.add(id, fd.body) |
|---|
| 86 | init(fd.body) |
|---|
| 87 | end |
|---|
| 88 | |
|---|
| 89 | (* Var, True, and False do nothing. *) |
|---|
| 90 | init(e: Expr) = () |
|---|
| 91 | |
|---|
| 92 | (* For each function expression, |
|---|
| 93 | add the following mappings to the tables: |
|---|
| 94 | function id |-> function expression |
|---|
| 95 | function id |-> function body |
|---|
| 96 | function id |-> parameter name |
|---|
| 97 | and initialize the helper tables from the function body |
|---|
| 98 | *) |
|---|
| 99 | init(e: FnExpr) = do |
|---|
| 100 | id = e.getId() |
|---|
| 101 | atomic fexprs := fexprs.add(id, e) |
|---|
| 102 | atomic params := params.add(id, e.param) |
|---|
| 103 | atomic bodies := bodies.add(id, e.body) |
|---|
| 104 | init(e.body) |
|---|
| 105 | end |
|---|
| 106 | |
|---|
| 107 | (* For each application expression, |
|---|
| 108 | initialize the helper tables from its subexpressions. |
|---|
| 109 | *) |
|---|
| 110 | init(e: App) = do _ = (init(e.function), init(e.argument)) end |
|---|
| 111 | |
|---|
| 112 | (* For each if expression, |
|---|
| 113 | initialize the helper tables from its subexpressions. |
|---|
| 114 | *) |
|---|
| 115 | init(e: If) = do _ = (init(e.cond), init(e.thenB), init(e.elseB)) end |
|---|
| 116 | |
|---|
| 117 | (* Debugging *******************************************************************) |
|---|
| 118 | debug: Boolean := false |
|---|
| 119 | indent = " " |
|---|
| 120 | |
|---|
| 121 | (* print the helper tables *****************************************************) |
|---|
| 122 | dumpHelperTables() = |
|---|
| 123 | if debug |
|---|
| 124 | then |
|---|
| 125 | println "(* print the helper tables ***************************************)" |
|---|
| 126 | println "(* fids : function name |-> function id *)" |
|---|
| 127 | println fids// |
|---|
| 128 | println "(* fdecls: function id |-> function declaration *)" |
|---|
| 129 | println fdecls// |
|---|
| 130 | println "(* bodies: function id |-> function body *)" |
|---|
| 131 | println bodies// |
|---|
| 132 | println "(* params: function id |-> parameter name *)" |
|---|
| 133 | println params// |
|---|
| 134 | end |
|---|
| 135 | |
|---|
| 136 | (* print the equation tables ***************************************************) |
|---|
| 137 | dumpEquationsTables() = |
|---|
| 138 | if debug |
|---|
| 139 | then |
|---|
| 140 | println "(* print the equation tables *************************************)" |
|---|
| 141 | println "(* cfa_eqns: function id |-> { function id } *)" |
|---|
| 142 | println (indent "{") |
|---|
| 143 | println (indent indent cfa_eqn), cfa_eqn <- cfa_eqns |
|---|
| 144 | println (indent "}")// |
|---|
| 145 | end |
|---|
| 146 | |
|---|
| 147 | (* Control flow analysis table *************************************************) |
|---|
| 148 | (* function id |-> { function id } *) |
|---|
| 149 | cfa_eqns: Map[\ZZ32, Set[\ZZ32\]\] := {[\ZZ32, Set[\ZZ32\]\]} |
|---|
| 150 | new_eqn: Boolean := true |
|---|
| 151 | |
|---|
| 152 | (* Add a (id, s) pair to the cfa_eqns table. *) |
|---|
| 153 | add(id: ZZ32, s: Set[\ZZ32\]) = do |
|---|
| 154 | if debug then println("add(" id ", " s ")") end |
|---|
| 155 | atomic cfa_eqns := cfa_eqns.add(id, s) |
|---|
| 156 | end |
|---|
| 157 | |
|---|
| 158 | (* Map id to s. *) |
|---|
| 159 | update(id: ZZ32, s: Set[\ZZ32\]) = do |
|---|
| 160 | if debug then println("update(" id ", " s ")") end |
|---|
| 161 | atomic cfa_eqns := cfa_eqns.update(id, s) |
|---|
| 162 | end |
|---|
| 163 | |
|---|
| 164 | (* Build control flow equations in the cfa_eqns table. *************************) |
|---|
| 165 | iteration: ZZ32 := 0 |
|---|
| 166 | (* Build equations from the function declarations and the body expression. |
|---|
| 167 | Repeat it until no new equation is generated. |
|---|
| 168 | *) |
|---|
| 169 | buildEquations(p: Program) = do |
|---|
| 170 | while new_eqn do |
|---|
| 171 | atomic iteration += 1 |
|---|
| 172 | if debug then println("(* buildEquations iteration: " iteration |
|---|
| 173 | " ****************)") end |
|---|
| 174 | atomic new_eqn := false |
|---|
| 175 | buildEquations(fd), fd <- p.decls |
|---|
| 176 | buildEquations(p.expr) |
|---|
| 177 | if debug then println "" end |
|---|
| 178 | end |
|---|
| 179 | end |
|---|
| 180 | |
|---|
| 181 | (* For each function declaration, |
|---|
| 182 | add the following equation into the cfa_eqns table: |
|---|
| 183 | |
|---|
| 184 | its_function_id CONTAINS its_function_id |
|---|
| 185 | |
|---|
| 186 | and build equations from its body expression. |
|---|
| 187 | *) |
|---|
| 188 | buildEquations(fd: FnDecl) = do |
|---|
| 189 | addEquation(fd.getId()) |
|---|
| 190 | buildEquations(fd.body) |
|---|
| 191 | end |
|---|
| 192 | |
|---|
| 193 | (* For each expression, |
|---|
| 194 | build equations into the cfa_eqns table. |
|---|
| 195 | True and False do not generate any equations. |
|---|
| 196 | *) |
|---|
| 197 | buildEquations(e: Expr) = () |
|---|
| 198 | |
|---|
| 199 | (* For each function expression, |
|---|
| 200 | add the following equation into the cfa_eqns table: |
|---|
| 201 | |
|---|
| 202 | its_function_id CONTAINS its_function_id |
|---|
| 203 | |
|---|
| 204 | and build equations from its body expression. |
|---|
| 205 | *) |
|---|
| 206 | buildEquations(e: FnExpr) = do |
|---|
| 207 | addEquation(e.getId()) |
|---|
| 208 | buildEquations(e.body) |
|---|
| 209 | end |
|---|
| 210 | |
|---|
| 211 | (* For each named function, |
|---|
| 212 | add the following equation into the cfa_eqns table: |
|---|
| 213 | |
|---|
| 214 | the_variable_id CONTAINS its_function_id |
|---|
| 215 | *) |
|---|
| 216 | buildEquations(e: Var) = |
|---|
| 217 | if id <- fids.member(e.name) |
|---|
| 218 | then addEquation(e.id, { id }) |
|---|
| 219 | end |
|---|
| 220 | |
|---|
| 221 | (* For each if expression, |
|---|
| 222 | if its 'then' branch has a set of function ids, s, in the cfa_eqns table |
|---|
| 223 | then if its else branch has a set of function ids, s', |
|---|
| 224 | then add the following equation into the cfa_eqns table: |
|---|
| 225 | |
|---|
| 226 | the_if_expression_id INCLUDES s UNION s' |
|---|
| 227 | |
|---|
| 228 | else add the following equation into the cfa_eqns table: |
|---|
| 229 | |
|---|
| 230 | the_if_expression_id INCLUDES s |
|---|
| 231 | |
|---|
| 232 | else if its 'else' branch has a set of function ids, s', |
|---|
| 233 | then add the following equation into the cfa_eqns table: |
|---|
| 234 | |
|---|
| 235 | the_if_expression_id INCLUDES s' |
|---|
| 236 | |
|---|
| 237 | and build equations from its "then" and "else" branches. |
|---|
| 238 | *) |
|---|
| 239 | buildEquations(e: If) = do |
|---|
| 240 | _ = (buildEquations(e.thenB), buildEquations(e.elseB)) |
|---|
| 241 | |
|---|
| 242 | id = e.getId() |
|---|
| 243 | if s <- cfa_eqns.member(e.thenB.getId()) |
|---|
| 244 | then if s' <- cfa_eqns.member(e.elseB.getId()) |
|---|
| 245 | then addEquation(id, s UNION s') |
|---|
| 246 | else addEquation(id, s) |
|---|
| 247 | end |
|---|
| 248 | else if s' <- cfa_eqns.member(e.elseB.getId()) |
|---|
| 249 | then addEquation(id, s') |
|---|
| 250 | end |
|---|
| 251 | end |
|---|
| 252 | end |
|---|
| 253 | |
|---|
| 254 | (* There are two kinds of equation building in this function: |
|---|
| 255 | |
|---|
| 256 | For each function application, e1 e2, |
|---|
| 257 | if e1 has a set of function ids, ftns, in the cfa_eqns table |
|---|
| 258 | then for each function ftn in ftns |
|---|
| 259 | if ftn's body has a set of function ids, ftns' in the cfa_eqns table |
|---|
| 260 | then add the following equation into the cfa_eqns table: |
|---|
| 261 | |
|---|
| 262 | the_appication_id INCLUDES ftns' |
|---|
| 263 | |
|---|
| 264 | For each function application e1 e2, |
|---|
| 265 | if e1 has a set of function ids, ftns, in the cfa_eqns table |
|---|
| 266 | then for each function ftn in ftns and its parameter x |
|---|
| 267 | if e2 has a set of function ids, ftns', in the cfa_eqns table |
|---|
| 268 | then add the following equation into the cfa_eqns table: |
|---|
| 269 | |
|---|
| 270 | x's_id INCLUDES ftns' |
|---|
| 271 | |
|---|
| 272 | and build equations from its "then" and "else" branches. |
|---|
| 273 | *) |
|---|
| 274 | buildEquations(e: App) = do |
|---|
| 275 | e1 = e.function |
|---|
| 276 | e2 = e.argument |
|---|
| 277 | |
|---|
| 278 | if debug |
|---|
| 279 | then println("App(" e.getId() ", " e1.getId() ", " e2.getId() ") = " e) |
|---|
| 280 | end |
|---|
| 281 | |
|---|
| 282 | _ = (buildEquations(e1), buildEquations(e2)) |
|---|
| 283 | |
|---|
| 284 | if ftns <- cfa_eqns.member(e1.getId()) |
|---|
| 285 | then for ftn <- ftns do |
|---|
| 286 | if ftns' <- cfa_eqns.member(bodies[ftn].getId()) |
|---|
| 287 | then addEquation(e.getId(), ftns') |
|---|
| 288 | end |
|---|
| 289 | |
|---|
| 290 | if ftns' <- cfa_eqns.member(e2.getId()) |
|---|
| 291 | then addEquation(x, ftns'), x <- collectVars(params[ftn], bodies[ftn]) |
|---|
| 292 | end |
|---|
| 293 | end |
|---|
| 294 | end |
|---|
| 295 | end |
|---|
| 296 | |
|---|
| 297 | (* Collect a set of variable ids of the given name in a given expression *******) |
|---|
| 298 | (* There are no variables in True and False *) |
|---|
| 299 | collectVars(name: String, e: Expr) = emptySet |
|---|
| 300 | |
|---|
| 301 | (* If a variable has the same name as the given name |
|---|
| 302 | then returns a singleton set of the variable's id |
|---|
| 303 | else returns an empty set |
|---|
| 304 | *) |
|---|
| 305 | collectVars(name: String, e: Var) = |
|---|
| 306 | if name = e.name then { e.getId() } else emptySet end |
|---|
| 307 | |
|---|
| 308 | (* If a function expression's parameter has the same name as the given name |
|---|
| 309 | then returns an empty set |
|---|
| 310 | else returns a set of variable ids of the given name in the function body |
|---|
| 311 | *) |
|---|
| 312 | collectVars(name: String, e: FnExpr) = |
|---|
| 313 | if name = e.param then emptySet else collectVars(name, e.body) end |
|---|
| 314 | |
|---|
| 315 | (* For an function application expression |
|---|
| 316 | collect a set of variable ids of the given name |
|---|
| 317 | in its function and argument expressions. |
|---|
| 318 | *) |
|---|
| 319 | collectVars(name: String, e: App) = |
|---|
| 320 | collectVars(name, e.function) UNION collectVars(name, e.argument) |
|---|
| 321 | |
|---|
| 322 | (* For an if expression |
|---|
| 323 | collect a set of variable ids of the given name |
|---|
| 324 | in its true and false branches. |
|---|
| 325 | *) |
|---|
| 326 | collectVars(name: String, e: If) = |
|---|
| 327 | collectVars(name, e.thenB) UNION collectVars(name, e.elseB) |
|---|
| 328 | |
|---|
| 329 | (* Add control flow equations into the cfa_eqns table. *************************) |
|---|
| 330 | (* For a given function id, |
|---|
| 331 | if there exists an equation: |
|---|
| 332 | |
|---|
| 333 | the_function_id INCLUDES function_ids_set |
|---|
| 334 | |
|---|
| 335 | then if the function id is in the function_ids_set |
|---|
| 336 | then new equation is not generated. |
|---|
| 337 | else update the equation as follows: |
|---|
| 338 | |
|---|
| 339 | the_function_id INCLUDES the_function_id UNION { the_function_id } |
|---|
| 340 | |
|---|
| 341 | else add the following equation into the cfa_eqns table: |
|---|
| 342 | |
|---|
| 343 | the_function_id CONTAINS the_function_id |
|---|
| 344 | |
|---|
| 345 | if a new equation is generated, set the new_eqn flag. |
|---|
| 346 | *) |
|---|
| 347 | addEquation(id: ZZ32) = |
|---|
| 348 | if fids' <- cfa_eqns.member(id) |
|---|
| 349 | then if NOT(id IN fids') |
|---|
| 350 | then atomic update(id, fids' UNION {[\ZZ32\]id}) |
|---|
| 351 | atomic new_eqn := true |
|---|
| 352 | end |
|---|
| 353 | else atomic add(id, {[\ZZ32\]id}) |
|---|
| 354 | atomic new_eqn := true |
|---|
| 355 | end |
|---|
| 356 | |
|---|
| 357 | (* For a given function id, 'id' and a set of function ids, 's', |
|---|
| 358 | if there exists an equation: |
|---|
| 359 | |
|---|
| 360 | id INCLUDES s' |
|---|
| 361 | |
|---|
| 362 | then if s is a subset or equal to s' |
|---|
| 363 | then new equation is not generated. |
|---|
| 364 | else update the equation as follows: |
|---|
| 365 | |
|---|
| 366 | id INCLUDES s UNION s' |
|---|
| 367 | |
|---|
| 368 | else add the following equation into the cfa_eqns table: |
|---|
| 369 | |
|---|
| 370 | id INCLUDES s |
|---|
| 371 | |
|---|
| 372 | if a new equation is generated, set the new_eqn flag. |
|---|
| 373 | *) |
|---|
| 374 | addEquation(id: ZZ32, s: Set[\ZZ32\]) = |
|---|
| 375 | if s' <- cfa_eqns.member(id) |
|---|
| 376 | then if NOT(s SUBSETEQ s') |
|---|
| 377 | then atomic update(id, s UNION s') |
|---|
| 378 | atomic new_eqn := true |
|---|
| 379 | end |
|---|
| 380 | else atomic add(id, s) |
|---|
| 381 | atomic new_eqn := true |
|---|
| 382 | end |
|---|
| 383 | (* '*) |
|---|
| 384 | |
|---|
| 385 | (* Control flow analysis main engin ********************************************) |
|---|
| 386 | cfa(p: Program) = do |
|---|
| 387 | init(p) |
|---|
| 388 | dumpHelperTables() |
|---|
| 389 | buildEquations(p) |
|---|
| 390 | dumpEquationsTables() |
|---|
| 391 | if result <- cfa_eqns.member(p.expr.getId()) |
|---|
| 392 | then result |
|---|
| 393 | else emptySet |
|---|
| 394 | end |
|---|
| 395 | end |
|---|
| 396 | |
|---|
| 397 | (* Driver of the control flow analysis for a program *) |
|---|
| 398 | doit(p: Program) = do |
|---|
| 399 | (* controfl flow analysis ****************************************************) |
|---|
| 400 | cfa_result = cfa(p) |
|---|
| 401 | |
|---|
| 402 | (* print the result **********************************************************) |
|---|
| 403 | println "Test Program:" |
|---|
| 404 | if debug |
|---|
| 405 | then println (p.asString)// |
|---|
| 406 | else println (p.toSource())// |
|---|
| 407 | end |
|---|
| 408 | |
|---|
| 409 | println "Evaluated value:" |
|---|
| 410 | result = (VDASH p).getValue() |
|---|
| 411 | if debug |
|---|
| 412 | then println (indent result.asString)// |
|---|
| 413 | else println (indent result.toSource())// |
|---|
| 414 | end |
|---|
| 415 | |
|---|
| 416 | println "Control flow analysis result with " iteration " iterations:" |
|---|
| 417 | println (indent "{") |
|---|
| 418 | println (indent indent (fidToFunction(fid).toSource())), fid <- cfa_result |
|---|
| 419 | println (indent "}")// |
|---|
| 420 | end |
|---|
| 421 | |
|---|
| 422 | (* test programs ***************************************************************) |
|---|
| 423 | (* test program 1 *) |
|---|
| 424 | test1() = do |
|---|
| 425 | println "(* Test program 1 **************************************************)" |
|---|
| 426 | (* f(x) = x |
|---|
| 427 | g(y) = f(y) |
|---|
| 428 | h(z) = f(z) |
|---|
| 429 | if f(true) then g(fn x => x) else h(fn y => false) end |
|---|
| 430 | *) |
|---|
| 431 | fd = FnDecl("f", "x", Var("x")) |
|---|
| 432 | gd = FnDecl("g", "y", App(Var("f"), Var("y"))) |
|---|
| 433 | hd = FnDecl("h", "z", App(Var("f"), Var("z"))) |
|---|
| 434 | fds = <|fd, gd, hd|> |
|---|
| 435 | body = If(App(Var("f"), False), |
|---|
| 436 | App(Var("g"), FnExpr("x", Var("x"))), |
|---|
| 437 | App(Var("h"), FnExpr("y", False))) |
|---|
| 438 | Program(fds, body) |
|---|
| 439 | end |
|---|
| 440 | |
|---|
| 441 | (* test program 2 *) |
|---|
| 442 | test2() = do |
|---|
| 443 | println "(* Test program 2 **************************************************)" |
|---|
| 444 | (* f(x) = true |
|---|
| 445 | g(y) = false |
|---|
| 446 | h(z) = if z then f else g end |
|---|
| 447 | (h(true)) false |
|---|
| 448 | *) |
|---|
| 449 | fd = FnDecl("f", "x", True) |
|---|
| 450 | gd = FnDecl("g", "y", False) |
|---|
| 451 | hd = FnDecl("h", "z", If(Var("z"), Var("f"), Var("g"))) |
|---|
| 452 | fds = <|fd, gd, hd|> |
|---|
| 453 | body = App(App(Var("h"), True), False) |
|---|
| 454 | Program(fds, body) |
|---|
| 455 | end |
|---|
| 456 | |
|---|
| 457 | (* test program 3 *) |
|---|
| 458 | test3() = do |
|---|
| 459 | println "(* Test program 3 **************************************************)" |
|---|
| 460 | (* f_0(x) = x |
|---|
| 461 | ... |
|---|
| 462 | f_n(x) = f_{n-1}(x) |
|---|
| 463 | f_n(fn y => false) |
|---|
| 464 | *) |
|---|
| 465 | n = 50 |
|---|
| 466 | fd0 = FnDecl("f_0", "x", Var("x")) |
|---|
| 467 | fds = <| FnDecl("f_" i, "x", App(Var("f_" (i-1)), Var("x"))) | i <- 1:n |>.addLeft(fd0) |
|---|
| 468 | body = App(Var("f_" n), FnExpr("y", False)) |
|---|
| 469 | Program(fds, body) |
|---|
| 470 | end |
|---|
| 471 | |
|---|
| 472 | (* Run test programs. *) |
|---|
| 473 | tests() = do |
|---|
| 474 | doit(test1()) |
|---|
| 475 | doit(test2()) |
|---|
| 476 | recordTime(6.847) |
|---|
| 477 | doit(test3()) |
|---|
| 478 | printTime(6.847) |
|---|
| 479 | end |
|---|
| 480 | |
|---|
| 481 | printUsage() = println "Usage: fortress Cfa.fss [-[-]debug]" |
|---|
| 482 | |
|---|
| 483 | run() = |
|---|
| 484 | if |args| > 1 |
|---|
| 485 | then printUsage() |
|---|
| 486 | else if |args| = 1 |
|---|
| 487 | then if args[0] = "-debug" OR args[0] = "--debug" |
|---|
| 488 | then debug := true |
|---|
| 489 | tests() |
|---|
| 490 | else printUsage() |
|---|
| 491 | end |
|---|
| 492 | else tests() |
|---|
| 493 | end |
|---|
| 494 | end |
|---|
| 495 | |
|---|
| 496 | end |
|---|