Advertisement
Guest User

Untitled

a guest
Jan 18th, 2018
110
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #!/home/jbw/jbw-cvs/bin/smlnj-script
  2. (*-*-SML-*-*) (* Tell Emacs to use SML mode even though name does not end with “.sml”. *)
  3. (* #!/usr/bin/env smlnj-script *) (* This is better 1st line if smlnj-script is in your PATH. *)
  4.  
  5. (* Author of template portion: Joe Wells *)
  6.  
  7. (**********************************************************************
  8.  * INSTRUCTIONS FOR USING THIS FILE:
  9.  *
  10.  * These instructions assume this file is named Xyzzy.  When reading
  11.  * these instructions, replace Xyzzy in your mind by the actual file
  12.  * name.
  13.  *
  14.  * This is an SML/NJ _*script*_.  You do not need to compile it.  It
  15.  * should be runnable as is.  This means if this file is in the
  16.  * current directory, you should be able to type ./Xyzzy at a shell
  17.  * command prompt and this program will run.  If you put this file in
  18.  * one of the directories listed in your PATH environment variable,
  19.  * then you can run this by just typing “Xyzzy”.
  20.  *
  21.  * There are a few things that can go wrong, and here is a short guide
  22.  * to how to fix them:
  23.  *
  24.  * 1. The permissions on this file might be wrong.  Do “chmod a+rx
  25.  *    Xyzzy” (assuming you own the file).
  26.  *
  27.  * 2. smlnj-script might not be installed anywhere on the computer you
  28.  *    are using.  Install it.
  29.  *
  30.  * 3. If the first line reads “#!/usr/bin/env smlnj-script”, then
  31.  *    “smlnj-script” might not be in any of the directories found via
  32.  *    your PATH environment variable.  Fix your PATH.
  33.  *
  34.  *    Alternatively, if the first line is of the form
  35.  *    “#!/directory/path/to/smlnj-script”, then the path
  36.  *    “/directory/path/to/smlnj-script” might be the wrong path to
  37.  *    smlnj-script.  Fix it.
  38.  *
  39.  * Fuller instructions for smlnj-script can be found in the README
  40.  * file in the smlnj-script git repository.  As of 2016-01, you can
  41.  * find a copy of this repository at
  42.  * /home/jbw/smlnj-script-git/smlnj-script on the UNIX NFS file
  43.  * systems of the Heriot-Watt University Computer Science department.
  44.  * Do “git clone
  45.  * ssh://MACHINE.macs.hw.ac.uk/~jbw/smlnj-script-git/smlnj-script”
  46.  * (where you must replace MACHINE by the name of some machine that
  47.  * works, e.g., linux01 worked for me) to get your own copy of this
  48.  * repository.
  49.  **********************************************************************)
  50.  
  51. (* *************************)
  52. (*** support for debugging *)
  53. (* *************************)
  54.  
  55. (* Comments that begin with “*SKALPEL-” help Skalpel, a tool for SML type errors. *)
  56. (* Semicolons after Skalpel magic comments are needed by Skalpel. *)
  57. (**SKALPEL-USE-FILE /home/jbw/smlnj-script-git/smlnj-script/smlnj-script.sml *);
  58.  
  59. (* structure U = SmlnjScriptUtils; *) (* Already in effect; uncomment to list what is available. *)
  60.  
  61. (* val () = U.raisePrintingLimitsToMax (); *) (* Uncomment to see into “...” in compiler message. *)
  62.  
  63. (* val () = U.interact (); *) (* Uncomment where you want to enter an interactive compiling mode. *)
  64.  
  65. val () = silenceCompiler ();
  66.  
  67. (* These two help you avoid shooting yourself in the foot. *)
  68. val () = Student.strongerPatternErrorsAndWarnings ();
  69. val () = Student.disableBadPartialFunctions ();
  70.  
  71. (* This helps you avoid getting a lower mark by violating the prohibition on string building. *)
  72. val () = Student.disableStringBuilding ();
  73.  
  74. val () = U.clearCompilerOutputStash ();
  75.  
  76. val () = unsilenceCompiler (); (* Comment when your script is finally completely working. *)
  77.  
  78. (* *********************************************************************)
  79. (*** utilities for processing mathematical definitions encoded in JSON *)
  80. (* *********************************************************************)
  81.  
  82. structure J = JSON;
  83.  
  84. (* The JSON structure represents JSON objects as association lists.  Parse results are not
  85. guaranteed to have object fields in any particular order.  Because this causes difficulty with
  86. pattern matching, the sortJsonFields function is used to sort the JSON object fields.  This also
  87. will help with detecting two fields with the same name (which I suspect the JSON structure
  88. allows). *)
  89. fun sortJsonFields fields =
  90.     ListMergeSort.sort (fn ((key1,value1),(key2,value2)) =>
  91.                            U.isGreater (String.compare (key1,key2)))
  92.                        fields;
  93.  
  94. (* Error exceptions have (string list) rather than string so as to abide by the prohibition of
  95. run-time string building *)
  96. exception BadJsonMath of J.value * (string list);
  97. exception BadVariableName of string list;
  98.  
  99. (* Identifies which operators are allowed and how many arguments each expects. *)
  100. val operatorArgSpecs =
  101.     List.concat
  102.         (map (fn (argSpec, operList) =>
  103.                  (map (fn oper => (oper, argSpec))
  104.                       operList))
  105.              [(SOME 1, ["domain", "inverse", "is-function"]),
  106.               (SOME 2, ["pair", "apply-function", "equal", "member", "set-difference", "union"]),
  107.               (SOME 4, ["diagonalize"]),
  108.               (NONE, ["set"])]);
  109.  
  110. (* Enforces the rules for valid variable names and converts them to integers. *)
  111. fun parseVariableName varName =
  112.     case String.explode varName
  113.      of #"x" :: #"0" :: _ :: _ =>
  114.         raise (BadVariableName ["purported variable name contains character(s) after x0: ",
  115.                                 varName])
  116.       | #"x" :: digits =>
  117.         foldl (fn (c as (#"0"|(#"1")|(#"2")|(#"3")|(#"4")|(#"5")|(#"6")|(#"7")|(#"8")|(#"9")),
  118.                    num : IntInf.int)
  119.                   => (num * 10) + (IntInf.fromInt (Char.ord c - Char.ord #"0"))
  120.               | _ =>
  121.                 raise (BadVariableName
  122.                            ["purported variable name contains non-digit after the first position: ",
  123.                             varName]))
  124.               (0 : IntInf.int)
  125.               digits
  126.       | _ :: _ => raise (BadVariableName ["purported variable name does not start with x: ",
  127.                                           varName])
  128.       | nil => raise (BadVariableName ["purported variable name is empty string"]);
  129.  
  130. (* Detects whether a JSON.value is a valid representation of a mathematical expression and if it
  131. is calls one of the 3 functions it is supplied for the different cases.  The “extra” parameter is
  132. way to get information to the 3 functions that might be different for this expression; this is an
  133. alternative to using mutable references or generating fresh functions. *)
  134. fun ('extra,'result)
  135.     caseJsonMathExp
  136.         {intFn : {extra : 'extra, int : IntInf.int}                           -> 'result,
  137.          opFn  : {extra : 'extra, op_name : string, arguments : J.value list} -> 'result,
  138.          varFn : {extra : 'extra, var_num : IntInf.int}                       -> 'result}
  139.         extra
  140.         j =
  141.     case j
  142.      of (J.INT i) => intFn {extra = extra, int = i}
  143.       | (J.OBJECT fields) =>
  144.         (case sortJsonFields fields
  145.           of [("variable", J.STRING varName)] =>
  146.              varFn {extra = extra, var_num = parseVariableName varName}
  147.            | [("variable", _)] =>
  148.              raise (BadJsonMath (j, ["JSON object does not represent a variable reference: ",
  149.                                      "the contents of its field is not a string"]))
  150.            | [("arguments", J.ARRAY args),
  151.               ("operator", J.STRING operName)] => let
  152.                val numArgs = length args
  153.                val maybeArgSpec =
  154.                    Option.map (# 2) (List.find (fn (operName2, argSpec) =>
  155.                                                    operName2 = operName)
  156.                                                operatorArgSpecs)
  157.                val () =
  158.                    case maybeArgSpec
  159.                     of NONE =>
  160.                        raise (BadJsonMath (j, ["JSON object does not represent a math expression: ",
  161.                                                "bad operator name: ", operName]))
  162.                      | SOME NONE => ()
  163.                      | SOME (SOME requiredNumArgs) =>
  164.                        if requiredNumArgs = numArgs
  165.                        then ()
  166.                        else raise (BadJsonMath
  167.                                        (j, ["JSON object does not represent a math expression: ",
  168.                                             "operator ",operName,"requires ",
  169.                                             Int.toString requiredNumArgs,
  170.                                             " arguments but got ",Int.toString numArgs]))
  171.              in opFn {extra = extra, op_name = operName, arguments = args} end
  172.            | [("arguments", J.ARRAY _),
  173.               ("operator", _)] =>
  174.              raise (BadJsonMath (j, ["JSON object does not represent an operation: ",
  175.                                      "the contents of its operator field is not a string"]))
  176.            | [("arguments", _),
  177.               ("operator", J.STRING _)] =>
  178.              raise (BadJsonMath (j, ["JSON object does not represent an operation: ",
  179.                                      "the contents of its arguments field is not an array"]))
  180.            | _ => raise (BadJsonMath (j, ["JSON object does not represent a math expression: ",
  181.                                           "wrong fields"])))
  182.       | _ => raise (BadJsonMath (j, ["JSON value does not represent a math expression: ",
  183.                                      "neither integer nor object"]));
  184.  
  185. (* Detects whether a JSON.value is a valid representation of a mathematical definition and if it
  186. is calls the function it is supplied with the extracted pieces of the definition *)
  187. fun 'result caseJsonMathDec (decFn : {var_num : IntInf.int, expression : J.value} -> 'result)
  188.                             (j as J.OBJECT fields) =
  189.     (case sortJsonFields fields
  190.       of [("declared-variable", J.STRING var),
  191.           ("value", exp)] =>
  192.          decFn {var_num = parseVariableName var, expression = exp}
  193.        | _ => raise (BadJsonMath (j, ["JSON object does not represent a math declaration: ",
  194.                                       "wrong fields or declared-variable not a string"])))
  195.   | caseJsonMathDec _ j =
  196.     raise (BadJsonMath (j, ["JSON value does not represent a math declaration: not an object"]));
  197.  
  198. (* Detects whether a JSON.value is a valid representation of a list of mathematical definition
  199. and if it is calls the function it is supplied with the list of definitions. *)
  200. fun 'result caseJsonMathDecList (decListFn : J.value list -> 'result)
  201.             (J.OBJECT [("declaration-list", J.ARRAY decs)]) =
  202.     decListFn decs
  203.   | caseJsonMathDecList _ j =
  204.     raise (BadJsonMath (j, ["JSON value does not represent a math declaration list: ",
  205.                             "not an object or object with wrong fields"]));
  206.  
  207. (* *************************************************************************** *
  208.  * Code implementation of Part 1 by Nasr Herzallah                        *                                                                          *
  209.  * *************************************************************************** *)
  210.  
  211. (* Open output file *)
  212. val outfile = TextIO.openOut "output.txt";
  213.  
  214. (* output helpers *)
  215. fun printErr s = TextIO.output (TextIO.stdErr, s);
  216. fun printOut s = TextIO.output (outfile, s);
  217. fun closeFile _ = TextIO.closeOut outfile;
  218.  
  219. fun printList (h::t) = let
  220.   val () = printOut h;
  221.   val () = printList t;
  222. in () end
  223.  |  printList [] = ();
  224.  
  225. (* Program Exit helpers *)
  226. fun exitCode true = OS.Process.failure
  227.  |  exitCode false = OS.Process.success;
  228.  
  229. fun exit error = let
  230.   val () = closeFile ();
  231.   val () = OS.Process.exit(exitCode error);
  232. in () end;
  233.  
  234. (* Functions related to exception handling *)
  235. fun badInput m = let
  236.   val () = printOut "Error: ";
  237.   val () = printList m;
  238.   val () = printOut "\n";
  239. in () end;
  240.  
  241. fun badInitialInput (j,m) = let
  242.   val () = badInput m;
  243.   val () = printErr "Error: See output file.\n";
  244.   val () = exit true;
  245. in [j] end;
  246.  
  247. fun badVar m = let
  248.   val () = badInput m;
  249.   val () = printErr "Error: See output file.\n";
  250. in () end;
  251.  
  252. fun badLaterInput (j,m) = let
  253.   val () = badInput m;
  254.   val () = printErr "Error: See output file.\n";
  255. in () end;
  256.  
  257. fun badImplementation m = let
  258.   val () = printOut "Error: ";
  259.   val () = printList m;
  260.   val () = printOut "\n";
  261.   val () = printErr "Error: See output file.\n";
  262. in (exit true) end;
  263.  
  264. datatype EXP =
  265.     INT   of  IntInf.int
  266.   | PAIR  of (EXP * EXP)
  267.   | SET   of EXP list
  268.  
  269. (* type to hold variable, which is a pair containg a string variable name, and
  270.  * an associated expression. *)
  271. datatype VAR = VAR of (IntInf.int * EXP)
  272.  
  273. exception EXPException of string list;
  274.  
  275. (* a couple function that can be used to print out an EXP. *)
  276. fun printEXP (INT i)  = printInt  i
  277.  |  printEXP (PAIR p) = printPair p
  278.  |  printEXP (SET s)  = let
  279.       val () = printOut "{";
  280.       val () = printSet s;
  281.       val () = printOut "}";
  282.     in () end
  283.  
  284. and printInt i = let
  285.   val () = if i<0 then printOut "-" else ();
  286.   val j = IntInf.abs i;
  287. in printOut (IntInf.toString j) end
  288.  
  289. and printPair (f, l) = let
  290.   val () = printOut "(";
  291.   val () = printEXP f;
  292.   val () = printOut ", ";
  293.   val () = printEXP l;
  294.   val () = printOut ")";
  295. in () end
  296.  
  297. and printSet (hd::m::tl) = let
  298.       val () = printEXP hd;
  299.       val () = printOut ", ";
  300.       val () = printSet (m::tl);
  301.     in () end
  302.  | printSet (hd::tl) = let
  303.       val () = printEXP hd;
  304.     in () end
  305.  | printSet [] = ();
  306.  
  307. fun printVarDec (VAR(i:IntInf.int, e:EXP)) = let
  308.   val () = printOut "Let x";
  309.   val () = printInt i;
  310.   val () = printOut " be ";
  311.   val () = printEXP e;
  312. in () end;
  313.  
  314. fun printEvaluation (VAR(i:IntInf.int, e:EXP)) = let
  315. val () = printOut "\n\twhich is ";
  316. val () = printEXP e;
  317. val () = printOut ".\n"
  318. in () end;
  319.  
  320. fun orderInt (INT i, INT j) = if i=j then
  321.   EQUAL else if i>j then
  322.   GREATER else
  323.   LESS
  324.  |  orderInt _ = raise EXPException ["Not required for part-1"];
  325.  
  326. fun evaluateSet e = let
  327.   val sorted = ListMergeSort.uniqueSort orderInt e;
  328. in sorted end;
  329.  
  330. fun evaluateEXP (INT i) = (INT i)
  331.  |  evaluateEXP (SET s) = SET(evaluateSet s)
  332.  |  evaluateEXP e = e;
  333.  
  334. fun evaluateVariable (VAR(i:IntInf.int, e:EXP)) = let
  335.   val eval = evaluateEXP e;
  336. in VAR(i, eval) end;
  337.  
  338. (* ********************************
  339.  * Translate from JSON to EXP/VAR *
  340.  * ********************************)
  341.  
  342. fun translateExpression vars expression = let
  343.   val exp = caseJsonMathExp
  344.     { intFn = translateInt, opFn = translateOp, varFn = translateVar }
  345.     vars expression;
  346. in exp end
  347.  
  348. and translateInt {extra, int} = INT int
  349.  
  350. and translateOp {extra, op_name, arguments} = let
  351.   val exp = (case op_name
  352.     of "set"  => translateSet { extra = extra, arguments = arguments }
  353.     |  "pair" => translatePair { extra = extra, arguments = arguments }
  354.     |   _     => raise EXPException ["Not required for part-1"]);
  355. in exp end
  356.  
  357. and translateVar {extra, var_num} = let
  358.   val () = raise EXPException ["Not required for part-1"];
  359. in INT 42 end
  360.  
  361. and translatePair {extra, arguments} = (case arguments
  362.   of [i, j] => PAIR((translateExpression extra i),(translateExpression extra j))
  363.   | _ => raise (BadVariableName ["Variable name does not exist!"]))
  364.  
  365. and translateSet {extra, arguments} = let
  366.   fun loop vars (h::t) = (translateExpression vars h)::(loop vars t)
  367.    |  loop valList [] = [];
  368.   val set = loop extra arguments;
  369. in (SET(set)) end;
  370.  
  371. fun translateDeclaration vars {var_num, expression} = let
  372.   val exp = translateExpression vars expression;
  373. in VAR(var_num, exp) end;
  374.  
  375. (* *************************************************************************** *
  376.  * Main Loop Function            === NASR REWRITE THIS ===
  377.   === MAKE SURE YOU UNDERSTAND WHAT THE CODE DOES ===                                              *
  378.  *                                                                             *
  379.  * Function iterates over each JSON variable declaration. Each declaration is  *
  380.  * translated into a VAR and then printed to output, first in its         *
  381.  * 'declared' form, and then in it 'evaluated' form, the function also stores  *
  382.  * a list of all previously evaluated VARs in case they need to be        *
  383.  * referenced in the future.                                                   *
  384.  *                                                                             *
  385.  * If JSON is not correctly formatted, exceptions are raised through the       *
  386.  * `caseJsonMathDec`, `caseJsonMathExp`, or `parseVariableName` functions,     *
  387.  * they are caught and that declaration is skipped. This error is also         *
  388.  * recorded so that the program can exit with an appropriate error code.       *
  389.  * *************************************************************************** *)
  390.  
  391. exception LoopException of (J.value list * VAR list * bool);
  392.  
  393. fun mainLoop [] _ error = (exit error)
  394.  |  mainLoop (h::t) vars error = let
  395.       val var = caseJsonMathDec (translateDeclaration vars) h
  396.       handle BadJsonMath (j,m) => let val () = badLaterInput (j,m);
  397.               in raise (LoopException (t, vars, true)) end
  398.        |     BadVariableName m => let val () = badVar m;
  399.               in raise (LoopException (t, vars, true)) end;
  400.       val () = printVarDec var;
  401.       val eval = evaluateVariable var;
  402.       val () = printEvaluation eval;
  403.       val variables = (eval)::vars;
  404.     in mainLoop t variables error end
  405. handle LoopException (json,vars,error) => mainLoop json vars true
  406.   |    EXPException m => badImplementation m;
  407.  
  408. (* Use JSONParser using the preliminary code given to us to parse the
  409.  * JSON file as input *)
  410. val inputFile = JSONParser.parseFile "input.json";
  411.  
  412. (* If BadJsonMath is raised here, the script exits with an error code. *)
  413. val declarations = caseJsonMathDecList (fn x => x) inputFile
  414. handle BadJsonMath (j,m) => badInitialInput (j,m);
  415.  
  416. (* Loop over the list of variable declarations *)
  417. mainLoop declarations [] false;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement