Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/home/jbw/jbw-cvs/bin/smlnj-script
- (*-*-SML-*-*) (* Tell Emacs to use SML mode even though name does not end with “.sml”. *)
- (* #!/usr/bin/env smlnj-script *) (* This is better 1st line if smlnj-script is in your PATH. *)
- (* Author of template portion: Joe Wells *)
- (* STUDENT'S SOURCE CODE MUST HAVE A STATEMENT (INCLUDING THEIR NAME) OF WHAT PORTION THEY HAVE AUTHORED!!! *)
- (**********************************************************************
- * INSTRUCTIONS FOR USING THIS FILE
- * (DELETE THIS COMMENT AFTER UNDERSTANDING IT.)
- *
- * These instructions assume this file is named Xyzzy. When reading
- * these instructions, replace Xyzzy in your mind by the actual file
- * name.
- *
- * This is an SML/NJ _*script*_. You do not need to compile it. It
- * should be runnable as is. This means if this file is in the
- * current directory, you should be able to type ./Xyzzy at a shell
- * command prompt and this program will run. If you put this file in
- * one of the directories listed in your PATH environment variable,
- * then you can run this by just typing “Xyzzy”.
- *
- * There are a few things that can go wrong, and here is a short guide
- * to how to fix them:
- *
- * 1. The permissions on this file might be wrong. Do “chmod a+rx
- * Xyzzy” (assuming you own the file).
- *
- * 2. smlnj-script might not be installed anywhere on the computer you
- * are using. Install it.
- *
- * 3. If the first line reads “#!/usr/bin/env smlnj-script”, then
- * “smlnj-script” might not be in any of the directories found via
- * your PATH environment variable. Fix your PATH.
- *
- * Alternatively, if the first line is of the form
- * “#!/directory/path/to/smlnj-script”, then the path
- * “/directory/path/to/smlnj-script” might be the wrong path to
- * smlnj-script. Fix it.
- *
- * Fuller instructions for smlnj-script can be found in the README
- * file in the smlnj-script git repository. As of 2016-01, you can
- * find a copy of this repository at
- * /home/jbw/smlnj-script-git/smlnj-script on the UNIX NFS file
- * systems of the Heriot-Watt University Computer Science department.
- * Do “git clone
- * ssh://MACHINE.macs.hw.ac.uk/~jbw/smlnj-script-git/smlnj-script”
- * (where you must replace MACHINE by the name of some machine that
- * works, e.g., linux01 worked for me) to get your own copy of this
- * repository.
- **********************************************************************)
- (* *************************)
- (*** support for debugging *)
- (* *************************)
- (* Comments that begin with “*SKALPEL-” help Skalpel, a tool for SML type errors. *)
- (* Semicolons after Skalpel magic comments are needed by Skalpel. *)
- (**SKALPEL-USE-FILE /home/jbw/smlnj-script-git/smlnj-script/smlnj-script-for-skalpel.sml *);
- val () = U.raisePrintingLimitsToMax (); (* Comment to hide details in compiler messages. *)
- (* val () = U.interact (); *) (* Move this to where you want to enter interactive mode and uncomment. *)
- val () = silenceCompiler (); (* Because next 3 function calls print a lot. *)
- (* These two help you avoid shooting yourself in the foot. *)
- val () = Student.strongerPatternErrorsAndWarnings ();
- val () = Student.disableBadPartialFunctions ();
- (* This helps you avoid getting a lower mark by violating the prohibition on string building. *)
- val () = Student.disableStringBuilding ();
- val () = U.clearCompilerOutputStash ();
- val () = unsilenceCompiler (); (* Comment when your script is finally completely working. *)
- (* *********************************************************************)
- (*** utilities for processing mathematical definitions encoded in JSON *)
- (* *********************************************************************)
- structure J = JSON;
- (* The JSON structure represents JSON objects as association lists. Parse results are not
- guaranteed to have object fields in any particular order. Because this makes pattern matching
- tedious, the sortJsonFields function is used to sort the JSON object fields. This also will help
- with detecting bad JSON having two fields with the same name (which I suspect the JSON structure
- allows). *)
- fun 'value sortJsonFields (fields : (string * 'value) list) : (string * 'value) list =
- ListMergeSort.sort (fn ((key1,value1),(key2,value2)) =>
- U.isGreater (String.compare (key1,key2)))
- fields;
- (* Error exceptions have (string list) rather than string so as to abide by the prohibition of
- run-time string building *)
- exception BadJsonMath of J.value * (string list);
- exception BadVariableName of string list;
- (* Identifies which operators are allowed and how many arguments each expects. *)
- val operatorArgSpecs : (string * (int option)) list =
- List.concat
- (map (fn (argSpec, operList) =>
- (map (fn oper => (oper, argSpec))
- operList))
- [(SOME 1, ["domain", "inverse", "is-function"]),
- (SOME 2, ["pair", "apply-function", "equal", "member", "function-space", "union"]),
- (SOME 4, ["diagonalize"]),
- (NONE, ["set"])]);
- (* Enforces the rules for valid variable names and converts them to integers. *)
- fun parseVariableName (varName : string) : IntInf.int =
- case String.explode varName
- of #"x" :: #"0" :: _ :: _ =>
- raise (BadVariableName ["purported variable name contains character(s) after x0: ",
- varName])
- | #"x" :: digits =>
- foldl (fn (c as (#"0"|(#"1")|(#"2")|(#"3")|(#"4")|(#"5")|(#"6")|(#"7")|(#"8")|(#"9")),
- num : IntInf.int)
- => (num * 10) + (IntInf.fromInt (Char.ord c - Char.ord #"0"))
- | _ =>
- raise (BadVariableName
- ["purported variable name contains non-digit after the first position: ",
- varName]))
- (0 : IntInf.int)
- digits
- | _ :: _ => raise (BadVariableName ["purported variable name does not start with x: ",
- varName])
- | nil => raise (BadVariableName ["purported variable name is empty string"]);
- (* Detects whether a JSON.value is a valid representation of a mathematical expression and if it
- is calls one of the 3 functions it is supplied for the different cases. *)
- fun ('result)
- caseJsonMathExp
- {intFn : IntInf.int -> 'result,
- opFn : {op_name : string, arguments : J.value list} -> 'result,
- varFn : IntInf.int -> 'result,
- j : J.value}
- : 'result =
- case j
- of (J.INT i) => intFn i
- | (J.OBJECT fields) =>
- (case sortJsonFields fields
- of [("variable", J.STRING varName)] =>
- varFn (parseVariableName varName)
- | [("variable", _)] =>
- raise (BadJsonMath (j, ["JSON object does not represent a variable reference: ",
- "the contents of its field is not a string"]))
- | [("arguments", J.ARRAY args),
- ("operator", J.STRING operName)] => let
- val numArgs : int = length args
- val maybeArgSpec : int option option =
- Option.map (# 2) (List.find (fn (operName2, argSpec) =>
- operName2 = operName)
- operatorArgSpecs)
- val () =
- case maybeArgSpec
- of NONE =>
- raise (BadJsonMath (j, ["JSON object does not represent a math expression: ",
- "bad operator name: ", operName]))
- | SOME NONE => ()
- | SOME (SOME requiredNumArgs) =>
- if requiredNumArgs = numArgs
- then ()
- else raise (BadJsonMath
- (j, ["JSON object does not represent a math expression: ",
- "operator ",operName," requires ",
- Int.toString requiredNumArgs,
- " arguments but got ",Int.toString numArgs]))
- in opFn {op_name = operName, arguments = args} end
- | [("arguments", J.ARRAY _),
- ("operator", _)] =>
- raise (BadJsonMath (j, ["JSON object does not represent an operation: ",
- "the contents of its operator field is not a string"]))
- | [("arguments", _),
- ("operator", J.STRING _)] =>
- raise (BadJsonMath (j, ["JSON object does not represent an operation: ",
- "the contents of its arguments field is not an array"]))
- | _ => raise (BadJsonMath (j, ["JSON object does not represent a math expression: ",
- "wrong fields"])))
- | _ => raise (BadJsonMath (j, ["JSON value does not represent a math expression: ",
- "neither integer nor object"]));
- (* Detects whether a JSON.value is a valid representation of a mathematical definition and if it
- is extracts the variable and the JSON representing what the variable is being defined to be. *)
- fun extractJsonMathDec (j as J.OBJECT fields) =
- (case sortJsonFields fields
- of [("declared-variable", J.STRING var),
- ("value", exp)] =>
- (parseVariableName var, exp)
- | _ => raise (BadJsonMath (j, ["JSON object does not represent a math declaration: ",
- "wrong fields or declared-variable not a string"])))
- | extractJsonMathDec j =
- raise (BadJsonMath (j, ["JSON value does not represent a math declaration: not an object"]));
- (* Detects whether a JSON.value is a valid representation of a list of mathematical definitions
- and if it is extracts the list. *)
- fun extractJsonMathDecList (J.OBJECT [("declaration-list", J.ARRAY decs)]) = decs
- | extractJsonMathDecList j =
- raise (BadJsonMath (j, ["JSON value does not represent a math declaration list: ",
- "not an object or object with wrong fields"]));
- (* ********************)
- (*** output utilities *)
- (* ********************)
- val outFile = TextIO.openOut "output.txt";
- fun printToFile s = TextIO.output (outFile, s);
- fun printToFileAndConsole s = (printOut s; print s);
- fun printError s = TextIO.output (TextIO.stdErr, s);
- (* *************************************************************************** *
- * Code implementation of Part 1 by Nasr Herzallah - H00...... * *
- * *************************************************************************** *)
- datatype DATA = INT of IntInf.int | VAR of (IntInf.int * DATA) | PAIR of (DATA * DATA) | SET of DATA list;
- exception DataTreeException of string;
- fun printDataTree (INT i) = printInt i
- | printDataTree (VAR v) = printVar v
- | printDataTree (PAIR p) = printPair p
- | printDataTree (SET s) = let
- val () = printToFile "{";
- val () = printSet s;
- val () = printToFile "}";
- in () end
- and printInt i = let
- val () = if i < 0 then printToFile "-" else (); (* Check if number is negative *)
- val j = IntInf.abs i; (* Get the absolute value of the integer (positive) *)
- in printToFile (IntInf.toString newInt) end
- and printVar (i, d) = let
- val () = printToFile "Let x";
- val () = printToFile (IntInf.toString i);
- val () = printToFile " be ";
- val () = printDataTree d;
- in () end
- and printPair (d1, d2) = let
- val () = printToFile "(";
- val () = printDataTree d1;
- val () = printToFile ", ";
- val () = printDataTree d2;
- val () = printToFile ")";
- in () end
- and printSet (hd::snd::tl) = let
- val () = printDataTree hd;
- val () = printToFile ", ";
- val () = printSet (snd::tl); (* Loop the rest of the list *)
- in () end
- | printSet (hd::tl) = let
- val () = printDataTree hd;
- in () end
- | printSet [] = ();
- fun JSONToDataTree (data : J.value, node : int) = let
- val result = caseJsonMathExp {intFn = JSONToINT, varFn = JSONToVAR, opFn = traverseOp, j = data};
- in result end
- and JSONToINT (i : IntInf.int) = INT i
- and JSONToVAR (varNum : IntInf.int) = let
- val () = raise DataTreeException "Not required for part-1";
- in INT 0 end
- and JSONToOperator {op_name : string, arguments : J.value list} = let
- val result = (case op_name of
- "pair" => JSONToPAIR {arguments = arguments} |
- "set" => JSONToSET {arguments = arguments} |
- _ => raise DataTreeException "Not required for part-1";
- )
- in result end
- and JSONToPAIR {arguments} = (case arguments
- of [i, j] => let
- val args
- in PAIR((JSONToDataTree ..?), (JSONToDataTree ..?))
- | _ => raise DataTreeException "Bad variable name!";
- )
- and JSONToSET {arguments} = let
- (*fun loop vars (h::t) = (JSONToDataTree ..?)...*)
- (* what the fuck *)
- (* val set = loop ... *)
- in (SET([])) end; (* replace [] with set *)
- fun traverseJSONObj (dec : J.value, node : int) = let
- val (var_num : IntInf.int, exp : J.value) = extractJsonMathDec dec;
- val () = printToFile "Let x";
- val () = printToFile (IntInf.toString var_num)
- val () = printToFile " be ";
- val n2 : int = JSONToDataTree (exp, node + 1)
- val () = printDataTree n2;
- val () = printToFile " which is ";
- val () = printDataTree n2;
- val () = printToFile ".\n";
- in 2 end; (* random int return *)
- fun traverseJSONList list = let
- fun loop ((dec : J.value) :: decs, node : int) : unit =
- loop (decs, traverseJSONObj (dec, node))
- | loop ([], _) = ();
- val () = loop (decs, 2);
- in () end;
- val jsonInput = JSONParser.parseFile "input.json";
- val json = extractJsonMathDecList jsonInput;
- val () = traverseJSONList decs;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement