Advertisement
Guest User

Untitled

a guest
Jan 24th, 2017
90
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 14.35 KB | None | 0 0
  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. (*** example of processing mathematical definitions *)
  209. (* **************************************************)
  210.  
  211. (* This section is an example of how to traverse a JSON-encoded tree representing mathematical
  212. definitions. The example also shows how to thread a piece of stateful information through the
  213. traversal using the “extra” parameter of caseJsonMathExp. *)
  214.  
  215. (***************************************************************************************************
  216. * NOTICE TO STUDENT: You may use the code above this line provided you carefully mark any changes
  217. * you make. You may take inspiration from the code below this line but you should not use it. You
  218. * should instead understand it and then write your own code from your understanding.
  219. * *************************************************************************************************)
  220.  
  221. datatype NotationTree = INT of IntInf.int | VAR of IntInf.int | PAIR of NotationTree * NotationTree | SET of NotationTree list;
  222.  
  223. exception BadPair of string;
  224.  
  225. val file = "output.txt";
  226.  
  227. fun writeAppendFile fileName content =
  228. let val fd = TextIO.openAppend fileName
  229. val _ = TextIO.output (fd, content) handle e => (TextIO.closeOut fd; raise e)
  230. val _ = TextIO.closeOut fd
  231. in () end;
  232.  
  233. fun traverseNotationTree (INT i) = let
  234. val k = if i < 0 then let
  235. val () = writeAppendFile "output.txt" "-";
  236. val () = writeAppendFile "output.txt" (IntInf.toString (abs i));
  237. in () end
  238. else writeAppendFile "output.txt" (IntInf.toString i);
  239. in k end
  240. | traverseNotationTree (VAR i) = ()
  241. | traverseNotationTree (PAIR (x, y)) = let
  242. val () = writeAppendFile "output.txt" "(";
  243. val () = traverseNotationTree x;
  244. val () = writeAppendFile "output.txt" ", ";
  245. val () = traverseNotationTree y;
  246. val () = writeAppendFile "output.txt" ")";
  247. in () end
  248. | traverseNotationTree (SET (hd::tl)) = let
  249. val () = writeAppendFile "output.txt" "{";
  250. val () = traverseNotationTree hd;
  251. fun loop (h::t) = let
  252. val () = writeAppendFile "output.txt" ", ";
  253. val () = traverseNotationTree h;
  254. in loop t end
  255. | loop [] = ();
  256. val () = loop tl;
  257. val () = writeAppendFile "output.txt" "}";
  258. in () end
  259. | traverseNotationTree (SET ([])) = writeAppendFile "output.txt" "{}";
  260.  
  261. fun traverseInt {extra = node, int} = (INT int)
  262.  
  263. and traverseVar {extra = node, var_num} = (VAR var_num)
  264.  
  265. and traverseSet node arguments = let
  266. fun loop node (arg::args)
  267. = (traverseJsonMathExp node arg)::(loop node args)
  268. | loop node [] = [];
  269. in (SET (loop node arguments)) end
  270.  
  271. and traversePair node (hd::tl::[]) = let
  272. in (PAIR (INT 1, INT 2)) end
  273. | traversePair node _ = (INT 1)
  274.  
  275. and traverseOp {extra = node, op_name, arguments} = if op_name = "set" then (traverseSet node arguments) else (traversePair node arguments)
  276.  
  277. and traverseJsonMathExp node exp =
  278. caseJsonMathExp {intFn = traverseInt, varFn = traverseVar, opFn = traverseOp} node exp;
  279.  
  280. fun traverseDec node {var_num, expression} = let
  281. val () = writeAppendFile "output.txt" "Let x";
  282. val () = writeAppendFile "output.txt" (IntInf.toString var_num);
  283. val () = writeAppendFile "output.txt" " be ";
  284. val node2 = traverseJsonMathExp (node + 1) expression;
  285. val () = traverseNotationTree node2;
  286. val () = writeAppendFile "output.txt" "\n";
  287. val () = writeAppendFile "output.txt" " which is ";
  288. val () = traverseNotationTree node2;
  289. val () = writeAppendFile "output.txt" "\n";
  290. (*val node3 = traverseNotationTree (traverseJsonMathExp node2 expression);*)
  291. in 2 end;
  292.  
  293. fun traverseDecList decs = let
  294. fun loop node (d::decs) = loop (caseJsonMathDec (traverseDec node) d) decs
  295. | loop _ [] = ();
  296. val () = loop 2 decs;
  297. in () end;
  298.  
  299. val input = JSONParser.parseFile "input.json";
  300.  
  301. val () = caseJsonMathDecList traverseDecList input;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement