├── .gitignore ├── assign1 ├── program │ ├── .gitignore │ ├── even.lam │ ├── lci_linux │ ├── lci_macos │ ├── lci_win.exe │ ├── make_submission.sh │ ├── mult.lam │ └── sum.lam └── written │ ├── .gitignore │ ├── Makefile │ ├── assign1.tex │ └── defs.tex ├── assign2 ├── program │ ├── Makefile │ ├── _tags │ ├── make_submission.sh │ ├── run_tests.py │ ├── sol_linux │ ├── sol_mac │ ├── src │ │ ├── ast.ml │ │ ├── ast.mli │ │ ├── interpreter.ml │ │ ├── interpreter.mli │ │ ├── lexer.mll │ │ ├── main.ml │ │ ├── parser.mly │ │ ├── typecheck.ml │ │ └── typecheck.mli │ └── tests │ │ ├── binop1.lam1 │ │ ├── binop2.lam1 │ │ ├── binop3.lam1 │ │ ├── binop_fail1.lam1 │ │ ├── binop_fail2.lam1 │ │ ├── binop_zero1.lam1 │ │ ├── case1.lam2 │ │ ├── case_fail1.lam2 │ │ ├── function_apply1.lam1 │ │ ├── function_apply2.lam1 │ │ ├── function_apply_error1.lam1 │ │ ├── function_error1.lam1 │ │ ├── function_type1.lam1 │ │ ├── function_type2.lam1 │ │ ├── function_type3.lam1 │ │ ├── inject1.lam2 │ │ ├── inject2.lam2 │ │ ├── inject_fail1.lam2 │ │ ├── pair1.lam2 │ │ ├── pair2.lam2 │ │ ├── pair_fail1.lam2 │ │ ├── project1.lam2 │ │ ├── project_fail1.lam2 │ │ ├── simple_fail1.lam1 │ │ └── simple_fail2.lam1 └── written │ ├── Makefile │ ├── assign2.tex │ └── defs.tex ├── assign3 ├── program │ ├── Makefile │ ├── _tags │ └── src │ │ ├── list2.ml │ │ └── stream2.ml └── written │ ├── Makefile │ ├── assign3.tex │ └── defs.tex ├── assign4 ├── program │ ├── .gitignore │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── hash.wat │ │ ├── index.html │ │ ├── index.js │ │ └── tests.js │ └── webpack.config.js └── written │ ├── Makefile │ ├── assign4.tex │ └── defs.tex ├── assign5 ├── Cargo.lock ├── Cargo.toml ├── make_submission.sh ├── run_tests.py ├── solution_linux ├── solution_mac ├── src │ ├── ast.rs │ ├── interpret.rs │ ├── main.rs │ ├── memory.rs │ ├── parse.rs │ └── sexp.rs └── tests │ ├── binop.wat │ ├── block.wat │ ├── func_call.wat │ ├── load_invalid.wat │ ├── load_store.wat │ ├── local.wat │ ├── loop.wat │ ├── mem_grow.wat │ ├── memory_test_safe.rs │ ├── memory_test_unsafe.rs │ ├── relop.wat │ ├── return.wat │ └── unreachable.wat ├── assign6 ├── .rustfmt.toml ├── Cargo.lock ├── Cargo.toml ├── make_submission.sh ├── src │ ├── asyncio.rs │ ├── executor.rs │ ├── future.rs │ ├── future_util.rs │ └── lib.rs └── tests │ ├── asyncio_test.rs │ ├── executors_test.rs │ └── futures_test.rs ├── assign7 ├── program │ ├── .rustfmt.toml │ ├── Cargo.lock │ ├── Cargo.toml │ ├── make_submission.sh │ └── src │ │ ├── atm.rs │ │ ├── counterex.rs │ │ ├── echo_example.rs │ │ ├── lib.rs │ │ ├── session.rs │ │ ├── session_bug.rs │ │ └── tcp.rs └── written │ ├── Makefile │ ├── assign7.tex │ └── defs.tex ├── assign8 ├── .gitignore ├── Dockerfile ├── Makefile ├── class │ ├── class.lua │ ├── class_tests.lua │ ├── type_tests.lua │ └── types.lua ├── deps │ ├── README.md │ ├── randomlua.lua │ └── rotLove │ │ ├── img │ │ └── cp437.png │ │ ├── rot.lua │ │ └── rot │ │ ├── class.lua │ │ ├── color.lua │ │ ├── dice.lua │ │ ├── display.lua │ │ ├── engine.lua │ │ ├── eventQueue.lua │ │ ├── fov.lua │ │ ├── fov │ │ ├── bresenham.lua │ │ ├── precise.lua │ │ └── recursive.lua │ │ ├── lighting.lua │ │ ├── map.lua │ │ ├── map │ │ ├── arena.lua │ │ ├── brogue.lua │ │ ├── brogueRoom.lua │ │ ├── cellular.lua │ │ ├── corridor.lua │ │ ├── digger.lua │ │ ├── dividedMaze.lua │ │ ├── dungeon.lua │ │ ├── ellerMaze.lua │ │ ├── feature.lua │ │ ├── iceyMaze.lua │ │ ├── rogue.lua │ │ ├── room.lua │ │ └── uniform.lua │ │ ├── newFuncs.lua │ │ ├── noise.lua │ │ ├── noise │ │ └── simplex.lua │ │ ├── path.lua │ │ ├── path │ │ ├── astar.lua │ │ ├── dijkstra.lua │ │ └── dijkstraMap.lua │ │ ├── rng.lua │ │ ├── scheduler.lua │ │ ├── scheduler │ │ ├── action.lua │ │ ├── simple.lua │ │ └── speed.lua │ │ ├── stringGenerator.lua │ │ ├── text.lua │ │ ├── textDisplay.lua │ │ └── type │ │ ├── grid.lua │ │ └── pointSet.lua ├── game │ ├── entity.lua │ ├── game.lua │ ├── game_tests.lua │ ├── hero.lua │ ├── light.lua │ ├── monster.lua │ └── tiles.lua ├── point │ ├── benchmark_point.lua │ ├── lauxlib.linux.rs │ ├── lauxlib.macos.rs │ ├── native_point.rs │ ├── point.lua │ └── point_tests.lua ├── roguelike.bin └── roguelike.lua ├── final ├── grading.py ├── make_submission.sh └── proofs.lean ├── lab1 ├── Makefile ├── _tags ├── exercise1.ml ├── exercise2.ml ├── exercise3.ml └── solution │ ├── Makefile │ ├── _tags │ ├── exercise1.ml │ ├── exercise2.ml │ └── exercise3.ml ├── lab2 ├── Cargo.lock ├── Cargo.toml ├── solution │ ├── Cargo.lock │ ├── Cargo.toml │ └── src │ │ ├── main.rs │ │ ├── part1.rs │ │ └── part2.rs └── src │ ├── main.rs │ ├── part1.rs │ └── part2.rs └── lab3 ├── part1 └── serialize.lua ├── part2 └── metatables.lua ├── part3 ├── Makefile ├── lauxlib.linux.rs ├── lauxlib.macos.rs ├── match_test.lua └── stringmatch.rs └── solution ├── part1 └── serialize.lua ├── part2 └── metatables.lua └── part3 ├── Makefile ├── lauxlib.rs ├── match_test.lua └── stringmatch.rs /.gitignore: -------------------------------------------------------------------------------- 1 | **/.DS_Store 2 | -------------------------------------------------------------------------------- /assign1/program/.gitignore: -------------------------------------------------------------------------------- 1 | assign1.zip 2 | -------------------------------------------------------------------------------- /assign1/program/even.lam: -------------------------------------------------------------------------------- 1 | z = fun f -> fun x -> x 2 | s = fun n -> fun f -> fun x -> f (n f x) 3 | true = fun a -> fun b -> a 4 | false = fun a -> fun b -> b 5 | not = fun p -> fun a -> fun b -> p b a 6 | even = fun n -> (* fill this in - tests are below *) 7 | 8 | booltonum = fun b -> b (s z) z 9 | 10 | booltonum (even z) 11 | booltonum (even (s z)) 12 | booltonum (even (s (s z))) 13 | booltonum (even (s (s (s z)))) 14 | 15 | booltonum (even (s (s (s (s (s (s (s (s z))))))))) 16 | -------------------------------------------------------------------------------- /assign1/program/lci_linux: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-cs242/f18-assignments/0646cc427e126f105654405323c4074db3015f56/assign1/program/lci_linux -------------------------------------------------------------------------------- /assign1/program/lci_macos: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-cs242/f18-assignments/0646cc427e126f105654405323c4074db3015f56/assign1/program/lci_macos -------------------------------------------------------------------------------- /assign1/program/lci_win.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-cs242/f18-assignments/0646cc427e126f105654405323c4074db3015f56/assign1/program/lci_win.exe -------------------------------------------------------------------------------- /assign1/program/make_submission.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | zip -r assign1.zip even.lam mult.lam sum.lam 3 | -------------------------------------------------------------------------------- /assign1/program/mult.lam: -------------------------------------------------------------------------------- 1 | z = fun f -> fun x -> x 2 | s = fun n -> fun f -> fun x -> f (n f x) 3 | plus = fun m -> fun n -> m s n 4 | mult = fun m -> fun n -> (* fill this in - tests are below *) 5 | 6 | mult z z 7 | mult (s z) (s z) 8 | mult (s z) (s (s z)) 9 | mult (s z) (s (s (s z))) 10 | mult (s (s z)) (s (s (s z))) 11 | mult z (s (s (s z))) 12 | mult (s (s z)) (mult (s (s z)) (s (s z))) 13 | 14 | ten = (s (s (s (s (s (s (s (s (s (s z)))))))))) 15 | mult ten ten 16 | -------------------------------------------------------------------------------- /assign1/program/sum.lam: -------------------------------------------------------------------------------- 1 | z = fun f -> fun x -> x 2 | s = fun n -> fun f -> fun x -> f (n f x) 3 | pred = fun n -> fun f -> fun x -> n (fun g -> fun h -> h (g f)) (fun u -> x) (fun u -> u) 4 | 5 | plus = fun m -> fun n -> n s m 6 | 7 | true = fun a -> fun b -> a 8 | false = fun a -> fun b -> b 9 | if = fun p -> fun a -> fun b -> p a b 10 | 11 | fix = fun f -> (fun x -> f (x x)) (fun x -> f (x x)) 12 | 13 | iszero = (* you might find it useful to define this helper function *) 14 | sum = (* put your answer here! *) 15 | 16 | sum z 17 | sum (s z) 18 | sum (s (s z)) 19 | 20 | sum (s (s (s (s (s z))))) 21 | 22 | sum (s (s (s (s (s (s (s (s (s (s z)))))))))) 23 | -------------------------------------------------------------------------------- /assign1/written/.gitignore: -------------------------------------------------------------------------------- 1 | assign1.pdf 2 | -------------------------------------------------------------------------------- /assign1/written/Makefile: -------------------------------------------------------------------------------- 1 | TEX := pdflatex 2 | FLAGS := -shell-escape 3 | 4 | all: assign1.pdf 5 | 6 | %.pdf: %.tex 7 | ${TEX} ${FLAGS} $^ 8 | 9 | check: 10 | aspell -t -c *.tex 11 | 12 | clean: 13 | rm -rf *.aux *.log *.out *.pdf _minted-* 14 | -------------------------------------------------------------------------------- /assign1/written/assign1.tex: -------------------------------------------------------------------------------- 1 | \documentclass[11pt]{article} 2 | 3 | \input{./defs.tex} 4 | 5 | \begin{document} 6 | 7 | \hwtitle 8 | {Assignment 1} 9 | {Will Crichton (wcrichto)} %% REPLACE THIS WITH YOUR NAME/ID 10 | 11 | \problem{Problem 1} 12 | 13 | Your answer goes here. Here's an example of writing a lambda calculus expression. 14 | 15 | $$ 16 | Y = \fun{f}{\app 17 | {(\fun{x}{\app{f}{(\app{x}{x})}})} 18 | {(\fun{x}{\app{f}{(\app{x}{x})}})}} 19 | $$ 20 | 21 | \problem{Problem 3} 22 | 23 | Your answer goes here. Here's the dynamically-scoped untyped lambda calculus operational semantics as examples of writing inference rules. 24 | 25 | \begin{mathpar} 26 | \ir{V-Lam}{ \ }{\val{\fun{x}{e}}} 27 | 28 | \ir{D-Var} 29 | {\ctx(x) = e} 30 | {\dynJC{\steps{x}{e}}} 31 | 32 | \ir{D-App$_1$} 33 | {\dynJC{\steps{e_1}{e_1'}}} 34 | {\dynJC{\steps{\app{e_1}{e_2}}{\app{e_1'}{e_2}}}} 35 | 36 | \ir{D-App$_2$} 37 | {\dynJ{\ctx, x \rightarrow e_2}{\steps{e_1}{e_1'}}} 38 | {\dynJC{\steps{\app{(\fun{x}{e_1})}{e_2}}{\app{(\fun{x}{e_1'})}{e_2}}}} 39 | 40 | \ir{D-App$_3$} 41 | {\val{e_1}} 42 | {\dynJC{\steps{\app{(\fun{x}{e_1})}{e_2}}{e_1}}} 43 | \end{mathpar} 44 | 45 | \end{document} 46 | -------------------------------------------------------------------------------- /assign1/written/defs.tex: -------------------------------------------------------------------------------- 1 | %%% PACKAGES 2 | 3 | \usepackage{fullpage} % 1 page margins 4 | \usepackage{latexsym} % extra symbols, e.g. \leadsto 5 | \usepackage{verbatim} % verbatim mode 6 | \usepackage{proof} % proof mode 7 | \usepackage{amsthm,amssymb,amsmath} % various math symbols 8 | \usepackage{color} % color control 9 | \usepackage{etoolbox} % misc utilities 10 | \usepackage{graphics} % images 11 | \usepackage{mathpartir}% inference rules 12 | \usepackage{hyperref} % hyperlinks 13 | \usepackage{titlesec} % title/section controls 14 | \usepackage{minted} % code blocks 15 | \usepackage{tocstyle} % table of contents styling 16 | \usepackage[hang,flushmargin]{footmisc} % No indent footnotes 17 | \usepackage{parskip} % no parindent 18 | \usepackage{tikz} % drawing figures 19 | \usepackage[T1]{fontenc} 20 | %%% COMMANDS 21 | 22 | % Typography and symbols 23 | \newcommand{\msf}[1]{\mathsf{#1}} 24 | \newcommand{\ctx}{\Gamma} 25 | \newcommand{\qamp}{&\quad} 26 | \newcommand{\qqamp}{&&\quad} 27 | \newcommand{\Coloneqq}{::=} 28 | \newcommand{\proves}{\vdash} 29 | \newcommand{\str}[1]{#1^{*}} 30 | \newcommand{\eps}{\varepsilon} 31 | \newcommand{\brc}[1]{\{{#1}\}} 32 | 33 | % Untyped lambda calculus 34 | \newcommand{\fun}[2]{\lambda ~ {#1} ~ . ~ {#2}} 35 | \newcommand{\app}[2]{#1 ~ #2} 36 | 37 | % Typed lambda calculus - expressions 38 | \newcommand{\funt}[3]{\lambda ~ \left(#1 : #2\right) ~ . ~ #3} 39 | \newcommand{\lett}[4]{\msf{let} ~ \hasType{#1}{#2} = #3 ~ \msf{in} ~ #4} 40 | \newcommand{\rec}[3]{\msf{rec}(#1; ~ x.y.#2)(#3)} 41 | \newcommand{\case}[5]{\msf{case} ~ {#1} ~ \{ L(#2) \to #3 \mid R(#4) \to #5 \}} 42 | \newcommand{\pair}[2]{\left({#1},{#2}\right)} 43 | \newcommand{\proj}[2]{#1 . #2} 44 | \newcommand{\inj}[3]{\msf{inj} ~ #1 = #2 ~ \msf{as} ~ #3} 45 | \newcommand{\letv}[3]{\msf{let} ~ {#1} = {#2} ~ \msf{in} ~ {#3}} 46 | 47 | % Typed lambda calculus - types 48 | \newcommand{\tprod}[2]{#1 \times #2} 49 | \newcommand{\tsum}[2]{#1 + #2} 50 | 51 | % WebAssembly 52 | \newcommand{\wconst}[1]{\msf{i32.const}~{#1}} 53 | \newcommand{\wbinop}[1]{\msf{i32}.{#1}} 54 | \newcommand{\wgetlocal}[1]{\msf{get\_local}~{#1}} 55 | \newcommand{\wsetlocal}[1]{\msf{set\_local}~{#1}} 56 | \newcommand{\wload}{\msf{i32.load}} 57 | \newcommand{\wstore}{\msf{i32.store}} 58 | \newcommand{\wsize}{\msf{memory.size}} 59 | \newcommand{\wgrow}{\msf{memory.grow}} 60 | \newcommand{\wunreachable}{\msf{unreachable}} 61 | \newcommand{\wblock}[1]{\msf{block}~{#1}} 62 | \newcommand{\wblockr}[2]{\msf{block}~{#1}~{#2}} 63 | \newcommand{\wloop}[1]{\msf{loop}~{#1}} 64 | \newcommand{\wbr}[1]{\msf{br}~{#1}} 65 | \newcommand{\wbrif}[1]{\msf{br\_if}~{#1}} 66 | \newcommand{\wreturn}{\msf{return}} 67 | \newcommand{\wcall}[1]{\msf{call}~{#1}} 68 | \newcommand{\wlabel}[3]{\msf{label}_{#1}~\{#2\}~{#3}} 69 | \newcommand{\wframe}[1]{\msf{frame}~{#1}} 70 | \newcommand{\wtrapping}{\msf{trapping}} 71 | \newcommand{\wbreaking}[2]{\msf{breaking}_{#1}~{#2}} 72 | \newcommand{\wreturning}[1]{\msf{returning}~{#1}} 73 | \newcommand{\wconfig}[5]{\{\msf{module}~{#1};~\msf{mem}~{#2};~\msf{locals}~{#3};~\msf{stack}~{#4};~\msf{instrs}~{#5}\}} 74 | \newcommand{\wfunc}[3]{\{\msf{params}~{#1};~\msf{locals}~{#2};~\msf{body}~{#3}\}} 75 | \newcommand{\wmodule}[1]{\{\msf{funcs}~{#1}\}} 76 | 77 | \newcommand{\semi}[2]{{#1};~{#2}} 78 | \newcommand{\semii}[3]{{#1};~{#2};~{#3}} 79 | \newcommand{\semiii}[4]{{#1};~{#2};~{#3};~{#4}} 80 | \newcommand{\semiiii}[5]{{#1};~{#2};~{#3};~{#4};~{#5}} 81 | \newcommand{\wci}{\msf{instrs}} 82 | \newcommand{\wcs}{\msf{stack}} 83 | \newcommand{\wcl}{\msf{locals}} 84 | \newcommand{\wcm}{\msf{mem}} 85 | \newcommand{\wcmod}{\msf{module}} 86 | \newcommand{\wsteps}[2]{\steps{\brc{#1}}{\brc{#2}}} 87 | 88 | % Inference rules 89 | %\newcommand{\inferrule}[3][]{\cfrac{#2}{#3}\;{#1}} 90 | \newcommand{\ir}[3]{\inferrule*[right=\text{(#1)}]{#2}{#3}} 91 | \newcommand{\s}{\hspace{1em}} 92 | \newcommand{\nl}{\\[2em]} 93 | \newcommand{\steps}[2]{#1 \boldsymbol{\mapsto} #2} 94 | \newcommand{\subst}[3]{[#1 \rightarrow #2] ~ #3} 95 | \newcommand{\dynJ}[2]{#1 \proves #2} 96 | \newcommand{\dynJC}[1]{\dynJ{\ctx}{#1}} 97 | \newcommand{\typeJ}[3]{#1 \proves \hasType{#2}{#3}} 98 | \newcommand{\typeJC}[2]{\typeJ{\ctx}{#1}{#2}} 99 | \newcommand{\hasType}[2]{#1 : #2} 100 | \newcommand{\val}[1]{#1~\msf{val}} 101 | \newcommand{\num}[1]{\msf{Int}(#1)} 102 | \newcommand{\err}[1]{#1~\msf{err}} 103 | \newcommand{\trans}[2]{#1 \leadsto #2} 104 | \newcommand{\size}[1]{\left|#1\right|} 105 | 106 | 107 | \newcommand{\hwtitle}[2]{\begin{center}{\Large #1} \\[0.5em] {\large #2}\end{center}\vspace{1em}} 108 | \newcommand{\toc}{{\hypersetup{hidelinks}\tableofcontents}} 109 | \newcommand{\problem}[1]{\section*{#1}} 110 | 111 | %%% CONFIG 112 | 113 | % Spacing around title/sections 114 | \titlelabel{\thetitle.\quad} 115 | \titlespacing*{\section}{0pt}{10pt}{0pt} 116 | \titlespacing*{\subsection}{0pt}{10pt}{0pt} 117 | 118 | 119 | % Show color on hyperlinks 120 | \hypersetup{colorlinks=true} 121 | 122 | % Stylize code blocks 123 | \usemintedstyle{xcode} 124 | % TODO(wcrichto): remove line of spacing beneath code blocks 125 | \newcommand{\nm}[2]{ 126 | \newminted{#1}{#2} 127 | \newmint{#1}{#2} 128 | \newmintinline{#1}{#2}} 129 | \nm{lua}{} 130 | \nm{ocaml}{} 131 | \nm{rust}{} 132 | \nm{prolog}{} 133 | 134 | \newcommand{\ml}[1]{\ocamlinline|#1|} 135 | 136 | \usetocstyle{standard} 137 | -------------------------------------------------------------------------------- /assign2/program/Makefile: -------------------------------------------------------------------------------- 1 | all: main.native 2 | 3 | BUILD = corebuild 4 | FLAGS = -use-ocamlfind -use-menhir 5 | 6 | %.native: always 7 | $(BUILD) $(FLAGS) src/$@ 8 | 9 | clean: 10 | rm -rf *.native *.top _build 11 | 12 | always: 13 | 14 | .PHONY: always 15 | -------------------------------------------------------------------------------- /assign2/program/_tags: -------------------------------------------------------------------------------- 1 | : annot, bin_annot, thread 2 | -------------------------------------------------------------------------------- /assign2/program/make_submission.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cd src 3 | zip -r -0 assign2.zip * 4 | mv assign2.zip .. 5 | -------------------------------------------------------------------------------- /assign2/program/run_tests.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import unittest 4 | import subprocess 5 | import re 6 | 7 | # RUN FROM assign2/solution 8 | 9 | TESTS = { 10 | "binop1": "Success: (Int 10)", 11 | "binop2": "Success: (Int -25)", 12 | "binop3": "Success: (Int -8)", 13 | "binop_fail1": "Error", 14 | "binop_fail2": "Error", 15 | "binop_zero1": "Success: (Int 0)", 16 | "case1": "Success: (Int 9)", 17 | "case_fail1": "Error", 18 | "function_apply1": "Success: (Int 140)", 19 | "function_apply2": "Success: (Int 15)", 20 | "function_apply_error1": "Error", 21 | "function_error1": "Error", 22 | "function_type1": "Success: (Lam x (Fn Int Int) (Binop Add (Int 3) (App (Var x) (Int 7))))", 23 | "function_type2": "Success: (Lam sup (Fn Int (Fn Int Int)) (Int 3))", 24 | "function_type3": "Success: (Int 1337)", 25 | "inject1": "Success: (Inject (Int 1) Left (Sum Int (Product Int Int)))", 26 | "inject2": "Success: (Inject (Pair (Int 4) (Int 5)) Right (Sum Int (Product Int Int)))", 27 | "inject_fail1": "Error", 28 | "pair1": "Success: (Pair (Int 5) (Int 2))", 29 | "pair2": "Success: (Int 9)", 30 | "pair_fail1": "Error", 31 | "project1": "Success: (Lam x (Product Int Int) (Project (Var x) Left))", 32 | "project_fail1": "Error", 33 | "simple_fail1": "Error", 34 | "simple_fail2": "Error", 35 | "binop_zero_adv1": "(Int 0)", 36 | "case_adv1": "Success: (Lam y Int (Binop Add (Int 3) (Var y)))", 37 | "function_apply_adv1": "Success: (Int 34)", 38 | "function_apply_adv2": "Success: (Int 240)", 39 | "function_apply_error2": "Error", 40 | "function_error2": "Error", 41 | "function_error_advanced1": "Error", 42 | "function_lexical_error1": "Error", 43 | "function_variable_apply1": "Success", 44 | "inject_adv1": "Success: (Inject (Pair (Int 3) (Lam x Int (Var x))) Right\n (Sum Int (Product Int (Fn Int Int))))", 45 | "pair_adv1": "Success: (Int 20)", 46 | "pair_adv2": "Success: (Inject (Int 5) Right (Sum Int Int))", 47 | "pair_fail_adv1": "Error" 48 | } 49 | 50 | 51 | def create_testfunc(tname, ext): 52 | testdir = os.path.abspath('tests') 53 | def func(*args): 54 | _self = args[0] 55 | tfile = os.path.join(testdir, "%s.%s" % (tname, ext)) 56 | out = subprocess.check_output(['./main.native', tfile]).decode('UTF-8').strip() 57 | res = re.search(r'Success:.*', out, flags=re.DOTALL) 58 | if not res: 59 | res = re.search(r'Error:.*', out, flags=re.DOTALL) 60 | _self.assertIn(TESTS[tname], res.group(0)) 61 | return func 62 | 63 | 64 | def add_basic_testfuncs(cls): 65 | for tpath in sorted(os.listdir('tests')): 66 | if '.lam1' not in tpath: continue 67 | name, ext = tpath.split('.') 68 | setattr(cls, 'test_%s' % name, create_testfunc(name, ext)) 69 | return cls 70 | 71 | 72 | def add_adt_testfuncs(cls): 73 | for tpath in sorted(os.listdir('tests')): 74 | if '.lam2' not in tpath: continue 75 | name, ext = tpath.split('.') 76 | setattr(cls, 'test_%s' % name, create_testfunc(name, ext)) 77 | return cls 78 | 79 | 80 | @add_basic_testfuncs 81 | class TestBasicLambdaInterpreter(unittest.TestCase): 82 | pass 83 | 84 | 85 | @unittest.skipIf(len(sys.argv) < 2, 'ADTs test') 86 | @add_adt_testfuncs 87 | class TestADTLambdaInterpreter(unittest.TestCase): 88 | pass 89 | 90 | 91 | if __name__ == '__main__': 92 | unittest.main(verbosity=2, argv=sys.argv[:1]) 93 | -------------------------------------------------------------------------------- /assign2/program/sol_linux: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-cs242/f18-assignments/0646cc427e126f105654405323c4074db3015f56/assign2/program/sol_linux -------------------------------------------------------------------------------- /assign2/program/sol_mac: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-cs242/f18-assignments/0646cc427e126f105654405323c4074db3015f56/assign2/program/sol_mac -------------------------------------------------------------------------------- /assign2/program/src/ast.ml: -------------------------------------------------------------------------------- 1 | open Core 2 | 3 | exception Unimplemented 4 | 5 | module Type = struct 6 | type t = 7 | | Int 8 | | Fn of t * t 9 | | Product of t * t 10 | | Sum of t * t 11 | [@@deriving sexp_of, sexp, compare] 12 | 13 | let to_string ty = Sexp.to_string_hum (sexp_of_t ty) 14 | end 15 | 16 | module Expr = struct 17 | type binop = Add | Sub | Mul | Div 18 | [@@deriving sexp_of, sexp, compare] 19 | 20 | type direction = Left | Right 21 | [@@deriving sexp_of, sexp, compare] 22 | 23 | type t = 24 | | Var of string 25 | | Int of int 26 | | Binop of binop * t * t 27 | | Lam of string * Type.t * t 28 | | App of t * t 29 | | Pair of t * t 30 | | Project of t * direction 31 | | Inject of t * direction * Type.t 32 | | Case of t * (string * t) * (string * t) 33 | [@@deriving sexp_of, sexp, compare] 34 | 35 | (* substitute has the following mapping to the logic discussed in lecture: 36 | * substitute x e' e = [x -> e'] e 37 | * 38 | * You will need to implement substitution by defining a case for each 39 | * possible form of a term. For each line, delete the raise and add your 40 | * implementation. *) 41 | let rec substitute (x : string) (e' : t) (e : t) : t = 42 | match e with 43 | | Int n -> raise Unimplemented 44 | | Var x' -> raise Unimplemented 45 | | Binop (b, t1, t2) -> raise Unimplemented 46 | | Lam (x', tau, body) -> raise Unimplemented 47 | | App (t1, t2) -> raise Unimplemented 48 | | Pair (e1, e2) -> raise Unimplemented 49 | | Project (e, d) -> raise Unimplemented 50 | | Inject (e, d, tau) -> raise Unimplemented 51 | | Case (e, (x1, e1), (x2, e2)) -> raise Unimplemented 52 | 53 | let inline_tests () = 54 | let t1 = App(Lam("x", Type.Int, Var "x"), Var "y") in 55 | assert (substitute "x" (Int 0) t1 = t1); 56 | assert (substitute "y" (Int 0) t1 = 57 | App(Lam("x", Type.Int, Var "x"), Int 0)); 58 | 59 | let t2 = Binop(Add, Var "x", Lam("x", Type.Int, Var "y")) in 60 | assert (substitute "x" (Int 0) t2 = 61 | Binop(Add, Int 0, Lam("x", Type.Int, Var "y"))); 62 | assert (substitute "y" (Int 0) t2 = 63 | Binop(Add, Var "x", Lam("x", Type.Int, Int 0))) 64 | 65 | (* Uncomment the line below when you want to run the inline tests. *) 66 | (* let () = inline_tests () *) 67 | 68 | 69 | let to_string e = Sexp.to_string_hum (sexp_of_t e) 70 | end 71 | -------------------------------------------------------------------------------- /assign2/program/src/ast.mli: -------------------------------------------------------------------------------- 1 | open Core 2 | 3 | module Type : sig 4 | type t = 5 | | Int 6 | | Fn of t * t 7 | | Product of t * t 8 | | Sum of t * t 9 | [@@deriving sexp_of, sexp, compare] 10 | 11 | val to_string : t -> string 12 | end 13 | 14 | module Expr : sig 15 | type binop = Add | Sub | Mul | Div 16 | [@@deriving sexp_of, sexp, compare] 17 | 18 | type direction = Left | Right 19 | [@@deriving sexp_of, sexp, compare] 20 | 21 | type t = 22 | | Var of string 23 | | Int of int 24 | | Binop of binop * t * t 25 | | Lam of string * Type.t * t 26 | | App of t * t 27 | | Pair of t * t 28 | | Project of t * direction 29 | | Inject of t * direction * Type.t 30 | | Case of t * (string * t) * (string * t) 31 | [@@deriving sexp_of, sexp, compare] 32 | 33 | val to_string : t -> string 34 | 35 | val substitute : string -> t -> t -> t 36 | end 37 | -------------------------------------------------------------------------------- /assign2/program/src/interpreter.ml: -------------------------------------------------------------------------------- 1 | open Core 2 | open Ast 3 | 4 | type outcome = 5 | | Step of Expr.t 6 | | Val 7 | 8 | exception RuntimeError of string 9 | exception Unimplemented 10 | 11 | (* You will implement the App, Binop, Pair, Project, Inject, and Case cases 12 | below. See the dynamics section for a specification on how the small step 13 | semantics should work. *) 14 | let rec trystep e = 15 | match e with 16 | | Expr.Var _ -> raise (RuntimeError "Unreachable") 17 | | (Expr.Lam _ | Expr.Int _) -> Val 18 | | Expr.App (fn, arg) -> raise Unimplemented 19 | | Expr.Binop (binop, left, right) -> raise Unimplemented 20 | | Expr.Pair (e1, e2) -> raise Unimplemented 21 | | Expr.Project (e, dir) -> raise Unimplemented 22 | | Expr.Inject (e, dir, tau) -> raise Unimplemented 23 | | Expr.Case (e, (x1, e1), (x2, e2)) -> raise Unimplemented 24 | 25 | let rec eval e = 26 | match trystep e with 27 | | Step e' -> eval e' 28 | | Val -> Ok e 29 | 30 | let inline_tests () = 31 | let e1 = Expr.Binop(Expr.Add, Expr.Int 2, Expr.Int 3) in 32 | assert (trystep e1 = Step(Expr.Int 5)); 33 | 34 | let e2 = Expr.App(Expr.Lam("x", Type.Int, Expr.Var "x"), Expr.Int 3) in 35 | assert (trystep e2 = Step(Expr.Int 3)) 36 | 37 | (* Uncomment the line below when you want to run the inline tests. *) 38 | (* let () = inline_tests () *) 39 | -------------------------------------------------------------------------------- /assign2/program/src/interpreter.mli: -------------------------------------------------------------------------------- 1 | open Core 2 | open Ast 3 | 4 | type outcome = 5 | | Step of Expr.t 6 | | Val 7 | 8 | (* Attempts to execute a small step in the term. *) 9 | val trystep : Expr.t -> outcome 10 | 11 | (* Reduces a term to a value, or an error if one occurs. *) 12 | val eval : Expr.t -> (Expr.t, string) Result.t 13 | -------------------------------------------------------------------------------- /assign2/program/src/lexer.mll: -------------------------------------------------------------------------------- 1 | { 2 | open Parser 3 | exception Error of string 4 | } 5 | 6 | rule token = parse 7 | | "(*" _* "*)" { token lexbuf } 8 | | [' ' '\t' '\n'] { token lexbuf } 9 | | '.' { DOT } 10 | | '(' { LPAREN } 11 | | ')' { RPAREN } 12 | | "fn" { FN } 13 | | "int" { TY_INT } 14 | | "->" { ARROW } 15 | | "=>" { FATARROW } 16 | | ":" { COLON } 17 | | '+' { PLUS } 18 | | '-' { SUB } 19 | | ',' { COMMA } 20 | | "as" { AS } 21 | | "inj" { INJECT } 22 | | '*' { MUL } 23 | | '/' { DIV } 24 | | 'R' { RIGHT } 25 | | 'L' { LEFT } 26 | | '|' { BAR } 27 | | '{' { LBRACE } 28 | | '}' { RBRACE } 29 | | '=' { EQUAL } 30 | | "case" { CASE } 31 | | ['a'-'z''A'-'Z']['a'-'z''A'-'Z''0'-'9']* as v { VAR v } 32 | | ['0'-'9']+ as i { INT (int_of_string i) } 33 | | '-'['0'-'9']+ as i { INT (int_of_string i) } 34 | | eof { EOF } 35 | | _ { raise (Error (Printf.sprintf "At offset %d: unexpected character.\n" (Lexing.lexeme_start lexbuf))) } 36 | -------------------------------------------------------------------------------- /assign2/program/src/main.ml: -------------------------------------------------------------------------------- 1 | open Core 2 | open Result.Monad_infix 3 | open Ast 4 | 5 | let parse input = 6 | let filebuf = Lexing.from_string input in 7 | try (Ok (Parser.main Lexer.token filebuf)) with 8 | | Lexer.Error msg -> Error msg 9 | | Parser.Error -> Error ( 10 | Printf.sprintf "Parse error: col %d" (Lexing.lexeme_start filebuf)) 11 | 12 | let interpret expr = 13 | Printf.printf "Expr: %s\n" (Expr.to_string expr); 14 | Typecheck.typecheck expr >>= fun ty -> 15 | Printf.printf "Type: %s\n" (Type.to_string ty); 16 | Interpreter.eval expr 17 | 18 | let run fileopt = 19 | match fileopt with 20 | | Some (filename) -> ( 21 | let input = In_channel.read_all filename in 22 | let result = parse input >>= interpret in 23 | match result with 24 | | Ok e -> Printf.printf "Success: %s\n" (Expr.to_string e) 25 | | Error s -> Printf.printf "Error: %s\n" s) 26 | | None -> () 27 | 28 | let main () = 29 | let open Command.Let_syntax in 30 | Command.basic 31 | ~summary:"Lam1 interpreter" 32 | [%map_open 33 | let filename = anon (maybe ("filename" %: string)) in 34 | fun () -> run filename 35 | ] 36 | |> Command.run 37 | 38 | let () = main () 39 | -------------------------------------------------------------------------------- /assign2/program/src/parser.mly: -------------------------------------------------------------------------------- 1 | %{ 2 | open Ast 3 | exception Unimplemented 4 | %} 5 | 6 | %token VAR 7 | %token EOF 8 | %token ARROW 9 | %token FATARROW 10 | %token DOT 11 | %token FN 12 | %token LPAREN 13 | %token RPAREN 14 | %token COLON 15 | %token PLUS 16 | %token SUB 17 | %token MUL 18 | %token DIV 19 | %token AS 20 | %token INJECT 21 | %token RIGHT 22 | %token LEFT 23 | %token RBRACE 24 | %token LBRACE 25 | %token COMMA 26 | %token EQUAL 27 | %token BAR 28 | %token CASE 29 | %token TY_INT 30 | %token INT 31 | 32 | %left PLUS SUB 33 | %left MUL DIV 34 | %right ARROW 35 | 36 | %start main 37 | 38 | %% 39 | 40 | main: 41 | | e = expr EOF { e } 42 | 43 | expr: 44 | | e1 = expr e2 = expr2 { Expr.App(e1, e2) } 45 | | e = expr2 { e } 46 | 47 | expr2: 48 | | e1 = expr2 b = binop e2 = expr2 { Expr.Binop(b, e1, e2) } 49 | | n = INT { Expr.Int(n) } 50 | | FN LPAREN v = VAR COLON t = ty RPAREN DOT e = expr { Expr.Lam(v, t, e) } 51 | | v = VAR { Expr.Var(v) } 52 | | LPAREN e1 = expr2 COMMA e2 = expr2 RPAREN { Expr.Pair(e1, e2) } 53 | | e = expr2 DOT d = dir { Expr.Project(e, d) } 54 | | INJECT e = expr2 EQUAL d = dir AS t = ty { Expr.Inject(e, d, t) } 55 | | CASE e = expr2 LBRACE LEFT LPAREN x1 = VAR RPAREN FATARROW e1 = expr2 BAR RIGHT LPAREN x2 = VAR RPAREN FATARROW e2 = expr2 RBRACE { Expr.Case(e, (x1, e1), (x2, e2)) } 56 | | LPAREN e = expr RPAREN { e } 57 | 58 | %inline binop: 59 | | PLUS { Expr.Add } 60 | | SUB { Expr.Sub } 61 | | MUL { Expr.Mul } 62 | | DIV { Expr.Div } 63 | 64 | ty: 65 | | TY_INT { Type.Int } 66 | | t1 = ty ARROW t2 = ty { Type.Fn(t1, t2) } 67 | | t1 = ty PLUS t2 = ty { Type.Sum(t1, t2) } 68 | | t1 = ty MUL t2 = ty { Type.Product(t1, t2) } 69 | | LPAREN t = ty RPAREN { t } 70 | 71 | dir: 72 | | LEFT {Expr.Left} 73 | | RIGHT {Expr.Right} 74 | -------------------------------------------------------------------------------- /assign2/program/src/typecheck.ml: -------------------------------------------------------------------------------- 1 | open Core 2 | open Result.Monad_infix 3 | open Ast 4 | 5 | exception Unimplemented 6 | 7 | (* You need to implement the statics for the three remaining cases below, 8 | * Var, Lam, and App. We have provided you with an implementation for Int 9 | * and Binop that you may refer to.*) 10 | let rec typecheck_term (env : Type.t String.Map.t) (e : Expr.t) : (Type.t, string) Result.t = 11 | match e with 12 | | Expr.Int _ -> Ok Type.Int 13 | | Expr.Binop (_, e1, e2) -> 14 | typecheck_term env e1 15 | >>= fun tau1 -> 16 | typecheck_term env e2 17 | >>= fun tau2 -> 18 | (match (tau1, tau2) with 19 | | (Type.Int, Type.Int) -> Ok Type.Int 20 | | _ -> Error ("One of the binop operands is not an int")) 21 | | Expr.Var x -> raise Unimplemented 22 | | Expr.Lam(x, arg_tau, e') -> raise Unimplemented 23 | | Expr.App (fn, arg) -> raise Unimplemented 24 | | Expr.Pair (e1, e2) -> raise Unimplemented 25 | | Expr.Project (e, d) -> raise Unimplemented 26 | | Expr.Inject (e, d, tau) -> raise Unimplemented 27 | | Expr.Case (e, (x1, e1), (x2, e2)) -> raise Unimplemented 28 | 29 | let typecheck t = typecheck_term String.Map.empty t 30 | 31 | let inline_tests () = 32 | let e1 = Expr.Lam ("x", Type.Int, Expr.Var "x") in 33 | assert (typecheck e1 = Ok(Type.Fn(Type.Int, Type.Int))); 34 | 35 | let e2 = Expr.Lam ("x", Type.Int, Expr.Var "y") in 36 | assert (Result.is_error (typecheck e2)); 37 | 38 | let t3 = Expr.App (e1, Expr.Int 3) in 39 | assert (typecheck t3 = Ok(Type.Int)); 40 | 41 | let t4 = Expr.App (t3, Expr.Int 3) in 42 | assert (Result.is_error (typecheck t4)); 43 | 44 | let t5 = Expr.Binop (Expr.Add, Expr.Int 0, e1) in 45 | assert (Result.is_error (typecheck t5)) 46 | 47 | (* Uncomment the line below when you want to run the inline tests. *) 48 | (* let () = inline_tests () *) 49 | -------------------------------------------------------------------------------- /assign2/program/src/typecheck.mli: -------------------------------------------------------------------------------- 1 | open Core 2 | open Ast 3 | 4 | (* Returns the type of the term, or an error if it fails to typecheck. *) 5 | val typecheck : Expr.t -> (Type.t, string) Result.t 6 | -------------------------------------------------------------------------------- /assign2/program/tests/binop1.lam1: -------------------------------------------------------------------------------- 1 | 3 + 7 -------------------------------------------------------------------------------- /assign2/program/tests/binop2.lam1: -------------------------------------------------------------------------------- 1 | 3 - (2 * 7) * 2 -------------------------------------------------------------------------------- /assign2/program/tests/binop3.lam1: -------------------------------------------------------------------------------- 1 | -1 - 7 -------------------------------------------------------------------------------- /assign2/program/tests/binop_fail1.lam1: -------------------------------------------------------------------------------- 1 | 3 ++ 4 -------------------------------------------------------------------------------- /assign2/program/tests/binop_fail2.lam1: -------------------------------------------------------------------------------- 1 | 3 -7 -------------------------------------------------------------------------------- /assign2/program/tests/binop_zero1.lam1: -------------------------------------------------------------------------------- 1 | 7 / 0 -------------------------------------------------------------------------------- /assign2/program/tests/case1.lam2: -------------------------------------------------------------------------------- 1 | case (inj 1 = R as int+int) {L(x) => 1 | R(y) => 9} -------------------------------------------------------------------------------- /assign2/program/tests/case_fail1.lam2: -------------------------------------------------------------------------------- 1 | case (inj 1 = R as int+int) {L(x) => 1 | R(y) => fn (x: int) . x} -------------------------------------------------------------------------------- /assign2/program/tests/function_apply1.lam1: -------------------------------------------------------------------------------- 1 | (fn (x: int) . x * 7) 20 -------------------------------------------------------------------------------- /assign2/program/tests/function_apply2.lam1: -------------------------------------------------------------------------------- 1 | (fn (x: int) . fn (y: int) . fn (x: int) . x + y) 3 7 8 -------------------------------------------------------------------------------- /assign2/program/tests/function_apply_error1.lam1: -------------------------------------------------------------------------------- 1 | (fn (f: int -> int -> int) . f 3) (fn (x: int) . x * x) -------------------------------------------------------------------------------- /assign2/program/tests/function_error1.lam1: -------------------------------------------------------------------------------- 1 | fn (hey: int). testing -------------------------------------------------------------------------------- /assign2/program/tests/function_type1.lam1: -------------------------------------------------------------------------------- 1 | (fn (x: int -> int). 3 + (x 7)) -------------------------------------------------------------------------------- /assign2/program/tests/function_type2.lam1: -------------------------------------------------------------------------------- 1 | fn (sup: int -> int -> int) . 3 -------------------------------------------------------------------------------- /assign2/program/tests/function_type3.lam1: -------------------------------------------------------------------------------- 1 | (fn (john: int -> int -> int) . john 37 13) (fn (et: int) . (fn (le: int) . le * 100 + et ) ) -------------------------------------------------------------------------------- /assign2/program/tests/inject1.lam2: -------------------------------------------------------------------------------- 1 | inj 1 = L as int+int*int -------------------------------------------------------------------------------- /assign2/program/tests/inject2.lam2: -------------------------------------------------------------------------------- 1 | inj (4,5) = R as int+int*int -------------------------------------------------------------------------------- /assign2/program/tests/inject_fail1.lam2: -------------------------------------------------------------------------------- 1 | inj 1 = R as int+int*int -------------------------------------------------------------------------------- /assign2/program/tests/pair1.lam2: -------------------------------------------------------------------------------- 1 | (fn (x : int) . (x, 2)) 5 2 | -------------------------------------------------------------------------------- /assign2/program/tests/pair2.lam2: -------------------------------------------------------------------------------- 1 | (fn (y : int*int*int) . ((fn (x : int) . x))) ((5, 3), 4) 9 -------------------------------------------------------------------------------- /assign2/program/tests/pair_fail1.lam2: -------------------------------------------------------------------------------- 1 | (fn (x : int) . (x, 2)) (2, 5) 2 | -------------------------------------------------------------------------------- /assign2/program/tests/project1.lam2: -------------------------------------------------------------------------------- 1 | fn (x: int*int) . x.L -------------------------------------------------------------------------------- /assign2/program/tests/project_fail1.lam2: -------------------------------------------------------------------------------- 1 | ((3, 1), 0).R.L -------------------------------------------------------------------------------- /assign2/program/tests/simple_fail1.lam1: -------------------------------------------------------------------------------- 1 | 3 4 -------------------------------------------------------------------------------- /assign2/program/tests/simple_fail2.lam1: -------------------------------------------------------------------------------- 1 | (fn (x: int) . x * 7) + 3 -------------------------------------------------------------------------------- /assign2/written/Makefile: -------------------------------------------------------------------------------- 1 | TEX := pdflatex 2 | FLAGS := -shell-escape 3 | 4 | all: assign2.pdf 5 | 6 | %.pdf: %.tex 7 | ${TEX} ${FLAGS} $^ 8 | 9 | check: 10 | aspell -t -c *.tex 11 | 12 | clean: 13 | rm -rf *.aux *.log *.out *.pdf _minted-* 14 | -------------------------------------------------------------------------------- /assign2/written/assign2.tex: -------------------------------------------------------------------------------- 1 | \documentclass[11pt]{article} 2 | 3 | \input{./defs.tex} 4 | 5 | \begin{document} 6 | 7 | \hwtitle 8 | {Assignment 2} 9 | {Will Crichton (wcrichto)} %% REPLACE THIS WITH YOUR NAME/ID 10 | 11 | Your answer goes here. Here's the dynamically-scoped untyped lambda calculus operational semantics as examples of writing inference rules. 12 | 13 | \begin{mathpar} 14 | \ir{V-Lam}{ \ }{\val{\fun{x}{e}}} 15 | 16 | \ir{D-Var} 17 | {\ctx(x) = e} 18 | {\dynJC{\steps{x}{e}}} 19 | 20 | \ir{D-App$_1$} 21 | {\dynJC{\steps{e_1}{e_1'}}} 22 | {\dynJC{\steps{\app{e_1}{e_2}}{\app{e_1'}{e_2}}}} 23 | 24 | \ir{D-App$_2$} 25 | {\dynJ{\ctx, x \rightarrow e_2}{\steps{e_1}{e_1'}}} 26 | {\dynJC{\steps{\app{(\fun{x}{e_1})}{e_2}}{\app{(\fun{x}{e_1'})}{e_2}}}} 27 | 28 | \ir{D-App$_3$} 29 | {\val{e_1}} 30 | {\dynJC{\steps{\app{(\fun{x}{e_1})}{e_2}}{e_1}}} 31 | \end{mathpar} 32 | 33 | \end{document} 34 | -------------------------------------------------------------------------------- /assign2/written/defs.tex: -------------------------------------------------------------------------------- 1 | %%% PACKAGES 2 | 3 | \usepackage{fullpage} % 1 page margins 4 | \usepackage{latexsym} % extra symbols, e.g. \leadsto 5 | \usepackage{verbatim} % verbatim mode 6 | \usepackage{proof} % proof mode 7 | \usepackage{amsthm,amssymb,amsmath} % various math symbols 8 | \usepackage{color} % color control 9 | \usepackage{etoolbox} % misc utilities 10 | \usepackage{graphics} % images 11 | \usepackage{mathpartir}% inference rules 12 | \usepackage{hyperref} % hyperlinks 13 | \usepackage{titlesec} % title/section controls 14 | \usepackage{minted} % code blocks 15 | \usepackage{tocstyle} % table of contents styling 16 | \usepackage[hang,flushmargin]{footmisc} % No indent footnotes 17 | \usepackage{parskip} % no parindent 18 | \usepackage{tikz} % drawing figures 19 | \usepackage[T1]{fontenc} 20 | %%% COMMANDS 21 | 22 | % Typography and symbols 23 | \newcommand{\msf}[1]{\mathsf{#1}} 24 | \newcommand{\ctx}{\Gamma} 25 | \newcommand{\qamp}{&\quad} 26 | \newcommand{\qqamp}{&&\quad} 27 | \newcommand{\Coloneqq}{::=} 28 | \newcommand{\proves}{\vdash} 29 | \newcommand{\str}[1]{#1^{*}} 30 | \newcommand{\eps}{\varepsilon} 31 | \newcommand{\brc}[1]{\{{#1}\}} 32 | 33 | % Untyped lambda calculus 34 | \newcommand{\fun}[2]{\lambda ~ {#1} ~ . ~ {#2}} 35 | \newcommand{\app}[2]{#1 ~ #2} 36 | 37 | % Typed lambda calculus - expressions 38 | \newcommand{\funt}[3]{\lambda ~ \left(#1 : #2\right) ~ . ~ #3} 39 | \newcommand{\lett}[4]{\msf{let} ~ \hasType{#1}{#2} = #3 ~ \msf{in} ~ #4} 40 | \newcommand{\rec}[3]{\msf{rec}(#1; ~ x.y.#2)(#3)} 41 | \newcommand{\case}[5]{\msf{case} ~ {#1} ~ \{ L(#2) \to #3 \mid R(#4) \to #5 \}} 42 | \newcommand{\pair}[2]{\left({#1},{#2}\right)} 43 | \newcommand{\proj}[2]{#1 . #2} 44 | \newcommand{\inj}[3]{\msf{inj} ~ #1 = #2 ~ \msf{as} ~ #3} 45 | \newcommand{\letv}[3]{\msf{let} ~ {#1} = {#2} ~ \msf{in} ~ {#3}} 46 | 47 | % Typed lambda calculus - types 48 | \newcommand{\tprod}[2]{#1 \times #2} 49 | \newcommand{\tsum}[2]{#1 + #2} 50 | 51 | % WebAssembly 52 | \newcommand{\wconst}[1]{\msf{i32.const}~{#1}} 53 | \newcommand{\wbinop}[1]{\msf{i32}.{#1}} 54 | \newcommand{\wgetlocal}[1]{\msf{get\_local}~{#1}} 55 | \newcommand{\wsetlocal}[1]{\msf{set\_local}~{#1}} 56 | \newcommand{\wload}{\msf{i32.load}} 57 | \newcommand{\wstore}{\msf{i32.store}} 58 | \newcommand{\wsize}{\msf{memory.size}} 59 | \newcommand{\wgrow}{\msf{memory.grow}} 60 | \newcommand{\wunreachable}{\msf{unreachable}} 61 | \newcommand{\wblock}[1]{\msf{block}~{#1}} 62 | \newcommand{\wblockr}[2]{\msf{block}~{#1}~{#2}} 63 | \newcommand{\wloop}[1]{\msf{loop}~{#1}} 64 | \newcommand{\wbr}[1]{\msf{br}~{#1}} 65 | \newcommand{\wbrif}[1]{\msf{br\_if}~{#1}} 66 | \newcommand{\wreturn}{\msf{return}} 67 | \newcommand{\wcall}[1]{\msf{call}~{#1}} 68 | \newcommand{\wlabel}[3]{\msf{label}_{#1}~\{#2\}~{#3}} 69 | \newcommand{\wframe}[1]{\msf{frame}~{#1}} 70 | \newcommand{\wtrapping}{\msf{trapping}} 71 | \newcommand{\wbreaking}[2]{\msf{breaking}_{#1}~{#2}} 72 | \newcommand{\wreturning}[1]{\msf{returning}~{#1}} 73 | \newcommand{\wconfig}[5]{\{\msf{module}~{#1};~\msf{mem}~{#2};~\msf{locals}~{#3};~\msf{stack}~{#4};~\msf{instrs}~{#5}\}} 74 | \newcommand{\wfunc}[3]{\{\msf{params}~{#1};~\msf{locals}~{#2};~\msf{body}~{#3}\}} 75 | \newcommand{\wmodule}[1]{\{\msf{funcs}~{#1}\}} 76 | 77 | \newcommand{\semi}[2]{{#1};~{#2}} 78 | \newcommand{\semii}[3]{{#1};~{#2};~{#3}} 79 | \newcommand{\semiii}[4]{{#1};~{#2};~{#3};~{#4}} 80 | \newcommand{\semiiii}[5]{{#1};~{#2};~{#3};~{#4};~{#5}} 81 | \newcommand{\wci}{\msf{instrs}} 82 | \newcommand{\wcs}{\msf{stack}} 83 | \newcommand{\wcl}{\msf{locals}} 84 | \newcommand{\wcm}{\msf{mem}} 85 | \newcommand{\wcmod}{\msf{module}} 86 | \newcommand{\wsteps}[2]{\steps{\brc{#1}}{\brc{#2}}} 87 | 88 | % Inference rules 89 | %\newcommand{\inferrule}[3][]{\cfrac{#2}{#3}\;{#1}} 90 | \newcommand{\ir}[3]{\inferrule*[right=\text{(#1)}]{#2}{#3}} 91 | \newcommand{\s}{\hspace{1em}} 92 | \newcommand{\nl}{\\[2em]} 93 | \newcommand{\steps}[2]{#1 \boldsymbol{\mapsto} #2} 94 | \newcommand{\subst}[3]{[#1 \rightarrow #2] ~ #3} 95 | \newcommand{\dynJ}[2]{#1 \proves #2} 96 | \newcommand{\dynJC}[1]{\dynJ{\ctx}{#1}} 97 | \newcommand{\typeJ}[3]{#1 \proves \hasType{#2}{#3}} 98 | \newcommand{\typeJC}[2]{\typeJ{\ctx}{#1}{#2}} 99 | \newcommand{\hasType}[2]{#1 : #2} 100 | \newcommand{\val}[1]{#1~\msf{val}} 101 | \newcommand{\num}[1]{\msf{Int}(#1)} 102 | \newcommand{\err}[1]{#1~\msf{err}} 103 | \newcommand{\trans}[2]{#1 \leadsto #2} 104 | \newcommand{\size}[1]{\left|#1\right|} 105 | 106 | 107 | \newcommand{\hwtitle}[2]{\begin{center}{\Large #1} \\[0.5em] {\large #2}\end{center}\vspace{1em}} 108 | \newcommand{\toc}{{\hypersetup{hidelinks}\tableofcontents}} 109 | \newcommand{\problem}[1]{\section*{#1}} 110 | 111 | %%% CONFIG 112 | 113 | % Spacing around title/sections 114 | \titlelabel{\thetitle.\quad} 115 | \titlespacing*{\section}{0pt}{10pt}{0pt} 116 | \titlespacing*{\subsection}{0pt}{10pt}{0pt} 117 | 118 | 119 | % Show color on hyperlinks 120 | \hypersetup{colorlinks=true} 121 | 122 | % Stylize code blocks 123 | \usemintedstyle{xcode} 124 | % TODO(wcrichto): remove line of spacing beneath code blocks 125 | \newcommand{\nm}[2]{ 126 | \newminted{#1}{#2} 127 | \newmint{#1}{#2} 128 | \newmintinline{#1}{#2}} 129 | \nm{lua}{} 130 | \nm{ocaml}{} 131 | \nm{rust}{} 132 | \nm{prolog}{} 133 | 134 | \newcommand{\ml}[1]{\ocamlinline|#1|} 135 | 136 | \usetocstyle{standard} 137 | -------------------------------------------------------------------------------- /assign3/program/Makefile: -------------------------------------------------------------------------------- 1 | all: stream2.native list2.native 2 | 3 | BUILD = corebuild 4 | FLAGS = -use-ocamlfind -use-menhir 5 | 6 | %.native: always 7 | $(BUILD) $(FLAGS) src/$@ 8 | 9 | clean: 10 | rm -rf *.native *.top _build 11 | 12 | always: 13 | 14 | .PHONY: always 15 | -------------------------------------------------------------------------------- /assign3/program/_tags: -------------------------------------------------------------------------------- 1 | : annot, bin_annot, thread 2 | -------------------------------------------------------------------------------- /assign3/program/src/list2.ml: -------------------------------------------------------------------------------- 1 | open Core 2 | 3 | exception Unimplemented 4 | 5 | module type List2 = sig 6 | type 'a list = Cons of 'a * 'a list | Nil 7 | 8 | val foldr : ('a -> 'b -> 'b) -> 'b -> 'a list -> 'b 9 | val map : ('a -> 'b) -> 'a list -> 'b list 10 | val filter : ('a -> bool) -> 'a list -> 'a list 11 | val reduce : ('a -> 'a -> 'a) -> 'a list -> 'a option 12 | val combine_keys : ('a * 'b) list -> ('a * ('b list)) list 13 | val to_string : ('a -> string) -> 'a list -> string 14 | end 15 | 16 | module MyList : List2 = struct 17 | type 'a list = Cons of 'a * 'a list | Nil 18 | 19 | let rec foldr f base l = 20 | raise Unimplemented 21 | 22 | let to_string f l = 23 | raise Unimplemented 24 | 25 | let map f l = 26 | raise Unimplemented 27 | 28 | let rec filter f l = 29 | raise Unimplemented 30 | 31 | let reduce f l = 32 | raise Unimplemented 33 | 34 | let combine_keys l = 35 | raise Unimplemented 36 | end 37 | 38 | module ListTests(L : List2) = struct 39 | open L ;; 40 | 41 | let l = Cons(("b", 3), Cons(("a", 2), Cons(("a", 1), Nil))) in 42 | assert( 43 | (to_string (fun (s, n) -> Printf.sprintf "(%s, %s)" s (string_of_int n)) l) 44 | = "(b, 3) (a, 2) (a, 1) "); 45 | 46 | let l = combine_keys l in 47 | assert( 48 | l = Cons(("a", Cons(2, Cons(1, Nil))), Cons(("b", Cons(3, Nil)), Nil)) 49 | || 50 | l = Cons(("b", Cons(3, Nil)), Cons(("a", Cons(2, Cons(1, Nil))), Nil)) 51 | ); 52 | 53 | let m = map (fun x -> x+1) (Cons(1, Cons(2, Cons(3, Cons(4, Cons(5, Nil)))))) in 54 | assert (m = Cons(2, Cons(3, Cons(4, Cons(5, Cons(6, Nil)))))); 55 | 56 | let m = map (fun x -> x*2) (Cons(1, Cons(2, Cons(3, Cons(4, Cons(5, Nil)))))) in 57 | assert (m = Cons(2, Cons(4, Cons(6, Cons(8, Cons(10, Nil)))))); 58 | 59 | let m = foldr (max) 0 (Cons(1, Cons(2, Cons(3, Cons(4, Cons(5, Nil)))))) in 60 | assert (m = 5); 61 | 62 | let m = foldr (+) 0 (Cons(1, Cons(2, Cons(3, Cons(4, Cons(5, Nil)))))) in 63 | assert (m = 15); 64 | 65 | let m = reduce (+) (Cons(1, Cons(2, Cons(3, Cons(4, Cons(5, Nil)))))) in 66 | assert (m = Some 15); 67 | 68 | let m = reduce (max) (Cons(1, Cons(2, Cons(3, Cons(4, Cons(5, Nil)))))) in 69 | assert (m = Some 5); 70 | 71 | let m = filter (fun x -> (x mod 2) = 0) (Cons(1, Cons(2, Cons(3, Cons(4, Cons(5, Nil)))))) in 72 | assert (m = Cons(2, Cons(4, Nil))); 73 | 74 | let m = filter (fun x -> (x < 0)) (Cons(-1, Cons(2, Cons(100, Cons(0, Cons(-5, Nil)))))) in 75 | assert (m = Cons(-1, Cons(-5, Nil))); 76 | 77 | end 78 | 79 | module MyListTests = ListTests(MyList) -------------------------------------------------------------------------------- /assign3/program/src/stream2.ml: -------------------------------------------------------------------------------- 1 | open Core 2 | open List2.MyList 3 | 4 | exception Unimplemented 5 | 6 | module type Stream2 = sig 7 | type 'a stream = Stream of (unit -> 'a * 'a stream) 8 | val head : 'a stream -> 'a 9 | val tail : 'a stream -> 'a stream 10 | val take : 'a stream -> int -> 'a list * 'a stream 11 | val zip : 'a stream -> 'b stream -> ('a * 'b) stream 12 | val enumerate : 'a stream -> (int * 'a) stream 13 | val windows : 'a stream -> int -> ('a list) stream 14 | end 15 | 16 | module MyStream : Stream2 = struct 17 | type 'a stream = Stream of (unit -> 'a * 'a stream) 18 | 19 | let head (Stream f) = 20 | raise Unimplemented 21 | 22 | let tail (Stream f) = 23 | raise Unimplemented 24 | 25 | let rec take s n = 26 | raise Unimplemented 27 | 28 | let rec zip (Stream a) (Stream b) = 29 | raise Unimplemented 30 | 31 | let enumerate s = 32 | raise Unimplemented 33 | 34 | let rec windows s n = 35 | raise Unimplemented 36 | end 37 | 38 | module StreamTests(S : Stream2) = struct 39 | open S ;; 40 | 41 | let rec repeat (n : int) : int stream = 42 | Stream (fun () -> (n, repeat (n))) 43 | ;; 44 | let s = enumerate (repeat 1) in 45 | assert (head s = (0, 1)); 46 | assert (head (tail s) = (1, 1)); 47 | assert (head (tail (tail s)) = (2, 1)); 48 | assert (head (tail (tail (tail s))) = (3, 1)); 49 | 50 | let s = zip (repeat 1) (repeat 2) in 51 | assert (head s = (1, 2)); 52 | assert (head (tail s) = (1, 2)); 53 | assert (head (tail (tail s)) = (1, 2)); 54 | 55 | let s = enumerate (repeat 5) in 56 | let (l, s) = take s 2 in 57 | assert (l = Cons((0, 5), Cons((1, 5), Nil))); 58 | assert (head s = (2, 5)); 59 | 60 | let s = windows (repeat 4) 3 in 61 | assert (head s = (Cons(4, Cons(4, Cons(4, Nil))))); 62 | assert (head (tail s) = (Cons(4, Cons(4, Cons(4, Nil))))) 63 | ;; 64 | 65 | let rec upfrom (n : int) : int stream = 66 | raise Unimplemented 67 | ;; 68 | 69 | let s = upfrom 5 in 70 | assert (head s = 5); 71 | assert (head (tail s) = 6); 72 | 73 | let s = enumerate (upfrom 5) in 74 | let (l, s) = take s 2 in 75 | assert (l = Cons((0, 5), Cons((1, 6), Nil))); 76 | assert (head s = (2, 7)); 77 | 78 | let s = windows (upfrom 4) 3 in 79 | assert (head s = (Cons(4, Cons(5, Cons(6, Nil))))); 80 | assert (head (tail s) = (Cons(5, Cons(6, Cons(7, Nil))))) 81 | ;; 82 | 83 | let fib () : int stream = 84 | raise Unimplemented 85 | ;; 86 | 87 | let s = fib () in 88 | assert (head s = 0); 89 | assert (head (tail s) = 1); 90 | assert (head (tail (tail s)) = 1); 91 | assert (head (tail (tail (tail s))) = 2); 92 | 93 | let s = zip (fib ()) (repeat 2) in 94 | assert (head s = (0, 2)); 95 | assert (head (tail s) = (1, 2)); 96 | assert (head (tail (tail s)) = (1, 2)); 97 | assert (head (tail (tail (tail s))) = (2,2)); 98 | 99 | end 100 | 101 | module MyStreamTests = StreamTests(MyStream) 102 | -------------------------------------------------------------------------------- /assign3/written/Makefile: -------------------------------------------------------------------------------- 1 | TEX := pdflatex 2 | FLAGS := -shell-escape 3 | 4 | all: assign3.pdf 5 | 6 | %.pdf: %.tex 7 | ${TEX} ${FLAGS} $^ 8 | 9 | check: 10 | aspell -t -c *.tex 11 | 12 | clean: 13 | rm -rf *.aux *.log *.out *.pdf _minted-* 14 | -------------------------------------------------------------------------------- /assign3/written/assign3.tex: -------------------------------------------------------------------------------- 1 | \documentclass[11pt]{article} 2 | 3 | \input{./defs.tex} 4 | 5 | \begin{document} 6 | 7 | \hwtitle 8 | {Assignment 3} 9 | {Will Crichton (wcrichto)} %% REPLACE THIS WITH YOUR NAME/ID 10 | 11 | \problem{Problem 3} 12 | 13 | Your answer goes here. Here's a few examples of complex types and expressions. 14 | 15 | \begin{align*} 16 | \msf{list} &= \tpoly{\alpha}{\trec{\beta}{\tsum{\tunit}{(\tprod{\alpha}{\beta})}}} \\ 17 | \msf{nil} &= \poly{\alpha}{\fold{(\inj{()}{L}{\tsum{\tunit}{(\tprod{\alpha}{\beta})}})}{\trec{\beta}{\tsum{\tunit}{(\tprod{\alpha}{\beta})}}}} \\ 18 | \end{align*} 19 | 20 | \end{document} 21 | -------------------------------------------------------------------------------- /assign4/program/.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | node_modules/ 3 | -------------------------------------------------------------------------------- /assign4/program/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "start": "webpack-dev-server -d --open", 4 | "build": "webpack", 5 | "format": "prettier --write src/**/*.js" 6 | }, 7 | "devDependencies": { 8 | "html-webpack-plugin": "^3.2.0", 9 | "prettier": "^1.14.3", 10 | "webpack": "^4.16.1", 11 | "webpack-cli": "^3.1.0", 12 | "webpack-dev-server": "^3.1.4", 13 | "buffer-loader": "^0.1.0" 14 | }, 15 | "dependencies": { 16 | "chai": "^4.2.0", 17 | "wabt": "^1.0.5" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /assign4/program/src/hash.wat: -------------------------------------------------------------------------------- 1 | (module 2 | (memory 1) 3 | (export "mem" (memory 0)) 4 | 5 | ;; Stack-based Adler32 hash implementation. 6 | (func $adler32 (param $address i32) (param $len i32) (result i32) 7 | (local $a i32) (local $b i32) (local $i i32) 8 | 9 | ;; YOUR CODE GOES HERE 10 | (i32.const 0) 11 | ) 12 | (export "adler32" (func $adler32)) 13 | 14 | ;; Tree-based Adler32 hash implementation. 15 | (func $adler32v2 (param $address i32) (param $len i32) (result i32) 16 | (local $a i32) (local $b i32) (local $i i32) 17 | 18 | ;; YOUR CODE GOES HERE 19 | (i32.const 0) 20 | ) 21 | 22 | (export "adler32v2" (func $adler32v2)) 23 | 24 | ;; Initialize memory allocator. Creates the initial block assuming memory starts with 25 | ;; 1 page. 26 | (func $alloc_init 27 | (i32.store (i32.const 0) (i32.const 65528)) 28 | (i32.store (i32.const 4) (i32.const 1))) 29 | (export "alloc_init" (func $alloc_init)) 30 | 31 | ;; Frees a memory block by setting the free bit to 1. 32 | (func $free (param $address i32) 33 | (i32.store 34 | (i32.sub (get_local $address) (i32.const 4)) 35 | (i32.const 1))) 36 | (export "free" (func $free)) 37 | 38 | (func $alloc (param $len i32) (result i32) 39 | ;; YOUR CODE GOES HERE 40 | (unreachable) 41 | ) 42 | (export "alloc" (func $alloc)) 43 | 44 | ) 45 | -------------------------------------------------------------------------------- /assign4/program/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Assignment 4 Testing Tool 12 | 13 | 14 | 15 |
16 | 19 |
20 | 21 |
22 |
23 |
24 |
25 |
26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /assign4/program/src/index.js: -------------------------------------------------------------------------------- 1 | const wat = require("buffer-loader!./hash.wat"); 2 | const wabt = require("wabt")(); 3 | const getTests = require("./tests"); 4 | 5 | // Utility function that returns a delay promise. 6 | const delay = t => new Promise(resolve => setTimeout(resolve, t)); 7 | const waitTick = () => delay(0); 8 | 9 | const module = Promise.resolve(wat).then(wat => wabt.parseWat("hash.wat", wat)); 10 | 11 | // Show WASM parsing error. 12 | module.catch(e => 13 | $("#output").html(`
14 | Error While Parsing hash.wat 15 |
${e}
`) 16 | ); 17 | 18 | const validated = module.then(module => { 19 | module.resolveNames(); 20 | module.validate(); 21 | return module; 22 | }); 23 | 24 | // Show WASM validation error. 25 | validated.catch(e => 26 | $("#output").html(`
27 | Error while validating hash.wat 28 |
${e}
`) 29 | ); 30 | 31 | // A promise that resolves to the binary WASM module. 32 | const binary = validated.then( 33 | module => module.toBinary({ write_debug_names: false }).buffer 34 | ); 35 | 36 | // Return a promise that resolves to the WASM module imports. This is 37 | // done so that we can get a fresh allocator context each time. 38 | const getModule = () => 39 | binary 40 | .then(buffer => WebAssembly.instantiate(buffer, {})) 41 | .then(result => result.instance.exports); 42 | 43 | const formatError = e => { 44 | let message = e.toString(); 45 | if (e.showDiff) { 46 | message += "\nExpected: " + JSON.stringify(e.expected, undefined, 2); 47 | message += "\nActual: " + JSON.stringify(e.actual, undefined, 2); 48 | } 49 | return message; 50 | }; 51 | 52 | // Get the wasm module and run it's imports through `test`, writing results 53 | // to the output. 54 | const runTest = (name, test) => 55 | getModule() 56 | .then(test) 57 | .then(() => 58 | $("#output").append(`
59 | 60 | ${name} passed.
`) 61 | ) 62 | .catch(e => 63 | $("#output").append(`
64 | 65 | ${name} failed.

${formatError(
66 |         e
67 |       )}
`) 68 | ) 69 | .then(waitTick); 70 | 71 | // The list of tests to execute. 72 | const tests = getTests(runTest); 73 | 74 | // Execute tests. 75 | tests 76 | .reduce( 77 | (acc, test, i) => 78 | acc.then(test).then(() => { 79 | let progress = 10 + ((i + 1) / tests.length) * 90; 80 | $("#progress").width(`${progress}%`); 81 | }), 82 | binary.then(() => $("#progress").width("10%")).then(waitTick) 83 | ) 84 | .then(() => delay(1000)) 85 | .then(() => $("#progress-bar").fadeOut()); 86 | -------------------------------------------------------------------------------- /assign4/program/webpack.config.js: -------------------------------------------------------------------------------- 1 | const HtmlWebpackPlugin = require('html-webpack-plugin') 2 | 3 | const path = require("path"); 4 | 5 | module.exports = { 6 | entry: "./src/index.js", 7 | output: { 8 | path: path.resolve(__dirname, "dist"), 9 | filename: "bundle.js", 10 | }, 11 | node: { 12 | fs: 'empty' 13 | }, 14 | mode: "development", 15 | plugins: [ 16 | new HtmlWebpackPlugin({ 17 | template: 'src/index.html' 18 | }), 19 | ], 20 | }; 21 | -------------------------------------------------------------------------------- /assign4/written/Makefile: -------------------------------------------------------------------------------- 1 | TEX := pdflatex 2 | FLAGS := -shell-escape 3 | 4 | all: assign4.pdf 5 | 6 | %.pdf: %.tex 7 | ${TEX} ${FLAGS} $^ 8 | 9 | check: 10 | aspell -t -c *.tex 11 | 12 | clean: 13 | rm -rf *.aux *.log *.out *.pdf _minted-* 14 | -------------------------------------------------------------------------------- /assign4/written/assign4.tex: -------------------------------------------------------------------------------- 1 | \documentclass[11pt]{article} 2 | 3 | \input{defs.tex} 4 | 5 | \begin{document} 6 | 7 | \hwtitle 8 | {Assignment 4} 9 | {Will Crichton (wcrichto)} %% REPLACE THIS WITH YOUR NAME/ID 10 | 11 | \problem{Problem 3} 12 | 13 | \begin{mathpar} 14 | \ir{D-Raise} 15 | {\ } 16 | {\wsteps{\wcs~n;~\wci~\wraise}{\wci~\wraising{n}}} 17 | 18 | \ir{D-Label-Raising} 19 | {\ } 20 | {\wsteps 21 | {\wci~\wlabel{\_}{\_}{\wraising{n}}} 22 | {\wci~\wraising{n}}} 23 | 24 | \end{mathpar} 25 | 26 | \end{document} 27 | -------------------------------------------------------------------------------- /assign5/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "assign5" 3 | version = "0.1.0" 4 | authors = ["Will Crichton "] 5 | 6 | [dependencies] 7 | clap = "2.32" 8 | nom = "4.0" 9 | 10 | [lib] 11 | name = "memory" 12 | path = "src/memory.rs" 13 | 14 | [[bin]] 15 | name = "assign5" 16 | path = "src/main.rs" -------------------------------------------------------------------------------- /assign5/make_submission.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cd src 3 | zip -r -0 assign5.zip * 4 | mv assign5.zip .. 5 | -------------------------------------------------------------------------------- /assign5/run_tests.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import unittest 4 | import subprocess 5 | import re 6 | 7 | # RUN FROM assign5/program 8 | 9 | TESTS = { 10 | "binop": "Success: 5", 11 | "block": "Success: 1", 12 | "func_call": "Success: 8", 13 | "load_invalid": "Error", 14 | "load_store": "Success: 8", 15 | "local": "Success: 24", 16 | "loop": "Success: 5", 17 | "mem_grow": "Success: 8192", 18 | "relop": "Success: 0", 19 | "return": "Success: 2", 20 | "unreachable": "Error", 21 | } 22 | 23 | 24 | def create_testfunc(tname, ext): 25 | testdir = os.path.abspath('tests') 26 | def func(*args): 27 | _self = args[0] 28 | tfile = os.path.join(testdir, "%s.%s" % (tname, ext)) 29 | out = subprocess.check_output(['cargo', 'run', tfile], stderr=subprocess.DEVNULL).decode('UTF-8').strip() 30 | res = re.search(r'Success:.*', out, flags=re.DOTALL) 31 | if not res: 32 | res = re.search(r'Error:.*', out, flags=re.DOTALL) 33 | _self.assertIn(TESTS[tname], res.group(0)) 34 | return func 35 | 36 | 37 | def add_testfuncs(cls): 38 | for tpath in sorted(os.listdir('tests')): 39 | if '.wat' not in tpath: continue 40 | name, ext = tpath.split('.') 41 | setattr(cls, 'test_%s' % name, create_testfunc(name, ext)) 42 | return cls 43 | 44 | 45 | @add_testfuncs 46 | class TestWAInterpreter(unittest.TestCase): 47 | pass 48 | 49 | 50 | if __name__ == '__main__': 51 | unittest.main(verbosity=2, argv=sys.argv[:1]) 52 | 53 | 54 | -------------------------------------------------------------------------------- /assign5/solution_linux: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-cs242/f18-assignments/0646cc427e126f105654405323c4074db3015f56/assign5/solution_linux -------------------------------------------------------------------------------- /assign5/solution_mac: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-cs242/f18-assignments/0646cc427e126f105654405323c4074db3015f56/assign5/solution_mac -------------------------------------------------------------------------------- /assign5/src/ast.rs: -------------------------------------------------------------------------------- 1 | extern crate memory; 2 | 3 | use memory::WMemory; 4 | 5 | #[derive(Debug, PartialEq, Clone, Eq)] 6 | pub enum WBinop { Add, Sub, Mul, DivS } 7 | 8 | #[derive(Debug, PartialEq, Clone, Eq)] 9 | pub enum WRelop { Eq, Lt, Gt } 10 | 11 | #[derive(Debug, PartialEq, Clone, Eq)] 12 | pub enum WInstr { 13 | // Core instructions 14 | Const(i32), 15 | Binop(WBinop), 16 | Relop(WRelop), 17 | GetLocal(i32), 18 | SetLocal(i32), 19 | Load, 20 | Store, 21 | Size, 22 | Grow, 23 | Unreachable, 24 | Block(Vec), 25 | Loop(Vec), 26 | Br(i32), 27 | BrIf(i32), 28 | Return, 29 | Call(i32), 30 | 31 | // Administrative instructions 32 | Label{continuation: Box>, stack: WStack, instrs: Vec}, 33 | Frame(WConfig), 34 | Returning(i32), 35 | Trapping(String), 36 | } 37 | 38 | #[derive(Debug, Clone)] 39 | pub struct WFunc { 40 | pub params: i32, 41 | pub locals: i32, 42 | pub body: Vec 43 | } 44 | 45 | #[derive(Debug)] 46 | pub struct WModule { 47 | pub funcs: Vec, 48 | pub memory: Box 49 | } 50 | 51 | // Runtime constructs 52 | pub type WStack = Vec; 53 | 54 | #[derive(Debug, Clone, PartialEq, Eq)] 55 | pub struct WConfig { 56 | pub locals: Vec, 57 | pub stack: WStack, 58 | pub instrs: Vec 59 | } 60 | -------------------------------------------------------------------------------- /assign5/src/interpret.rs: -------------------------------------------------------------------------------- 1 | extern crate memory; 2 | 3 | use ast::*; 4 | 5 | #[allow(unused_macros)] 6 | macro_rules! fmt_state { 7 | ($x:ident) => ( 8 | format!("{}: {:?}", stringify!($x), $x) 9 | ); 10 | ($x:ident, $($y:ident),*) => ( 11 | format!("{} | {}", fmt_state!($x), fmt_state!($($y),*)) 12 | ); 13 | ($x:expr) => {{ 14 | let s: String = format!("{:?}", $x).chars().collect(); 15 | let v = &s[8..s.len()-2]; 16 | let mut r = format!("memory: ["); 17 | let mut i = 0; 18 | for _c in v.chars() { 19 | if _c == ',' || _c == ' ' { 20 | continue; 21 | } else if _c != '0' { 22 | r = format!("{} {}@{} ", r, _c, i); 23 | } 24 | i += 1; 25 | } 26 | format!("{}]", r) 27 | }} 28 | } 29 | 30 | // Print elements of config state, i.e. stack, locals, instrs 31 | // Usage ex.: 32 | // print_config!(stack); 33 | // print_config!(instrs, stack); 34 | // etc 35 | #[allow(unused_macros)] 36 | macro_rules! print_config { 37 | ($x:ident) => ( 38 | println!("{:?}", fmt_state!($x)); 39 | ); 40 | ($x:ident, $($y:ident),*) => ( 41 | println!("{:?}", fmt_state!($x, $($y),*)); 42 | ); 43 | } 44 | 45 | // Print memory layout. Format is value@index. 46 | // Usage: print_memory!(module.memory); 47 | #[allow(unused_macros)] 48 | macro_rules! print_memory { 49 | ($x:expr) => ( 50 | println!("{:?}", fmt_state!($x)); 51 | ) 52 | } 53 | 54 | fn step(module: &mut WModule, config: WConfig) -> WConfig { 55 | use self::WInstr::*; 56 | 57 | let WConfig {mut locals, mut stack, mut instrs} = config; 58 | let instr = instrs.remove(0); 59 | 60 | let new_instr = match instr { 61 | 62 | Unreachable => Some(Trapping("Unreachable".to_string())), 63 | 64 | Const(n) => { stack.push(n); None }, 65 | 66 | // YOUR CODE GOES HERE 67 | 68 | Binop(binop) => { unimplemented!(); } 69 | 70 | Relop(relop) => { unimplemented!(); } 71 | 72 | GetLocal(i) => { unimplemented!(); } 73 | 74 | SetLocal(i) => { unimplemented!(); } 75 | 76 | BrIf(label) => { unimplemented!(); } 77 | 78 | Return => { unimplemented!(); } 79 | 80 | Loop(instrs) => { unimplemented!(); } 81 | 82 | Block(instrs) => { unimplemented!(); } 83 | 84 | Label{continuation, stack: mut new_stack, instrs: new_instrs} => { unimplemented!(); } 85 | 86 | Call(i) => { unimplemented!(); } 87 | 88 | Frame(mut new_config) => { unimplemented!(); } 89 | 90 | Load => { unimplemented!(); } 91 | 92 | Store => { unimplemented!(); } 93 | 94 | Size => { unimplemented!(); } 95 | 96 | Grow => { unimplemented!(); } 97 | 98 | Returning(n) => { unimplemented!(); } 99 | 100 | Br(n) => { unimplemented!(); } 101 | 102 | Trapping(n) => unreachable!(), 103 | 104 | // END YOUR CODE 105 | 106 | }; 107 | 108 | if let Some(ins) = new_instr { 109 | instrs.insert(0, ins); 110 | } 111 | 112 | WConfig {locals, stack, instrs} 113 | } 114 | 115 | pub fn interpret(mut module: WModule) -> Result { 116 | let mut config = WConfig { 117 | locals: vec![], 118 | stack: vec![], 119 | instrs: vec![WInstr::Call(0)] 120 | }; 121 | 122 | while config.instrs.len() > 0 { 123 | if let WInstr::Trapping(ref err) = &config.instrs[0] { 124 | return Err(err.clone()) 125 | } 126 | config = step(&mut module, config); 127 | } 128 | 129 | Ok(config.stack.pop().unwrap()) 130 | } 131 | -------------------------------------------------------------------------------- /assign5/src/main.rs: -------------------------------------------------------------------------------- 1 | extern crate clap; 2 | #[macro_use] extern crate nom; 3 | 4 | extern crate memory; 5 | 6 | mod sexp; 7 | mod ast; 8 | mod parse; 9 | mod interpret; 10 | 11 | use clap::{App, Arg}; 12 | use std::fs; 13 | 14 | fn run(input: &str) -> Result { 15 | let ast = parse::parse(input)?; 16 | interpret::interpret(ast).map_err(|e| format!("{:?}", e)) 17 | } 18 | 19 | fn main() { 20 | let matches = App::new("assign5") 21 | .arg(Arg::with_name("input").index(1).required(true)) 22 | .get_matches(); 23 | 24 | let file = matches.value_of("input").unwrap(); 25 | let input = fs::read_to_string(file).expect("Couldn't read file"); 26 | let result = run(&input); 27 | match result { 28 | Ok(n) => { println!("Success: {}", n); }, 29 | Err(s) => { println!("Error: {}", s); } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /assign5/src/memory.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Debug; 2 | use std::{mem, ptr, alloc::{alloc, realloc, Layout}}; 3 | 4 | pub trait WMemory: Debug { 5 | fn load(&self, address: i32) -> Option; 6 | fn store(&mut self, address: i32, value: i32) -> bool; 7 | fn grow(&mut self); 8 | fn size(&self) -> i32; 9 | } 10 | 11 | #[derive(Debug)] 12 | pub struct VecMem(Vec); 13 | 14 | const PAGE_SIZE: i32 = 4096; 15 | 16 | fn alloc_page(npages: i32) -> Vec { 17 | (0..npages*PAGE_SIZE).map(|_| 0).collect::>() 18 | } 19 | 20 | 21 | impl VecMem { 22 | pub fn new(npages: i32) -> VecMem { 23 | VecMem(alloc_page(npages)) 24 | } 25 | } 26 | 27 | impl WMemory for VecMem { 28 | fn load(&self, address: i32) -> Option { 29 | // YOUR CODE GOES HERE 30 | unimplemented!() 31 | } 32 | 33 | fn store(&mut self, address: i32, value: i32) -> bool { 34 | // YOUR CODE GOES HERE 35 | unimplemented!() 36 | } 37 | 38 | fn grow(&mut self) { 39 | // YOUR CODE GOES HERE 40 | unimplemented!() 41 | } 42 | 43 | fn size(&self) -> i32 { 44 | // YOUR CODE GOES HERE 45 | unimplemented!() 46 | } 47 | } 48 | 49 | 50 | #[derive(Debug)] 51 | pub struct UnsafeMem { 52 | data: *mut i32, 53 | size: i32, 54 | } 55 | 56 | impl UnsafeMem { 57 | // npages must be > 0 58 | pub fn new(npages: i32) -> UnsafeMem { 59 | let size = (npages * PAGE_SIZE) as usize; 60 | let data = unsafe { 61 | let typesize = mem::size_of::(); 62 | let mut data = alloc(Layout::from_size_align(size * typesize, typesize).unwrap()); 63 | ptr::write_bytes(data, 0, size * typesize); 64 | data 65 | } as *mut i32; 66 | 67 | UnsafeMem { data, size: size as i32 } 68 | } 69 | } 70 | 71 | impl WMemory for UnsafeMem { 72 | fn load(&self, address: i32) -> Option { 73 | // YOUR CODE GOES HERE 74 | unimplemented!() 75 | } 76 | 77 | fn store(&mut self, address: i32, value: i32) -> bool { 78 | // YOUR CODE GOES HERE 79 | unimplemented!() 80 | } 81 | 82 | fn grow(&mut self) { 83 | // YOUR CODE GOES HERE 84 | unimplemented!() 85 | } 86 | 87 | fn size(&self) -> i32 { 88 | // YOUR CODE GOES HERE 89 | unimplemented!() 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /assign5/src/parse.rs: -------------------------------------------------------------------------------- 1 | extern crate memory; 2 | 3 | use ast::*; 4 | use nom::{is_alphanumeric, is_space}; 5 | use sexp::{Sexp, FromSexp}; 6 | use memory::VecMem; 7 | 8 | impl FromSexp for WInstr { 9 | fn from_sexp(sexp: &Sexp) -> Result { 10 | let tag = sexp.get_tag().ok_or("Expr has no tag")?; 11 | 12 | let parse_first = || -> Result { 13 | let mut args = sexp.iter().unwrap(); 14 | args.nth(1).ok_or("Missing arg")? 15 | .atom().ok_or("Arg not an atom")? 16 | .parse::().map_err(|e| e.to_string()) 17 | }; 18 | 19 | let parse_block = |sexp: &Sexp| -> Result, String> { 20 | let mut instrs = Vec::new(); 21 | for s in sexp.iter().unwrap().skip(1) { 22 | instrs.push(WInstr::from_sexp(s)?); 23 | } 24 | Ok(instrs) 25 | }; 26 | 27 | Ok(match tag.as_str() { 28 | 29 | "i32.const" => WInstr::Const(parse_first()?), 30 | 31 | "i32.add" => WInstr::Binop(WBinop::Add), 32 | "i32.sub" => WInstr::Binop(WBinop::Sub), 33 | "i32.mul" => WInstr::Binop(WBinop::Mul), 34 | "i32.div_s" => WInstr::Binop(WBinop::DivS), 35 | 36 | "i32.eq" => WInstr::Relop(WRelop::Eq), 37 | "i32.lt_s" => WInstr::Relop(WRelop::Lt), 38 | "i32.gt_s" => WInstr::Relop(WRelop::Gt), 39 | 40 | "get_local" => WInstr::GetLocal(parse_first()?), 41 | "set_local" => WInstr::SetLocal(parse_first()?), 42 | 43 | "i32.load" => WInstr::Load, 44 | "i32.store" => WInstr::Store, 45 | "memory.size" => WInstr::Size, 46 | "memory.grow" => WInstr::Grow, 47 | 48 | "unreachable" => WInstr::Unreachable, 49 | 50 | "block" => WInstr::Block(parse_block(sexp)?), 51 | "loop" => WInstr::Loop(parse_block(sexp)?), 52 | 53 | "br" => WInstr::Br(parse_first()?), 54 | "br_if" => WInstr::BrIf(parse_first()?), 55 | 56 | "return" => WInstr::Return, 57 | 58 | "call" => WInstr::Call(parse_first()?), 59 | 60 | t => { return Err(format!("Invalid expression tag {}", t)); } 61 | }) 62 | } 63 | } 64 | 65 | impl FromSexp for WFunc { 66 | fn from_sexp(sexp: &Sexp) -> Result { 67 | if !sexp.has_tag("func") { 68 | return Err("Missing func tag".to_string()) 69 | }; 70 | 71 | let mut params = 0; 72 | let mut locals = 0; 73 | let mut _result = false; 74 | let mut body = Vec::new(); 75 | for s in sexp.iter().unwrap().skip(1) { 76 | if s.has_tag("param") { 77 | params += 1; 78 | } else if s.has_tag("local") { 79 | locals += 1; 80 | } else if s.has_tag("result") { 81 | _result = true; 82 | } else { 83 | body.push(WInstr::from_sexp(s)?); 84 | } 85 | } 86 | 87 | Ok(WFunc { params, locals, body }) 88 | } 89 | } 90 | 91 | impl FromSexp for VecMem { 92 | fn from_sexp(sexp: &Sexp) -> Result { 93 | if !sexp.has_tag("memory") { 94 | return Err("Missing memory tag".to_string()); 95 | } 96 | 97 | let parse_first = || -> Result { 98 | let mut args = sexp.iter().unwrap(); 99 | args.nth(1).ok_or("Missing arg")? 100 | .atom().ok_or("Arg not an atom")? 101 | .parse::().map_err(|e| e.to_string()) 102 | }; 103 | 104 | let npages = parse_first(); 105 | match npages { 106 | Ok(n) => Ok(VecMem::new(n)), 107 | Err(e) => Err(e.to_string()), 108 | } 109 | } 110 | } 111 | 112 | impl FromSexp for WModule { 113 | fn from_sexp(sexp: &Sexp) -> Result { 114 | if !sexp.has_tag("module") { 115 | return Err("Missing module tag".to_string()) 116 | }; 117 | 118 | let mut funcs = Vec::new(); 119 | let mut memory = None; 120 | for s in sexp.iter().unwrap().skip(1) { 121 | if s.has_tag("func") { 122 | funcs.push(WFunc::from_sexp(s)?); 123 | } else if s.has_tag("memory") { 124 | memory = Some(VecMem::from_sexp(s)?); 125 | } else { 126 | return Err("Invalid sexp in module".to_string()); 127 | } 128 | } 129 | 130 | match memory { 131 | Some(m) => Ok(WModule { funcs, memory: Box::new(m) }), 132 | None => Ok(WModule { funcs, memory: Box::new(VecMem::new(0)) }) 133 | } 134 | 135 | } 136 | 137 | } 138 | 139 | fn is_atom_char(c: char) -> bool { 140 | is_alphanumeric(c as u8) || c == '.' || c == '$' || c == '_' 141 | } 142 | 143 | named!(atom<&str, Sexp>, 144 | map!(take_while1!(is_atom_char), |s| Sexp::Atom(s.to_string()))); 145 | 146 | named!(whitespace<&str, &str>, take_while!(|c| is_space(c as u8) || c == '\n')); 147 | 148 | named!( 149 | sexp<&str, Sexp>, 150 | alt!( 151 | map!( 152 | delimited!( 153 | char!('('), 154 | separated_list!(whitespace, sexp), 155 | char!(')')), 156 | |l: Vec| -> Sexp { Sexp::List(l) }) | 157 | atom)); 158 | 159 | pub fn parse(contents: &str) -> Result { 160 | let nocomments = contents.split("\n").filter(|x| !x.contains(";;")).collect::(); 161 | let (_, sp) = sexp(&nocomments).map_err(|err| err.to_string())?; 162 | WModule::from_sexp(&sp) 163 | } 164 | -------------------------------------------------------------------------------- /assign5/src/sexp.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, PartialEq, Eq, Clone)] 2 | pub enum Sexp { List(Vec), Atom(String) } 3 | 4 | impl Sexp { 5 | pub fn get_tag(&self) -> Option { 6 | if let Sexp::List(ref l) = self { 7 | if let Sexp::Atom(ref s) = &l[0] { 8 | Some(s.clone()) 9 | } else { 10 | None 11 | } 12 | } else { 13 | None 14 | } 15 | } 16 | 17 | pub fn has_tag>(&self, s: T) -> bool { 18 | if let Sexp::List(ref l) = self { 19 | l.len() > 0 && &l[0] == &Sexp::Atom(s.into()) 20 | } else { 21 | false 22 | } 23 | } 24 | 25 | pub fn atom(&self) -> Option { 26 | if let Sexp::Atom(ref s) = self { 27 | return Some(s.clone()) 28 | } else { 29 | None 30 | } 31 | } 32 | 33 | pub fn iter(&self) -> Option> { 34 | if let Sexp::List(ref l) = self { 35 | Some(l.iter()) 36 | } else { 37 | None 38 | } 39 | } 40 | } 41 | 42 | pub trait FromSexp: Sized { 43 | fn from_sexp(sexp: &Sexp) -> Result; 44 | } 45 | -------------------------------------------------------------------------------- /assign5/tests/binop.wat: -------------------------------------------------------------------------------- 1 | (module 2 | (func (result i32) 3 | (i32.const 3) 4 | (i32.const 2) 5 | (i32.add)) 6 | ) -------------------------------------------------------------------------------- /assign5/tests/block.wat: -------------------------------------------------------------------------------- 1 | (module 2 | (func (result i32) (local i32) 3 | (i32.const 0) 4 | (set_local 0) 5 | (block 6 | (get_local 0) 7 | (i32.const 1) 8 | (i32.add) 9 | (set_local 0) 10 | (br 0) 11 | (get_local 0) 12 | (i32.const 1) 13 | (i32.add) 14 | (set_local 0)) 15 | (get_local 0)) 16 | ) -------------------------------------------------------------------------------- /assign5/tests/func_call.wat: -------------------------------------------------------------------------------- 1 | (module 2 | (func (result i32) (local i32) 3 | (i32.const 3) 4 | (call 1)) 5 | 6 | (func (result i32) (param i32) 7 | (get_local 0) 8 | (i32.const 5) 9 | (i32.add)) 10 | ) -------------------------------------------------------------------------------- /assign5/tests/load_invalid.wat: -------------------------------------------------------------------------------- 1 | (module 2 | (memory 1) 3 | (func (result i32) 4 | (i32.const 5000) 5 | (i32.load)) 6 | ) -------------------------------------------------------------------------------- /assign5/tests/load_store.wat: -------------------------------------------------------------------------------- 1 | (module 2 | (memory 1) 3 | (func (result i32) 4 | (i32.const 4) 5 | (i32.const 8) 6 | (i32.store) 7 | (i32.const 4) 8 | (i32.load)) 9 | ) -------------------------------------------------------------------------------- /assign5/tests/local.wat: -------------------------------------------------------------------------------- 1 | (module 2 | (func (result i32) (local i32) 3 | (i32.const 8) 4 | (set_local 0) 5 | (i32.const 3) 6 | (get_local 0) 7 | (i32.mul)) 8 | ) -------------------------------------------------------------------------------- /assign5/tests/loop.wat: -------------------------------------------------------------------------------- 1 | (module 2 | (func (result i32) (local i32) 3 | (i32.const 0) 4 | (set_local 0) 5 | (loop 6 | (get_local 0) 7 | (i32.const 1) 8 | (i32.add) 9 | (set_local 0) 10 | 11 | (get_local 0) 12 | (i32.const 5) 13 | (i32.lt_s) 14 | (br_if 0)) 15 | (get_local 0))) 16 | -------------------------------------------------------------------------------- /assign5/tests/mem_grow.wat: -------------------------------------------------------------------------------- 1 | (module 2 | (memory 1) 3 | (func (result i32) 4 | (memory.grow) 5 | (memory.size)) 6 | ) -------------------------------------------------------------------------------- /assign5/tests/memory_test_safe.rs: -------------------------------------------------------------------------------- 1 | extern crate memory; 2 | 3 | use memory::{WMemory, VecMem}; 4 | 5 | const PAGE_SIZE: i32 = 4096; 6 | 7 | 8 | #[test] 9 | fn test_load_store() { 10 | let mut mem = VecMem::new(1); 11 | assert!(mem.store(0, 5)); 12 | assert!(mem.store(3909, 9)); 13 | assert!(!mem.store(5000, 1)); 14 | assert_eq!(mem.load(3909).unwrap(), 9); 15 | assert_eq!(mem.load(8).unwrap(), 0); 16 | assert_eq!(mem.load(5000), None); 17 | } 18 | 19 | #[test] 20 | fn test_grow_size() { 21 | let mut mem = VecMem::new(1); 22 | assert_eq!(mem.size(), PAGE_SIZE); 23 | mem.grow(); 24 | assert_eq!(mem.size(), 2 * PAGE_SIZE); 25 | } 26 | -------------------------------------------------------------------------------- /assign5/tests/memory_test_unsafe.rs: -------------------------------------------------------------------------------- 1 | extern crate memory; 2 | 3 | use memory::{WMemory, UnsafeMem}; 4 | 5 | const PAGE_SIZE: i32 = 4096; 6 | 7 | 8 | #[test] 9 | fn test_load_store() { 10 | let mut mem = UnsafeMem::new(1); 11 | assert!(mem.store(0, 5)); 12 | assert!(mem.store(3909, 9)); 13 | assert!(!mem.store(5000, 1)); 14 | assert_eq!(mem.load(3909).unwrap(), 9); 15 | assert_eq!(mem.load(8).unwrap(), 0); 16 | assert_eq!(mem.load(5000), None); 17 | } 18 | 19 | #[test] 20 | fn test_grow_size() { 21 | let mut mem = UnsafeMem::new(1); 22 | assert_eq!(mem.size(), PAGE_SIZE); 23 | mem.grow(); 24 | assert_eq!(mem.size(), 2 * PAGE_SIZE); 25 | } 26 | -------------------------------------------------------------------------------- /assign5/tests/relop.wat: -------------------------------------------------------------------------------- 1 | (module 2 | (func (result i32) 3 | (i32.const 3) 4 | (i32.const 2) 5 | (i32.lt_s)) 6 | ) -------------------------------------------------------------------------------- /assign5/tests/return.wat: -------------------------------------------------------------------------------- 1 | (module 2 | (func (result i32) 3 | (i32.const 2) 4 | (return)) 5 | ) -------------------------------------------------------------------------------- /assign5/tests/unreachable.wat: -------------------------------------------------------------------------------- 1 | (module 2 | (func (result i32) 3 | (loop 4 | (i32.const 1) 5 | (i32.const 3) 6 | (i32.add) 7 | (unreachable))) 8 | ) -------------------------------------------------------------------------------- /assign6/.rustfmt.toml: -------------------------------------------------------------------------------- 1 | tab_spaces = 2 -------------------------------------------------------------------------------- /assign6/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "assign6" 3 | version = "0.1.0" 4 | authors = ["Will Crichton "] 5 | 6 | [dependencies] 7 | take_mut = "0.2.2" 8 | tempfile = "3" 9 | 10 | [lib] 11 | name = "lib" 12 | path = "src/lib.rs" -------------------------------------------------------------------------------- /assign6/make_submission.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cd src 3 | zip -r -0 assign6.zip * 4 | mv assign6.zip .. 5 | -------------------------------------------------------------------------------- /assign6/src/asyncio.rs: -------------------------------------------------------------------------------- 1 | use future::*; 2 | use std::path::PathBuf; 3 | use std::thread; 4 | use std::sync::atomic::{AtomicBool, Ordering}; 5 | use std::sync::Arc; 6 | use std::fs; 7 | use std::io; 8 | 9 | pub struct FileReader { 10 | path: PathBuf, 11 | thread: Option>>, 12 | done_flag: Arc, 13 | } 14 | 15 | impl FileReader { 16 | pub fn new(path: PathBuf) -> FileReader { 17 | unimplemented!() 18 | } 19 | } 20 | 21 | impl Future for FileReader { 22 | type Item = io::Result; 23 | 24 | fn poll(&mut self) -> Poll { 25 | unimplemented!() 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /assign6/src/executor.rs: -------------------------------------------------------------------------------- 1 | use std::mem; 2 | use std::sync::{mpsc, Mutex, Arc}; 3 | use std::thread; 4 | use future::{Future, Poll}; 5 | use future_util::*; 6 | 7 | /* 8 | * Core executor interface. 9 | */ 10 | 11 | pub trait Executor { 12 | fn spawn(&mut self, f: F) 13 | where 14 | F: Future + 'static; 15 | fn wait(&mut self); 16 | } 17 | 18 | 19 | /* 20 | * Example implementation of a naive executor that executes futures 21 | * in sequence. 22 | */ 23 | 24 | pub struct BlockingExecutor; 25 | 26 | impl BlockingExecutor { 27 | pub fn new() -> BlockingExecutor { 28 | BlockingExecutor 29 | } 30 | } 31 | 32 | impl Executor for BlockingExecutor { 33 | fn spawn(&mut self, mut f: F) 34 | where 35 | F: Future, 36 | { 37 | loop { 38 | if let Poll::Ready(()) = f.poll() { 39 | break; 40 | } 41 | } 42 | } 43 | 44 | fn wait(&mut self) {} 45 | } 46 | 47 | /* 48 | * Part 2a - Single threaded executor 49 | */ 50 | 51 | pub struct SingleThreadExecutor { 52 | futures: Vec>>, 53 | } 54 | 55 | impl SingleThreadExecutor { 56 | pub fn new() -> SingleThreadExecutor { 57 | SingleThreadExecutor { futures: vec![] } 58 | } 59 | } 60 | 61 | impl Executor for SingleThreadExecutor { 62 | fn spawn(&mut self, mut f: F) 63 | where 64 | F: Future + 'static, 65 | { 66 | unimplemented!() 67 | } 68 | 69 | fn wait(&mut self) { 70 | unimplemented!() 71 | } 72 | } 73 | 74 | pub struct MultiThreadExecutor { 75 | sender: mpsc::Sender>>>, 76 | threads: Vec>, 77 | } 78 | 79 | impl MultiThreadExecutor { 80 | pub fn new(num_threads: i32) -> MultiThreadExecutor { 81 | unimplemented!() 82 | } 83 | } 84 | 85 | impl Executor for MultiThreadExecutor { 86 | fn spawn(&mut self, f: F) 87 | where 88 | F: Future + 'static, 89 | { 90 | unimplemented!() 91 | } 92 | 93 | fn wait(&mut self) { 94 | unimplemented!() 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /assign6/src/future.rs: -------------------------------------------------------------------------------- 1 | use take_mut; 2 | 3 | /* 4 | * Core futures interface. 5 | */ 6 | 7 | #[derive(Debug)] 8 | pub enum Poll { 9 | Ready(T), 10 | NotReady, 11 | } 12 | 13 | pub trait Future: Send { 14 | type Item: Send; 15 | fn poll(&mut self) -> Poll; 16 | } 17 | 18 | /* 19 | * Example implementation of a future for an item that returns immediately. 20 | */ 21 | 22 | // Container for the state of the future. 23 | pub struct Immediate { 24 | t: Option, 25 | } 26 | 27 | // Constructor to build the future. Note that the return type just says 28 | // "this produces a future", not specifying concretely the type Immediate. 29 | pub fn immediate(t: T) -> impl Future 30 | where 31 | T: Send, 32 | { 33 | Immediate { t: Some(t) } 34 | } 35 | 36 | // To treat Immediate as a future, we have to implement poll. Here it's 37 | // relatively simple, since we return immediately with a Poll::Ready. 38 | impl Future for Immediate 39 | where 40 | T: Send, 41 | { 42 | type Item = T; 43 | 44 | fn poll(&mut self) -> Poll { 45 | Poll::Ready(self.t.take().unwrap()) 46 | } 47 | } 48 | 49 | /* 50 | * Example implementation of a future combinator that applies a function to 51 | * the output of a future. 52 | */ 53 | 54 | struct Map { 55 | fut: Fut, 56 | fun: Option, 57 | } 58 | 59 | pub fn map(fut: Fut, fun: Fun) -> impl Future 60 | where 61 | T: Send, 62 | Fut: Future, 63 | Fun: FnOnce(Fut::Item) -> T + Send, 64 | { 65 | Map { 66 | fut, 67 | fun: Some(fun), 68 | } 69 | } 70 | 71 | impl Future for Map 72 | where 73 | T: Send, 74 | Fut: Future, 75 | Fun: FnOnce(Fut::Item) -> T + Send, 76 | { 77 | type Item = T; 78 | 79 | fn poll(&mut self) -> Poll { 80 | match self.fut.poll() { 81 | Poll::NotReady => Poll::NotReady, 82 | Poll::Ready(s) => { 83 | let mut f = self.fun.take(); 84 | Poll::Ready(f.unwrap()(s)) 85 | } 86 | } 87 | } 88 | } 89 | 90 | 91 | /* 92 | * Part 1a - Join 93 | */ 94 | 95 | // A join of two futures is a state machine depending on which future is 96 | // completed, represented as an enum. 97 | pub enum Join 98 | where 99 | F: Future, 100 | G: Future, 101 | { 102 | BothRunning(F, G), 103 | FirstDone(F::Item, G), 104 | SecondDone(F, G::Item), 105 | Done, 106 | } 107 | 108 | // When a join is created, we start by assuming neither child future 109 | // has completed. 110 | pub fn join(f: F, g: G) -> impl Future 111 | where 112 | F: Future, 113 | G: Future, 114 | { 115 | Join::BothRunning(f, g) 116 | } 117 | 118 | impl Future for Join 119 | where 120 | F: Future, 121 | G: Future, 122 | { 123 | type Item = (F::Item, G::Item); 124 | 125 | fn poll(&mut self) -> Poll { 126 | unimplemented!() 127 | } 128 | } 129 | 130 | /* 131 | * Part 1b - AndThen 132 | */ 133 | 134 | // The AndThen state machine depends on which future is currently running. 135 | pub enum AndThen { 136 | First(Fut1, Fun), 137 | Second(Fut2), 138 | Done, 139 | } 140 | 141 | pub fn and_then(fut: Fut1, fun: Fun) -> impl Future 142 | where 143 | Fut1: Future, 144 | Fut2: Future, 145 | Fun: FnOnce(Fut1::Item) -> Fut2 + Send, 146 | { 147 | AndThen::First(fut, fun) 148 | } 149 | 150 | impl Future for AndThen 151 | where 152 | Fut1: Future, 153 | Fut2: Future, 154 | Fun: FnOnce(Fut1::Item) -> Fut2 + Send, 155 | { 156 | type Item = Fut2::Item; 157 | 158 | fn poll(&mut self) -> Poll { 159 | unimplemented!() 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /assign6/src/future_util.rs: -------------------------------------------------------------------------------- 1 | use future::*; 2 | use std::sync::{Mutex, Arc}; 3 | 4 | impl Future for Box 5 | where 6 | F: Future + ?Sized, 7 | { 8 | type Item = F::Item; 9 | 10 | fn poll(&mut self) -> Poll { 11 | (**self).poll() 12 | } 13 | } 14 | 15 | impl Future for Arc> 16 | where 17 | F: Future, 18 | { 19 | type Item = F::Item; 20 | 21 | fn poll(&mut self) -> Poll { 22 | (**self).lock().unwrap().poll() 23 | } 24 | } 25 | 26 | pub struct Counter { 27 | pub fut: Fut, 28 | pub value: i32, 29 | } 30 | 31 | impl Future for Counter 32 | where 33 | Fut: Future, 34 | { 35 | type Item = Fut::Item; 36 | fn poll(&mut self) -> Poll { 37 | self.value += 1; 38 | return self.fut.poll(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /assign6/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate take_mut; 2 | extern crate tempfile; 3 | 4 | pub mod future; 5 | pub mod future_util; 6 | pub mod executor; 7 | pub mod asyncio; 8 | -------------------------------------------------------------------------------- /assign6/tests/asyncio_test.rs: -------------------------------------------------------------------------------- 1 | extern crate take_mut; 2 | extern crate lib; 3 | extern crate tempfile; 4 | use lib::asyncio::*; 5 | use lib::executor::*; 6 | use lib::future::*; 7 | use lib::future_util::*; 8 | use tempfile::NamedTempFile; 9 | use std::io::Write; 10 | use std::sync::{Mutex, Arc}; 11 | 12 | 13 | macro_rules! make_tmp { 14 | ($contents:expr) => {{ 15 | let mut tmp = NamedTempFile::new().unwrap(); 16 | { 17 | let f = tmp.as_file_mut(); 18 | write!(f, $contents).unwrap(); 19 | f.sync_all().unwrap(); 20 | } 21 | tmp 22 | }} 23 | } 24 | #[test] 25 | fn test_asyncio() { 26 | let tmp = make_tmp!("1.23"); 27 | let fut = FileReader::new(tmp.path().to_path_buf()); 28 | let mut exec = BlockingExecutor::new(); 29 | exec.spawn(map(fut, |s| { 30 | assert_eq!(s.unwrap(), "1.23"); 31 | () 32 | })); 33 | exec.wait(); 34 | } 35 | -------------------------------------------------------------------------------- /assign6/tests/executors_test.rs: -------------------------------------------------------------------------------- 1 | extern crate lib; 2 | use lib::executor::*; 3 | use lib::future::*; 4 | use lib::future_util::*; 5 | use std::sync::{Mutex, Arc}; 6 | 7 | fn test_executor(mut exec: T) { 8 | for _ in 0..100 { 9 | let f1 = immediate(5); 10 | let f2 = immediate(6); 11 | let f3 = join(f1, f2); 12 | exec.spawn(map(f3, |n| { 13 | assert_eq!(n, (5, 6)); 14 | () 15 | })); 16 | } 17 | exec.wait(); 18 | } 19 | 20 | #[test] 21 | fn blocking() { 22 | test_executor(BlockingExecutor::new()); 23 | } 24 | 25 | #[test] 26 | fn singlethread() { 27 | test_executor(SingleThreadExecutor::new()); 28 | } 29 | 30 | #[test] 31 | fn multithread() { 32 | test_executor(MultiThreadExecutor::new(4)); 33 | } -------------------------------------------------------------------------------- /assign6/tests/futures_test.rs: -------------------------------------------------------------------------------- 1 | extern crate take_mut; 2 | extern crate lib; 3 | use lib::future::*; 4 | 5 | #[test] 6 | fn test_join() { 7 | let f1 = immediate(5); 8 | let f2 = immediate(6); 9 | let mut f3 = join(f1, f2); 10 | loop { 11 | let res = f3.poll(); 12 | if let Poll::Ready(x) = res { 13 | assert_eq!(x, (5, 6)); 14 | break; 15 | } 16 | } 17 | } 18 | #[test] 19 | fn test_and_then() { 20 | let f1 = map(immediate(3), |n| n * 2); 21 | let f2 = |n| immediate(n + 4); 22 | let mut f3 = and_then(f1, f2); 23 | loop { 24 | let res = f3.poll(); 25 | if let Poll::Ready(x) = res { 26 | assert_eq!(x, 10); 27 | break; 28 | } 29 | } 30 | } 31 | #[test] 32 | fn test_both() { 33 | let f1 = map(immediate(3), |n| n * 2); 34 | let f2 = |n| immediate(n + 1); 35 | let f3 = immediate("Future"); 36 | let f4 = and_then(f1, f2); 37 | let mut f5 = join(f3, f4); 38 | loop { 39 | let res = f5.poll(); 40 | if let Poll::Ready(x) = res { 41 | assert_eq!(x, ("Future", 7)); 42 | break; 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /assign7/program/.rustfmt.toml: -------------------------------------------------------------------------------- 1 | tab_spaces = 2 -------------------------------------------------------------------------------- /assign7/program/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "assign7" 3 | version = "0.1.0" 4 | authors = ["Will Crichton "] 5 | 6 | [dependencies] 7 | rand = "0.6.0-pre.1" 8 | 9 | 10 | -------------------------------------------------------------------------------- /assign7/program/make_submission.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | zip -r -0 assign7.zip src/* Cargo.lock Cargo.toml 3 | 4 | -------------------------------------------------------------------------------- /assign7/program/src/atm.rs: -------------------------------------------------------------------------------- 1 | use session::*; 2 | 3 | type Id = String; 4 | type AtmDeposit = Recv>>; 5 | type AtmWithdraw = Recv, Close>>; 6 | type AtmServer = 7 | Recv, 13 | Close>>, 14 | Close>>; 15 | type AtmClient = ::Dual; 16 | 17 | fn approved(_id: &str) -> bool { true } 18 | 19 | pub fn atm_server(c: Chan<(), AtmServer>) { 20 | let (c, id) = c.recv(); 21 | if !approved(&id) { 22 | c.right().close(); 23 | return; 24 | } 25 | let mut balance = 100; // get balance for id 26 | 27 | let c = c.left(); 28 | let mut c = c.rec_push(); 29 | loop { 30 | c = match c.offer() { 31 | Branch::Left(c) => // Deposit or withdraw 32 | match c.offer() { 33 | Branch::Left(c) => { // Deposit 34 | let (c, amt) = c.recv(); 35 | balance += amt; 36 | c.send(balance).rec_pop() 37 | } 38 | Branch::Right(c) => { // Withdraw 39 | let (c, amt) = c.recv(); 40 | if balance >= amt { 41 | balance -= amt; 42 | c.left().rec_pop() 43 | } else { 44 | c.right().close(); 45 | return; 46 | } 47 | } 48 | }, 49 | Branch::Right(c) => { c.close(); return; } // Exit loop 50 | } 51 | } 52 | } 53 | 54 | pub fn atm_client(c: Chan<(), AtmClient>) { 55 | let id = String::from("wcrichto"); 56 | let c = c.send(id); 57 | match c.offer() { 58 | Branch::Left(c) => { 59 | let c = c.rec_push().left().right(); // withdraw 60 | let c = c.send(105); 61 | match c.offer() { 62 | Branch::Left(c) => { 63 | println!("Withdrawl succeeded."); 64 | c.rec_pop().right().close(); 65 | } 66 | Branch::Right(c) => { 67 | println!("Insufficient funds."); 68 | c.close() 69 | } 70 | } 71 | } 72 | Branch::Right(c) => { 73 | println!("Invalid authorization"); 74 | c.close(); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /assign7/program/src/counterex.rs: -------------------------------------------------------------------------------- 1 | use session_bug::*; 2 | 3 | fn sample_bug() { 4 | // this is only a bug **if** you comment out the Chan implementation 5 | // on line 63. you should get a compile error 6 | type Server = Close; 7 | let (c, _): (Chan, _) = Chan::new(); 8 | c.close(); 9 | } 10 | 11 | pub fn bug1() { 12 | unimplemented!() 13 | } 14 | 15 | pub fn bug2() { 16 | unimplemented!() 17 | } 18 | 19 | pub fn bug3() { 20 | unimplemented!() 21 | } 22 | 23 | #[cfg(test)] 24 | mod tests { 25 | #[test] 26 | fn bug1() { 27 | super::bug1(); 28 | } 29 | 30 | #[test] 31 | fn bug2() { 32 | super::bug2(); 33 | } 34 | 35 | #[test] 36 | fn bug3() { 37 | super::bug3(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /assign7/program/src/echo_example.rs: -------------------------------------------------------------------------------- 1 | use session::*; 2 | 3 | type Server = Rec, Close>>>; 4 | type Client = ::Dual; 5 | 6 | fn server(c: Chan<(), Server>) { 7 | let mut c = c.rec_push(); 8 | loop { 9 | c = { 10 | let (c, s) = c.recv(); 11 | println!("{}", s); 12 | match c.offer() { 13 | Branch::Left(c) => c.rec_pop(), 14 | Branch::Right(c) => { 15 | c.close(); 16 | return; 17 | } 18 | } 19 | } 20 | } 21 | } 22 | 23 | fn client(c: Chan<(), Client>) { 24 | let mut c = c.rec_push(); 25 | loop { 26 | c = { 27 | let c = c.send("echo!".to_string()); 28 | c.left().rec_pop() 29 | } 30 | } 31 | } 32 | 33 | -------------------------------------------------------------------------------- /assign7/program/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate rand; 2 | 3 | // UNCOMMENT this when doing section 1, and RE-COMMENT it when doing section 2 4 | //mod counterex; 5 | 6 | // UNCOMMENT this when doing section 2 7 | //pub mod tcp; 8 | 9 | pub mod session_bug; 10 | pub mod session; 11 | pub mod atm; 12 | -------------------------------------------------------------------------------- /assign7/program/src/session_bug.rs: -------------------------------------------------------------------------------- 1 | use std::marker::PhantomData; 2 | use std::sync::mpsc::{Sender, Receiver}; 3 | use std::marker; 4 | use std::mem::transmute; 5 | use std::sync::mpsc::channel; 6 | 7 | pub struct Send(PhantomData<(T, S)>); 8 | pub struct Recv(PhantomData<(T, S)>); 9 | pub struct Offer(PhantomData<(Left, Right)>); 10 | pub struct Choose(PhantomData<(Left, Right)>); 11 | pub struct Close; // equivalent to epsilon 12 | 13 | pub trait HasDual { 14 | type Dual; 15 | } 16 | 17 | impl HasDual for Close { 18 | type Dual = Close; 19 | } 20 | 21 | impl HasDual for Send where S: HasDual { 22 | type Dual = Recv; 23 | } 24 | 25 | impl HasDual for Recv where S: HasDual { 26 | type Dual = Recv; 27 | } 28 | 29 | impl HasDual for Choose 30 | where Left: HasDual, Right: HasDual { 31 | type Dual = Offer; 32 | } 33 | 34 | impl HasDual for Offer 35 | where Left: HasDual, Right: HasDual { 36 | type Dual = Choose; 37 | } 38 | 39 | pub struct Chan { 40 | sender: Sender>, 41 | receiver: Receiver>, 42 | _data: PhantomData, 43 | } 44 | 45 | impl Chan { 46 | unsafe fn write(&self, x: T) 47 | where 48 | T: marker::Send + 'static, 49 | { 50 | let sender: &Sender> = transmute(&self.sender); 51 | sender.send(Box::new(x)).unwrap(); 52 | } 53 | 54 | unsafe fn read(&self) -> T 55 | where 56 | T: marker::Send + 'static, 57 | { 58 | let receiver: &Receiver> = transmute(&self.receiver); 59 | *receiver.recv().unwrap() 60 | } 61 | } 62 | 63 | impl Chan { 64 | pub fn close(self) {} 65 | } 66 | 67 | impl Chan> 68 | where 69 | T: marker::Send + 'static, 70 | { 71 | pub fn send(self, x: T) -> Chan> { 72 | unsafe { 73 | self.write(x); 74 | transmute(self) 75 | } 76 | } 77 | } 78 | 79 | impl Chan> 80 | where 81 | T: marker::Send + 'static, 82 | { 83 | pub fn recv(self) -> (Chan, T) { 84 | unsafe { 85 | let a = self.read(); 86 | (transmute(self), a) 87 | } 88 | } 89 | } 90 | 91 | impl Chan> { 92 | pub fn left(self) -> Chan { 93 | unsafe { 94 | self.write(false); 95 | transmute(self) 96 | } 97 | } 98 | 99 | pub fn right(self) -> Chan { 100 | unsafe { 101 | self.write(true); 102 | transmute(self) 103 | } 104 | } 105 | } 106 | 107 | pub enum Branch { 108 | Left(L), 109 | Right(R), 110 | } 111 | 112 | impl Chan> { 113 | pub fn offer(self) -> Branch, Chan> { 114 | unsafe { 115 | if self.read() { 116 | Branch::Left(transmute(self)) 117 | } else { 118 | Branch::Right(transmute(self)) 119 | } 120 | } 121 | } 122 | } 123 | 124 | impl Chan where S: HasDual { 125 | pub fn new() -> (Chan, Chan) { 126 | let (sender1, receiver1) = channel(); 127 | let (sender2, receiver2) = channel(); 128 | let c1 = Chan { 129 | sender: sender1, 130 | receiver: receiver2, 131 | _data: PhantomData, 132 | }; 133 | let c2 = Chan { 134 | sender: sender2, 135 | receiver: receiver1, 136 | _data: PhantomData, 137 | }; 138 | (c1, c2) 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /assign7/program/src/tcp.rs: -------------------------------------------------------------------------------- 1 | extern crate rand; 2 | 3 | use session::*; 4 | use std::collections::{HashSet, HashMap}; 5 | 6 | pub struct Syn; 7 | pub struct SynAck; 8 | pub struct Ack; 9 | pub struct Fin; 10 | 11 | pub type TCPHandshake = (); 12 | 13 | pub type TCPRecv = (); 14 | 15 | pub type TCPClose = (); 16 | 17 | pub type TCPServer = TCPHandshake>; 18 | 19 | pub type TCPClient = ::Dual; 20 | 21 | pub fn tcp_server(c: Chan<(), TCPServer>) -> Vec { 22 | unimplemented!(); 23 | } 24 | 25 | pub fn tcp_client(c: Chan<(), TCPClient>, bufs: Vec) { 26 | unimplemented!(); 27 | } 28 | 29 | #[cfg(test)] 30 | mod test { 31 | use session::*; 32 | use session::NOISY; 33 | use std::sync::atomic::Ordering; 34 | use rand; 35 | use rand::Rng; 36 | use tcp::*; 37 | use std::marker::PhantomData; 38 | use std::sync::mpsc::channel; 39 | use std::thread; 40 | 41 | fn gen_bufs() -> Vec { 42 | let mut bufs: Vec = Vec::new(); 43 | let mut rng = rand::thread_rng(); 44 | for _ in 0usize..20 { 45 | let buf: Buffer = vec![0; rng.gen_range(1, 10)]; 46 | let buf: Buffer = buf.into_iter().map(|x: u8| rng.gen()).collect(); 47 | bufs.push(buf); 48 | } 49 | bufs 50 | } 51 | 52 | #[test] 53 | fn test_basic() { 54 | let bufs = gen_bufs(); 55 | let bufs_copy = bufs.clone(); 56 | let (s, c): ((Chan<(), TCPServer>), (Chan<(), TCPClient>)) = Chan::new(); 57 | let thread = thread::spawn(move || { tcp_client(c, bufs); }); 58 | 59 | let recvd = tcp_server(s); 60 | let res = thread.join(); 61 | 62 | assert_eq!(recvd, bufs_copy); 63 | } 64 | 65 | #[test] 66 | fn test_lossy() { 67 | let bufs = gen_bufs(); 68 | let bufs_copy = bufs.clone(); 69 | 70 | NOISY.with(|noisy| { 71 | noisy.store(true, Ordering::SeqCst); 72 | }); 73 | 74 | let (s, c): ((Chan<(), TCPServer>), (Chan<(), TCPClient>)) = Chan::new(); 75 | let thread = thread::spawn(move || { tcp_client(c, bufs); }); 76 | 77 | let recvd = tcp_server(s); 78 | let res = thread.join(); 79 | 80 | assert_eq!(recvd, bufs_copy); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /assign7/written/Makefile: -------------------------------------------------------------------------------- 1 | TEX := pdflatex 2 | FLAGS := -shell-escape 3 | 4 | all: assign7.pdf 5 | 6 | %.pdf: %.tex 7 | ${TEX} ${FLAGS} $^ 8 | 9 | check: 10 | aspell -t -c *.tex 11 | 12 | clean: 13 | rm -rf *.aux *.log *.out *.pdf _minted-* 14 | -------------------------------------------------------------------------------- /assign7/written/assign7.tex: -------------------------------------------------------------------------------- 1 | \documentclass[11pt]{article} 2 | 3 | \input{defs.tex} 4 | 5 | \begin{document} 6 | 7 | \hwtitle 8 | {Assignment 7} 9 | {Will Crichton (wcrichto)} %% REPLACE THIS WITH YOUR NAME/ID 10 | 11 | \problem{Bug 1} 12 | 13 | Your answer goes here. Here's an example of formatting code in LaTeX. 14 | 15 | \begin{verbatim} 16 | fn bug() { 17 | type Server = Close; 18 | let (c, _): (Chan, _) = Chan::new(); 19 | c.close(); 20 | } 21 | \end{verbatim} 22 | 23 | \problem{Bug 2} 24 | 25 | 26 | \problem{Bug 3} 27 | 28 | 29 | 30 | \end{document} 31 | -------------------------------------------------------------------------------- /assign8/.gitignore: -------------------------------------------------------------------------------- 1 | submission.zip 2 | point/lauxlib.rs 3 | point/native_point.so 4 | -------------------------------------------------------------------------------- /assign8/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | RUN apt update 3 | RUN apt-get install -y curl git python lua5.3 liblua5.3-dev luarocks 4 | RUN echo "termfx busted luacheck mobdebug debug.lua argparse" | xargs -n 1 luarocks install 5 | 6 | RUN curl https://sh.rustup.rs -sSf | \ 7 | sh -s -- --default-toolchain stable -y 8 | 9 | ENV PATH=/root/.cargo/bin:$PATH 10 | 11 | CMD ["/bin/bash"] -------------------------------------------------------------------------------- /assign8/Makefile: -------------------------------------------------------------------------------- 1 | LFLAGS=$(shell pkg-config --libs lua5.3) 2 | LUA=lua5.3 3 | 4 | .PHONY: default clean check 5 | 6 | default: point/native_point.so 7 | 8 | GAME_TARGETS := $(wildcard class/*.lua point/*.lua game/*.lua) 9 | GAME_TARGETS := roguelike.lua $(filter-out %_tests.lua, $(GAME_TARGETS)) 10 | roguelike.bin: $(GAME_TARGETS) 11 | squish 12 | @luac5.3 -o $@ solution.lua 13 | @rm solution.lua 14 | 15 | point/%.so: point/%.rs 16 | rustc -O $< --crate-type dylib -o $@ $(CFLAGS) $(LFLAGS) 17 | 18 | clean: 19 | rm -f *.so *.bin 20 | 21 | check: 22 | @luacheck . --no-self --exclude-files deps/* 23 | 24 | test: 25 | @$(LUA) class/class_tests.lua 26 | @$(LUA) class/type_tests.lua 27 | @$(LUA) game/game_tests.lua 28 | @$(LUA) point/point_tests.lua 29 | 30 | SUBMISSION_FILES := class/class.lua class/types.lua game/monster.lua point/native_point.rs 31 | submission: $(SUBMISSION_FILES) 32 | zip -r -0 submission.zip $^ 33 | -------------------------------------------------------------------------------- /assign8/class/class.lua: -------------------------------------------------------------------------------- 1 | local types = require "class.types" 2 | 3 | local Object 4 | Object = { 5 | new = function() 6 | local inst = {} 7 | inst.type = Object.type 8 | return inst 9 | end, 10 | 11 | constructor = function() end, 12 | 13 | is = function(class, val) 14 | -- TODO: fill in this function 15 | end, 16 | 17 | type = function(_) return Object end, 18 | 19 | datatypes = {}, 20 | 21 | bases = {} 22 | } 23 | 24 | local function class(bases, methods, datatypes) 25 | -- TODO: fill in this function 26 | end 27 | 28 | return { 29 | Object = Object, 30 | class = class, 31 | } 32 | -------------------------------------------------------------------------------- /assign8/class/class_tests.lua: -------------------------------------------------------------------------------- 1 | -- luacheck: std max+busted 2 | require 'busted.runner'() 3 | 4 | local class = require "class.class" 5 | local types = require "class.types" 6 | 7 | local BasicClass = class.class({class.Object}, function(Class) 8 | function Class:set(x) 9 | self.x = x 10 | end 11 | 12 | function Class:get() 13 | return self.x 14 | end 15 | end, {x = types.Number}) 16 | 17 | local ParentClass = class.class({class.Object}, function(Class) 18 | function Class:constructor(x) 19 | self.x = x + 1 20 | end 21 | 22 | function Class:incr() 23 | self.x = self.x + 1 24 | end 25 | end, {x = types.Number}) 26 | 27 | local ChildClass = class.class({ParentClass}, function(Class) 28 | function Class:constructor(x, y) 29 | ParentClass.constructor(self, x) 30 | self.y = y 31 | end 32 | 33 | function Class:add() 34 | return self.x + self.y 35 | end 36 | end, {y = types.Number}) 37 | 38 | local GrandchildClass = class.class({ChildClass}, function(_) end, {}) 39 | 40 | describe("Basic Class Tests", function() 41 | it("Object Tests", function() 42 | local p = BasicClass:new() 43 | p:set(1) 44 | assert.are.equals(1, p.x) 45 | assert.are.equals(1, p:get()) 46 | end) 47 | 48 | it("Constructor Tests", function() 49 | local p = ParentClass:new(1) 50 | assert.are.equals(2, p.x) 51 | p:incr() 52 | assert.are.equals(3, p.x) 53 | end) 54 | 55 | it("Inheritance Tests", function() 56 | local p1 = ChildClass:new(1, 2) 57 | assert.are.equals(2, p1.x) 58 | p1:incr() 59 | assert.are.equals(3, p1.x) 60 | assert.are.equals(2, p1.y) 61 | assert.are.equals(5, p1:add()) 62 | 63 | local p2 = GrandchildClass:new(1, 2) 64 | assert.are.equals(4, p2:add()) 65 | end) 66 | 67 | it("Type Tests", function() 68 | local p1 = ChildClass:new(1, 2) 69 | assert.is_true(class.Object:is(p1)) 70 | assert.is_true(ParentClass:is(p1)) 71 | assert.is_true(ChildClass:is(p1)) 72 | assert.is_false(GrandchildClass:is(p1)) 73 | 74 | local Class = class.class( 75 | {class.Object}, function(_) end, {x = types.Number, y = ChildClass}) 76 | local p2 = Class:new() 77 | assert.is_false(pcall(function() p2.x = "test" end)) 78 | assert.is_true(pcall(function() p2.x = 0 end)) 79 | assert.is_false(pcall(function() p2.y = "test" end)) 80 | assert.is_true(pcall(function() p2.y = ChildClass:new(1, 2) end)) 81 | assert.is_true(Class:is(p2)) 82 | assert.is_true(class.Object:is(p2)) 83 | end) 84 | end) 85 | -------------------------------------------------------------------------------- /assign8/class/type_tests.lua: -------------------------------------------------------------------------------- 1 | -- luacheck: std max+busted 2 | require 'busted.runner'() 3 | 4 | local types = require "class.types" 5 | 6 | describe("Basic Type Tests", function() 7 | describe('Primitive Tests', function() 8 | it('Any', function() 9 | assert.is_true(types.Any:is(nil)) 10 | assert.is_true(types.Any:is("a")) 11 | assert.is_true(types.Any:is(0)) 12 | end) 13 | 14 | it('String', function() 15 | assert.is_true(types.String:is("a")) 16 | assert.is_false(types.String:is(0)) 17 | end) 18 | 19 | it('Number', function() 20 | assert.is_true(types.Number:is(0)) 21 | assert.is_false(types.Number:is("a")) 22 | end) 23 | 24 | it('Function', function() 25 | assert.is_true(types.Function:is(function() end)) 26 | assert.is_false(types.Function:is(0)) 27 | end) 28 | 29 | it('Boolean', function() 30 | assert.is_true(types.Boolean:is(true)) 31 | assert.is_false(types.Boolean:is(0)) 32 | end) 33 | 34 | it('Nil', function() 35 | assert.is_true(types.Nil:is(nil)) 36 | assert.is_false(types.Nil:is(0)) 37 | end) 38 | end) 39 | 40 | it('List Tests', function() 41 | local numlist = types.List(types.Number) 42 | assert.is_true(numlist:is({1, 2, 3})) 43 | assert.is_false(numlist:is(1)) 44 | assert.is_false(numlist:is({"a", "b"})) 45 | assert.is_false(numlist:is({0, "a"})) 46 | 47 | local nestlist = types.List(types.List(types.String)) 48 | assert.is_true(nestlist:is({{"a"}, {"b"}})) 49 | assert.is_false(nestlist:is({{"a"}, {0}})) 50 | end) 51 | 52 | it('Table Tests', function() 53 | local tab = types.Table(types.String, types.Number) 54 | assert.is_true(tab:is({a = 0, b = 1})) 55 | assert.is_false(tab:is({a = 0, b = "b"})) 56 | end) 57 | end) 58 | -------------------------------------------------------------------------------- /assign8/class/types.lua: -------------------------------------------------------------------------------- 1 | local Any = {} 2 | function Any:is() return true end 3 | 4 | local String = nil 5 | local Number = nil 6 | local Function = nil 7 | local Boolean = nil 8 | local Nil = nil 9 | local List = nil 10 | local Table = nil 11 | 12 | return { 13 | Any = Any, 14 | String = String, 15 | Number = Number, 16 | Function = Function, 17 | Boolean = Boolean, 18 | Nil = Nil, 19 | List = List, 20 | Table = Table, 21 | } 22 | -------------------------------------------------------------------------------- /assign8/deps/README.md: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | 3 | This folder contains third-party dependencies. You shouldn't need to look at the code in here. 4 | -------------------------------------------------------------------------------- /assign8/deps/randomlua.lua: -------------------------------------------------------------------------------- 1 | --[[------------------------------------ 2 | RandomLua v0.3.1 3 | Pure Lua Pseudo-Random Numbers Generator 4 | Under the MIT license. 5 | copyright(c) 2017 linux-man 6 | --]]------------------------------------ 7 | 8 | local math_floor = math.floor 9 | 10 | local function normalize(n) --keep numbers at (positive) 32 bits 11 | return n % 0x80000000 12 | end 13 | 14 | local function bit_and(a, b) 15 | local r = 0 16 | local m = 0 17 | for m = 0, 31 do 18 | if (a % 2 == 1) and (b % 2 == 1) then r = r + 2^m end 19 | if a % 2 ~= 0 then a = a - 1 end 20 | if b % 2 ~= 0 then b = b - 1 end 21 | a = a / 2 b = b / 2 22 | end 23 | return normalize(r) 24 | end 25 | 26 | local function bit_or(a, b) 27 | local r = 0 28 | local m = 0 29 | for m = 0, 31 do 30 | if (a % 2 == 1) or (b % 2 == 1) then r = r + 2^m end 31 | if a % 2 ~= 0 then a = a - 1 end 32 | if b % 2 ~= 0 then b = b - 1 end 33 | a = a / 2 b = b / 2 34 | end 35 | return normalize(r) 36 | end 37 | 38 | local function bit_xor(a, b) 39 | local r = 0 40 | local m = 0 41 | for m = 0, 31 do 42 | if a % 2 ~= b % 2 then r = r + 2^m end 43 | if a % 2 ~= 0 then a = a - 1 end 44 | if b % 2 ~= 0 then b = b - 1 end 45 | a = a / 2 b = b / 2 46 | end 47 | return normalize(r) 48 | end 49 | 50 | local function seed() 51 | --return normalize(tonumber(tostring(os.time()):reverse())) 52 | return normalize(os.time()) 53 | end 54 | 55 | --Mersenne twister 56 | mersenne_twister = {} 57 | mersenne_twister.__index = mersenne_twister 58 | 59 | function mersenne_twister:randomseed(s) 60 | if not s then s = seed() end 61 | self.mt[0] = normalize(s) 62 | for i = 1, 623 do 63 | self.mt[i] = normalize(0x6c078965 * bit_xor(self.mt[i-1], math_floor(self.mt[i-1] / 0x40000000)) + i) 64 | end 65 | end 66 | 67 | function mersenne_twister:random(a, b) 68 | local y 69 | if self.index == 0 then 70 | for i = 0, 623 do 71 | --y = bit_or(math_floor(self.mt[i] / 0x80000000) * 0x80000000, self.mt[(i + 1) % 624] % 0x80000000) 72 | y = self.mt[(i + 1) % 624] % 0x80000000 73 | self.mt[i] = bit_xor(self.mt[(i + 397) % 624], math_floor(y / 2)) 74 | if y % 2 ~= 0 then self.mt[i] = bit_xor(self.mt[i], 0x9908b0df) end 75 | end 76 | end 77 | y = self.mt[self.index] 78 | y = bit_xor(y, math_floor(y / 0x800)) 79 | y = bit_xor(y, bit_and(normalize(y * 0x80), 0x9d2c5680)) 80 | y = bit_xor(y, bit_and(normalize(y * 0x8000), 0xefc60000)) 81 | y = bit_xor(y, math_floor(y / 0x40000)) 82 | self.index = (self.index + 1) % 624 83 | if not a then return y / 0xffffffff 84 | elseif not b then 85 | if a == 0 then return y 86 | else return 1 + (y % a) 87 | end 88 | else 89 | return a + (y % (b - a + 1)) 90 | end 91 | end 92 | 93 | function twister(s) 94 | local temp = {} 95 | setmetatable(temp, mersenne_twister) 96 | temp.mt = {} 97 | temp.index = 0 98 | temp:randomseed(s) 99 | return temp 100 | end 101 | 102 | --Linear Congruential Generator 103 | linear_congruential_generator = {} 104 | linear_congruential_generator.__index = linear_congruential_generator 105 | 106 | function linear_congruential_generator:random(a, b) 107 | local y = (self.a * self.x + self.c) % self.m 108 | self.x = y 109 | if not a then return y / 0xffff 110 | elseif not b then 111 | if a == 0 then return y 112 | else return 1 + (y % a) end 113 | else 114 | return a + (y % (b - a + 1)) 115 | end 116 | end 117 | 118 | function linear_congruential_generator:randomseed(s) 119 | if not s then s = seed() end 120 | self.x = normalize(s) 121 | end 122 | 123 | function lcg(s, r) 124 | local temp = {} 125 | setmetatable(temp, linear_congruential_generator) 126 | temp.a, temp.c, temp.m = 1103515245, 12345, 0x10000 --from Ansi C 127 | if r then 128 | if r == 'nr' then temp.a, temp.c, temp.m = 1664525, 1013904223, 0x10000 --from Numerical Recipes. 129 | elseif r == 'mvc' then temp.a, temp.c, temp.m = 214013, 2531011, 0x10000 end--from MVC 130 | end 131 | temp:randomseed(s) 132 | return temp 133 | end 134 | 135 | -- Multiply-with-carry 136 | multiply_with_carry = {} 137 | multiply_with_carry.__index = multiply_with_carry 138 | 139 | function multiply_with_carry:random(a, b) 140 | local m = self.m 141 | local t = self.a * self.x + self.c 142 | local y = t % m 143 | self.x = y 144 | self.c = math_floor(t / m) 145 | if not a then return y / 0xffff 146 | elseif not b then 147 | if a == 0 then return y 148 | else return 1 + (y % a) end 149 | else 150 | return a + (y % (b - a + 1)) 151 | end 152 | end 153 | 154 | function multiply_with_carry:randomseed(s) 155 | if not s then s = seed() end 156 | self.c = self.ic 157 | self.x = normalize(s) 158 | end 159 | 160 | function mwc(s, r) 161 | local temp = {} 162 | setmetatable(temp, multiply_with_carry) 163 | temp.a, temp.c, temp.m = 1103515245, 12345, 0x10000 --from Ansi C 164 | if r then 165 | if r == 'nr' then temp.a, temp.c, temp.m = 1664525, 1013904223, 0x10000 --from Numerical Recipes. 166 | elseif r == 'mvc' then temp.a, temp.c, temp.m = 214013, 2531011, 0x10000 end--from MVC 167 | end 168 | temp.ic = temp.c 169 | temp:randomseed(s) 170 | return temp 171 | end 172 | -------------------------------------------------------------------------------- /assign8/deps/rotLove/img/cp437.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-cs242/f18-assignments/0646cc427e126f105654405323c4074db3015f56/assign8/deps/rotLove/img/cp437.png -------------------------------------------------------------------------------- /assign8/deps/rotLove/rot.lua: -------------------------------------------------------------------------------- 1 | local ROTLOVE_PATH = (...) .. '.' 2 | local Class = require (ROTLOVE_PATH .. 'class') 3 | 4 | local ROT = Class:extend('ROT', { 5 | DEFAULT_WIDTH =80, 6 | DEFAULT_HEIGHT=24, 7 | 8 | DIRS= {FOUR={ 9 | { 0,-1}, 10 | { 1, 0}, 11 | { 0, 1}, 12 | {-1, 0} 13 | }, 14 | EIGHT={ 15 | { 0,-1}, 16 | { 1,-1}, 17 | { 1, 0}, 18 | { 1, 1}, 19 | { 0, 1}, 20 | {-1, 1}, 21 | {-1, 0}, 22 | {-1,-1} 23 | } 24 | } 25 | }) 26 | package.loaded[...] = ROT 27 | 28 | -- Concatenating assert function 29 | -- see http://lua.space/general/assert-usage-caveat 30 | function ROT.assert(pass, ...) 31 | if pass then 32 | return pass, ... 33 | elseif select('#', ...) > 0 then 34 | error(table.concat({...}), 2) 35 | else 36 | error('assertion failed!', 2) 37 | end 38 | end 39 | 40 | ROT.Class = Class 41 | 42 | ROT.RNG = require (ROTLOVE_PATH .. 'rng') 43 | 44 | -- bind a function to a class instance 45 | function Class:bind (func) 46 | return function (...) return func(self, ...) end 47 | end 48 | 49 | -- get/set RNG instance for a class 50 | -- used by maps, noise, dice, etc. 51 | Class._rng = ROT.RNG 52 | function Class:getRNG() 53 | return self._rng 54 | end 55 | function Class:setRNG(rng) 56 | self._rng = rng or ROT.RNG 57 | return self 58 | end 59 | 60 | require (ROTLOVE_PATH .. 'newFuncs') 61 | 62 | ROT.Type = {} -- collection types tuned for various use cases 63 | ROT.Type.PointSet = require (ROTLOVE_PATH .. 'type.pointSet') 64 | ROT.Type.Grid = require (ROTLOVE_PATH .. 'type.grid') 65 | 66 | ROT.Dice = require (ROTLOVE_PATH .. 'dice') 67 | ROT.Display = require (ROTLOVE_PATH .. 'display') 68 | ROT.TextDisplay = require (ROTLOVE_PATH .. 'textDisplay') 69 | ROT.StringGenerator = require (ROTLOVE_PATH .. 'stringGenerator') 70 | ROT.EventQueue = require (ROTLOVE_PATH .. 'eventQueue') 71 | ROT.Scheduler = require (ROTLOVE_PATH .. 'scheduler') 72 | ROT.Scheduler.Simple = require (ROTLOVE_PATH .. 'scheduler.simple') 73 | ROT.Scheduler.Speed = require (ROTLOVE_PATH .. 'scheduler.speed') 74 | ROT.Scheduler.Action = require (ROTLOVE_PATH .. 'scheduler.action') 75 | ROT.Engine = require (ROTLOVE_PATH .. 'engine') 76 | ROT.Map = require (ROTLOVE_PATH .. 'map') 77 | ROT.Map.Arena = require (ROTLOVE_PATH .. 'map.arena') 78 | ROT.Map.DividedMaze = require (ROTLOVE_PATH .. 'map.dividedMaze') 79 | ROT.Map.IceyMaze = require (ROTLOVE_PATH .. 'map.iceyMaze') 80 | ROT.Map.EllerMaze = require (ROTLOVE_PATH .. 'map.ellerMaze') 81 | ROT.Map.Cellular = require (ROTLOVE_PATH .. 'map.cellular') 82 | ROT.Map.Dungeon = require (ROTLOVE_PATH .. 'map.dungeon') 83 | ROT.Map.Feature = require (ROTLOVE_PATH .. 'map.feature') 84 | ROT.Map.Room = require (ROTLOVE_PATH .. 'map.room') 85 | ROT.Map.Corridor = require (ROTLOVE_PATH .. 'map.corridor') 86 | ROT.Map.Digger = require (ROTLOVE_PATH .. 'map.digger') 87 | ROT.Map.Uniform = require (ROTLOVE_PATH .. 'map.uniform') 88 | ROT.Map.Rogue = require (ROTLOVE_PATH .. 'map.rogue') 89 | ROT.Map.BrogueRoom = require (ROTLOVE_PATH .. 'map.brogueRoom') 90 | ROT.Map.Brogue = require (ROTLOVE_PATH .. 'map.brogue') 91 | ROT.Noise = require (ROTLOVE_PATH .. 'noise') 92 | ROT.Noise.Simplex = require (ROTLOVE_PATH .. 'noise.simplex') 93 | ROT.FOV = require (ROTLOVE_PATH .. 'fov') 94 | ROT.FOV.Precise = require (ROTLOVE_PATH .. 'fov.precise') 95 | ROT.FOV.Bresenham = require (ROTLOVE_PATH .. 'fov.bresenham') 96 | ROT.FOV.Recursive = require (ROTLOVE_PATH .. 'fov.recursive') 97 | ROT.Color = require (ROTLOVE_PATH .. 'color') 98 | ROT.Lighting = require (ROTLOVE_PATH .. 'lighting') 99 | ROT.Path = require (ROTLOVE_PATH .. 'path') 100 | ROT.Path.Dijkstra = require (ROTLOVE_PATH .. 'path.dijkstra') 101 | ROT.Path.DijkstraMap = require (ROTLOVE_PATH .. 'path.dijkstraMap') 102 | ROT.Path.AStar = require (ROTLOVE_PATH .. 'path.astar') 103 | ROT.Text = require (ROTLOVE_PATH .. 'text') 104 | 105 | return ROT 106 | 107 | -------------------------------------------------------------------------------- /assign8/deps/rotLove/rot/class.lua: -------------------------------------------------------------------------------- 1 | local BaseClass = {} 2 | 3 | function BaseClass:new(...) 4 | local t = setmetatable({}, self) 5 | t:init(...) 6 | return t 7 | end 8 | 9 | function BaseClass:extend(name, t) 10 | t = t or {} 11 | t.__index = t 12 | t.super = self 13 | return setmetatable(t, { __call = self.new, __index = self }) 14 | end 15 | 16 | function BaseClass:init() 17 | end 18 | 19 | return BaseClass 20 | 21 | -------------------------------------------------------------------------------- /assign8/deps/rotLove/rot/engine.lua: -------------------------------------------------------------------------------- 1 | local ROT = require((...):gsub(('.[^./\\]*'):rep(1) .. '$', '')) 2 | local Engine = ROT.Class:extend("Engine") 3 | 4 | function Engine:init(scheduler) 5 | self._scheduler=scheduler 6 | self._lock =1 7 | end 8 | 9 | function Engine:start() 10 | return self:unlock() 11 | end 12 | 13 | function Engine:lock() 14 | self._lock=self._lock+1 15 | end 16 | 17 | function Engine:unlock() 18 | assert(self._lock>0, 'Cannot unlock unlocked Engine') 19 | self._lock=self._lock-1 20 | while self._lock<1 do 21 | local actor=self._scheduler:next() 22 | if not actor then return self:lock() end 23 | actor:act() 24 | end 25 | return self 26 | end 27 | 28 | return Engine 29 | -------------------------------------------------------------------------------- /assign8/deps/rotLove/rot/eventQueue.lua: -------------------------------------------------------------------------------- 1 | --- Stores and retrieves events based on time. 2 | -- @module ROT.EventQueue 3 | local ROT = require((...):gsub(('.[^./\\]*'):rep(1) .. '$', '')) 4 | local EventQueue = ROT.Class:extend("EventQueue") 5 | 6 | function EventQueue:init() 7 | self._time = 0 8 | self._events = {} 9 | self._eventTimes = {} 10 | end 11 | 12 | --- Get Time. 13 | -- Get time counted since start 14 | -- @treturn int elapsed time 15 | function EventQueue:getTime() 16 | return self._time 17 | end 18 | 19 | --- Clear. 20 | -- Remove all events from queue 21 | -- @treturn ROT.EventQueue self 22 | function EventQueue:clear() 23 | self._events ={} 24 | self._eventTimes={} 25 | return self 26 | end 27 | 28 | --- Add. 29 | -- Add an event 30 | -- @tparam any event Any object 31 | -- @tparam int time The number of time units that will elapse before this event is returned 32 | function EventQueue:add(event, time) 33 | local index= 1 34 | if self._eventTimes then 35 | for i=1,#self._eventTimes do 36 | if self._eventTimes[i]>time then 37 | index=i 38 | break 39 | end 40 | index=i+1 41 | end 42 | end 43 | table.insert(self._events, index, event) 44 | table.insert(self._eventTimes, index, time) 45 | end 46 | 47 | --- Get. 48 | -- Get the next event from the queue and advance the appropriate amount time 49 | -- @treturn event|nil The event previously added by .add() or nil if none are queued 50 | function EventQueue:get() 51 | if #self._events<1 then return nil end 52 | local time = table.remove(self._eventTimes, 1) 53 | if time>0 then 54 | self._time=self._time+time 55 | for i=1,#self._eventTimes do 56 | self._eventTimes[i]=self._eventTimes[i]-time 57 | end 58 | end 59 | return table.remove(self._events, 1) 60 | end 61 | 62 | --- Get event time. 63 | -- Get the time associated with the given event 64 | -- @tparam any event 65 | -- @treturn number time 66 | function EventQueue:getEventTime(event) 67 | local index=table.indexOf(self._events, event) 68 | if index==0 then return nil end 69 | return self._eventTimes[index] 70 | end 71 | 72 | --- Remove. 73 | -- Find and remove an event from the queue 74 | -- @tparam any event The previously added event to be removed 75 | -- @treturn boolean true if an event was removed from the queue 76 | function EventQueue:remove(event) 77 | local index=table.indexOf(self._events, event) 78 | if index==0 then return false end 79 | self:_remove(index) 80 | return true 81 | end 82 | 83 | function EventQueue:_remove(index) 84 | table.remove(self._events, index) 85 | table.remove(self._eventTimes, index) 86 | end 87 | 88 | return EventQueue 89 | -------------------------------------------------------------------------------- /assign8/deps/rotLove/rot/fov.lua: -------------------------------------------------------------------------------- 1 | local ROT = require((...):gsub(('.[^./\\]*'):rep(1) .. '$', '')) 2 | local FOV = ROT.Class:extend("FOV") 3 | 4 | function FOV:init(lightPassesCallback, options) 5 | self._lightPasses=lightPassesCallback 6 | self._options={topology=8} 7 | if options then for k,_ in pairs(options) do self._options[k]=options[k] end end 8 | end 9 | 10 | function FOV:compute() end 11 | 12 | function FOV:_getCircle(cx, cy, r) 13 | local result={} 14 | local dirs, countFactor, startOffset 15 | local topo=self._options.topology 16 | if topo==4 then 17 | countFactor=1 18 | startOffset={0,1} 19 | dirs={ 20 | ROT.DIRS.EIGHT[8], 21 | ROT.DIRS.EIGHT[2], 22 | ROT.DIRS.EIGHT[4], 23 | ROT.DIRS.EIGHT[6] 24 | } 25 | elseif topo==8 then 26 | dirs=ROT.DIRS.FOUR 27 | countFactor=2 28 | startOffset={-1,1} 29 | end 30 | 31 | local x=cx+startOffset[1]*r 32 | local y=cy+startOffset[2]*r 33 | 34 | for i=1,#dirs do 35 | for _=1,r*countFactor do 36 | table.insert(result, {x, y}) 37 | x=x+dirs[i][1] 38 | y=y+dirs[i][2] 39 | end 40 | end 41 | return result 42 | end 43 | 44 | function FOV:_getRealCircle(cx, cy, r) 45 | local i=0 46 | local result={} 47 | while i<2*math.pi do 48 | i=i+0.05 49 | local x = cx + r * math.cos(i) 50 | local y = cy + r * math.sin(i) 51 | table.insert(result, {x,y}) 52 | end 53 | return result 54 | end 55 | 56 | return FOV 57 | -------------------------------------------------------------------------------- /assign8/deps/rotLove/rot/map.lua: -------------------------------------------------------------------------------- 1 | local ROT = require((...):gsub(('.[^./\\]*'):rep(1) .. '$', '')) 2 | local Map = ROT.Class:extend("Map") 3 | 4 | function Map:init(width, height) 5 | self._width = width or ROT.DEFAULT_WIDTH 6 | self._height = height or ROT.DEFAULT_HEIGHT 7 | end 8 | 9 | function Map:create() end 10 | 11 | function Map:_fillMap(value) 12 | local map = {} 13 | for x = 1, self._width do 14 | map[x] = {} 15 | for y = 1, self._height do 16 | map[x][y] = value 17 | end 18 | end 19 | return map 20 | end 21 | 22 | return Map 23 | 24 | -------------------------------------------------------------------------------- /assign8/deps/rotLove/rot/map/arena.lua: -------------------------------------------------------------------------------- 1 | --- The Arena map generator. 2 | -- Generates an arena style map. All cells except for the extreme borders are floors. The borders are walls. 3 | -- @module ROT.Map.Arena 4 | local ROT = require((...):gsub(('.[^./\\]*'):rep(2) .. '$', '')) 5 | local Arena = ROT.Map:extend("Arena") 6 | --- Constructor. 7 | -- Called with ROT.Map.Arena:new(width, height) 8 | -- @tparam int width Width in cells of the map 9 | -- @tparam int height Height in cells of the map 10 | function Arena:init(width, height) 11 | Arena.super.init(self, width, height) 12 | end 13 | 14 | --- Create. 15 | -- Creates a map. 16 | -- @tparam function callback This function will be called for every cell. It must accept the following parameters: 17 | -- @tparam int callback.x The x-position of a cell in the map 18 | -- @tparam int callback.y The y-position of a cell in the map 19 | -- @tparam int callback.value A value representing the cell-type. 0==floor, 1==wall 20 | -- @treturn ROT.Map.Arena self 21 | function Arena:create(callback) 22 | local w, h = self._width, self._height 23 | if not callback then return self end 24 | for y = 1, h do 25 | for x = 1, w do 26 | callback(x, y, x>1 and y>1 and x0 do 46 | local room=table.remove(self._stack, 1) 47 | self:_partitionRoom(room) 48 | end 49 | end 50 | 51 | function DividedMaze:_partitionRoom(room) 52 | local availX={} 53 | local availY={} 54 | 55 | for i=room[1]+1,room[3]-1 do 56 | local top =self._map[i][room[2]-1] 57 | local bottom=self._map[i][room[4]+1] 58 | if top>0 and bottom>0 and i%2==0 then table.insert(availX, i) end 59 | end 60 | 61 | for j=room[2]+1,room[4]-1 do 62 | local left =self._map[room[1]-1][j] 63 | local right=self._map[room[3]+1][j] 64 | if left>0 and right>0 and j%2==0 then table.insert(availY, j) end 65 | end 66 | 67 | if #availX==0 or #availY==0 then return end 68 | 69 | local x=table.random(availX) 70 | local y=table.random(availY) 71 | 72 | self._map[x][y]=1 73 | 74 | local walls={} 75 | 76 | table.insert(walls, {}) 77 | for i=room[1],x-1,1 do 78 | self._map[i][y]=1 79 | table.insert(walls[#walls], {i,y}) 80 | end 81 | 82 | table.insert(walls, {}) 83 | for i=x+1,room[3],1 do 84 | self._map[i][y]=1 85 | table.insert(walls[#walls],{i,y}) 86 | end 87 | 88 | table.insert(walls, {}) 89 | for j=room[2],y-1,1 do 90 | self._map[x][j]=1 91 | table.insert(walls[#walls],{x,j}) 92 | end 93 | 94 | table.insert(walls, {}) 95 | for j=y+1,room[4] do 96 | self._map[x][j]=1 97 | table.insert(walls[#walls],{x,j}) 98 | end 99 | 100 | local solid= table.random(walls) 101 | for i=1,#walls do 102 | local w=walls[i] 103 | if w~=solid then 104 | local hole=table.random(w) 105 | self._map[hole[1]][hole[2]]=0 106 | end 107 | end 108 | table.insert(self._stack, {room[1], room[2], x-1, y-1}) 109 | table.insert(self._stack, {x+1, room[2], room[3], y-1}) 110 | table.insert(self._stack, {room[1], y+1, x-1, room[4]}) 111 | table.insert(self._stack, {x+1, y+1, room[3], room[4]}) 112 | 113 | end 114 | 115 | return DividedMaze 116 | -------------------------------------------------------------------------------- /assign8/deps/rotLove/rot/map/dungeon.lua: -------------------------------------------------------------------------------- 1 | --- The Dungeon-style map Prototype. 2 | -- This class is extended by ROT.Map.Digger and ROT.Map.Uniform 3 | -- @module ROT.Map.Dungeon 4 | local ROT = require((...):gsub(('.[^./\\]*'):rep(2) .. '$', '')) 5 | local Dungeon = ROT.Map:extend("Dungeon") 6 | --- Constructor. 7 | -- Called with ROT.Map.Cellular:new() 8 | -- @tparam int width Width in cells of the map 9 | -- @tparam int height Height in cells of the map 10 | function Dungeon:init(width, height) 11 | Dungeon.super.init(self, width, height) 12 | self._rooms ={} 13 | self._corridors={} 14 | end 15 | 16 | --- Get rooms 17 | -- Get a table of rooms on the map 18 | -- @treturn table A table containing objects of the type ROT.Map.Room 19 | function Dungeon:getRooms() return self._rooms end 20 | 21 | --- Get doors 22 | -- Get a table of doors on the map 23 | -- @treturn table A table {{x=int, y=int},...} for doors. 24 | 25 | -- FIXME: This could be problematic; it accesses an internal member of another 26 | -- class (room._doors). Will break if underlying implementation changes. 27 | -- Should probably take a callback instead like Room:getDoors(). 28 | 29 | function Dungeon:getDoors() 30 | local result={} 31 | for _, room in ipairs(self._rooms) do 32 | for _, x, y in room._doors:each() do 33 | result[#result + 1] = { x = x, y = y } 34 | end 35 | end 36 | return result 37 | end 38 | 39 | --- Get corridors 40 | -- Get a table of corridors on the map 41 | -- @treturn table A table containing objects of the type ROT.Map.Corridor 42 | function Dungeon:getCorridors() return self._corridors end 43 | 44 | function Dungeon:_getDetail(name, x, y) 45 | local t = self[name] 46 | for i = 1, #t do 47 | if t[i].x == x and t[i].y == y then return t[i], i end 48 | end 49 | end 50 | 51 | function Dungeon:_setDetail(name, x, y, value) 52 | local detail, i = self:_getDetail(name, x, y) 53 | if detail then 54 | if value then 55 | detail.value = value 56 | else 57 | table.remove(self[name], i) 58 | end 59 | elseif value then 60 | local t = self[name] 61 | detail = { x = x, y = y, value = value } 62 | t[#t + 1] = detail 63 | end 64 | return detail 65 | end 66 | 67 | function Dungeon:getWall(x, y) 68 | return self:_getDetail('_walls', x, y) 69 | end 70 | 71 | function Dungeon:setWall(x, y, value) 72 | return self:_setDetail('_walls', x, y, value) 73 | end 74 | 75 | return Dungeon 76 | -------------------------------------------------------------------------------- /assign8/deps/rotLove/rot/map/ellerMaze.lua: -------------------------------------------------------------------------------- 1 | --- The Eller Maze Map Generator. 2 | -- See http://homepages.cwi.nl/~tromp/maze.html for explanation 3 | -- @module ROT.Map.EllerMaze 4 | local ROT = require((...):gsub(('.[^./\\]*'):rep(2) .. '$', '')) 5 | local EllerMaze = ROT.Map:extend("EllerMaze") 6 | 7 | --- Constructor. 8 | -- Called with ROT.Map.EllerMaze:new(width, height) 9 | -- @tparam int width Width in cells of the map 10 | -- @tparam int height Height in cells of the map 11 | function EllerMaze:init(width, height) 12 | EllerMaze.super.init(self, width, height) 13 | end 14 | 15 | --- Create. 16 | -- Creates a map. 17 | -- @tparam function callback This function will be called for every cell. It must accept the following parameters: 18 | -- @tparam int callback.x The x-position of a cell in the map 19 | -- @tparam int callback.y The y-position of a cell in the map 20 | -- @tparam int callback.value A value representing the cell-type. 0==floor, 1==wall 21 | -- @treturn ROT.Map.EllerMaze self 22 | function EllerMaze:create(callback) 23 | local map =ROT.Type.Grid() 24 | local w =math.ceil((self._width-2)/2) 25 | local rand=9/24 26 | local L ={} 27 | local R ={} 28 | 29 | for i=1,w do 30 | table.insert(L,i) 31 | table.insert(R,i) 32 | end 33 | table.insert(L,w) 34 | local j=2 35 | while jrand then 42 | self:_addToList(i, L, R) 43 | map:setCell(x + 1, y, 0) 44 | end 45 | 46 | if i~=L[i] and self._rng:random()>rand then 47 | self:_removeFromList(i, L, R) 48 | else 49 | map:setCell(x, y + 1, 0) 50 | end 51 | end 52 | j=j+2 53 | end 54 | --j=self._height%2==1 and self._height-2 or self._height-3 55 | for i=1,w do 56 | local x=2*i 57 | local y=j 58 | map:setCell(x, y, 0) 59 | 60 | if i~=L[i+1] and (i==L[i] or self._rng:random()>rand) then 61 | self:_addToList(i, L, R) 62 | map:setCell(x + 1, y, 0) 63 | end 64 | 65 | self:_removeFromList(i, L, R) 66 | end 67 | 68 | if not callback then return self end 69 | 70 | for y = 1, self._height do 71 | for x = 1, self._width do 72 | callback(x, y, map:getCell(x, y) or 1) 73 | end 74 | end 75 | 76 | return self 77 | end 78 | 79 | function EllerMaze:_removeFromList(i, L, R) 80 | R[L[i]]=R[i] 81 | L[R[i]]=L[i] 82 | R[i] =i 83 | L[i] =i 84 | end 85 | 86 | function EllerMaze:_addToList(i, L, R) 87 | R[L[i+1]]=R[i] 88 | L[R[i]] =L[i+1] 89 | R[i] =i+1 90 | L[i+1] =i 91 | end 92 | 93 | return EllerMaze 94 | -------------------------------------------------------------------------------- /assign8/deps/rotLove/rot/map/feature.lua: -------------------------------------------------------------------------------- 1 | local ROT = require((...):gsub(('.[^./\\]*'):rep(2) .. '$', '')) 2 | local Feature = ROT.Class:extend("Feature") 3 | 4 | function Feature:isValid() end 5 | function Feature:create() end 6 | function Feature:debug() end 7 | function Feature:createRandomAt() end 8 | return Feature 9 | -------------------------------------------------------------------------------- /assign8/deps/rotLove/rot/map/iceyMaze.lua: -------------------------------------------------------------------------------- 1 | --- The Icey Maze Map Generator. 2 | -- See http://www.roguebasin.roguelikedevelopment.org/index.php?title=Simple_maze for explanation 3 | -- @module ROT.Map.IceyMaze 4 | local ROT = require((...):gsub(('.[^./\\]*'):rep(2) .. '$', '')) 5 | local IceyMaze = ROT.Map:extend("IceyMaze") 6 | --- Constructor. 7 | -- Called with ROT.Map.IceyMaze:new(width, height, regularity) 8 | -- @tparam int width Width in cells of the map 9 | -- @tparam int height Height in cells of the map 10 | -- @tparam int[opt=0] regularity A value used to determine the 'randomness' of the map, 0= more random 11 | function IceyMaze:init(width, height, regularity) 12 | IceyMaze.super.init(self, width, height) 13 | self._regularity= regularity and regularity or 0 14 | end 15 | 16 | --- Create. 17 | -- Creates a map. 18 | -- @tparam function callback This function will be called for every cell. It must accept the following parameters: 19 | -- @tparam int callback.x The x-position of a cell in the map 20 | -- @tparam int callback.y The y-position of a cell in the map 21 | -- @tparam int callback.value A value representing the cell-type. 0==floor, 1==wall 22 | -- @treturn ROT.Map.IceyMaze self 23 | function IceyMaze:create(callback) 24 | local w=self._width 25 | local h=self._height 26 | local map=self:_fillMap(1) 27 | w= w%2==1 and w-1 or w-2 28 | h= h%2==1 and h-1 or h-2 29 | 30 | local cx, cy, nx, ny = 1, 1, 1, 1 31 | local done =0 32 | local blocked=false 33 | local dirs={ 34 | {0,0}, 35 | {0,0}, 36 | {0,0}, 37 | {0,0} 38 | } 39 | repeat 40 | cx=2+2*math.floor(self._rng:random()*(w-1)/2) 41 | cy=2+2*math.floor(self._rng:random()*(h-1)/2) 42 | if done==0 then map[cx][cy]=0 end 43 | if map[cx][cy]==0 then 44 | self:_randomize(dirs) 45 | repeat 46 | if math.floor(self._rng:random()*(self._regularity+1))==0 then self:_randomize(dirs) end 47 | blocked=true 48 | for i=1,4 do 49 | nx=cx+dirs[i][1]*2 50 | ny=cy+dirs[i][2]*2 51 | if self:_isFree(map, nx, ny, w, h) then 52 | map[nx][ny]=0 53 | map[cx+dirs[i][1]][cy+dirs[i][2]]=0 54 | 55 | cx=nx 56 | cy=ny 57 | blocked=false 58 | done=done+1 59 | break 60 | end 61 | end 62 | until blocked 63 | end 64 | until done+1>=w*h/4 65 | 66 | if not callback then return self end 67 | for y = 1, self._height do 68 | for x = 1, self._width do 69 | callback(x, y, map[x][y]) 70 | end 71 | end 72 | return self 73 | end 74 | 75 | function IceyMaze:_randomize(dirs) 76 | for i=1,4 do 77 | dirs[i][1]=0 78 | dirs[i][2]=0 79 | end 80 | local rand=math.floor(self._rng:random()*4) 81 | if rand==0 then 82 | dirs[1][1]=-1 83 | dirs[3][2]=-1 84 | dirs[2][1]= 1 85 | dirs[4][2]= 1 86 | elseif rand==1 then 87 | dirs[4][1]=-1 88 | dirs[2][2]=-1 89 | dirs[3][1]= 1 90 | dirs[1][2]= 1 91 | elseif rand==2 then 92 | dirs[3][1]=-1 93 | dirs[1][2]=-1 94 | dirs[4][1]= 1 95 | dirs[2][2]= 1 96 | elseif rand==3 then 97 | dirs[2][1]=-1 98 | dirs[4][2]=-1 99 | dirs[1][1]= 1 100 | dirs[3][2]= 1 101 | end 102 | end 103 | 104 | function IceyMaze:_isFree(map, x, y, w, h) 105 | if x<2 or y<2 or x>w or y>h then return false end 106 | return map[x][y]~=0 107 | end 108 | 109 | return IceyMaze 110 | -------------------------------------------------------------------------------- /assign8/deps/rotLove/rot/newFuncs.lua: -------------------------------------------------------------------------------- 1 | local ROT = require((...):gsub(('.[^./\\]*'):rep(1) .. '$', '')) 2 | 3 | -- asserts the type of 'theTable' is table 4 | local function isATable(theTable) 5 | ROT.assert(type(theTable)=='table', "bad argument #1 to 'random' (table expected got ",type(theTable),")") 6 | end 7 | 8 | -- returns string of length n consisting of only char c 9 | local function charNTimes(c, n) 10 | ROT.assert(#c==1, 'character must be a string of length 1') 11 | local s='' 12 | for _=1,n and n or 2 do 13 | s=s..c 14 | end 15 | return s 16 | end 17 | 18 | -- New Table Functions 19 | -- returns random table element, nil if length is 0 20 | function table.random(theTable) 21 | isATable(theTable) 22 | if #theTable==0 then return nil end 23 | return theTable[math.floor(ROT.RNG:random(#theTable))] 24 | end 25 | -- returns random valid index, nil if length is 0 26 | function table.randomi(theTable) 27 | isATable(theTable) 28 | if #theTable==0 then return nil end 29 | return math.floor(ROT.RNG:random(#theTable)) 30 | end 31 | -- randomly reorders the elements of the provided table and returns the result 32 | function table.randomize(theTable) 33 | isATable(theTable) 34 | local result={} 35 | while #theTable>0 do 36 | table.insert(result, table.remove(theTable, table.randomi(theTable))) 37 | end 38 | return result 39 | end 40 | -- add js slice function 41 | function table.slice (values,i1,i2) 42 | local res = {} 43 | local n = #values 44 | -- default values for range 45 | i1 = i1 or 1 46 | i2 = i2 or n 47 | if i2 < 0 then 48 | i2 = n + i2 + 1 49 | elseif i2 > n then 50 | i2 = n 51 | end 52 | if i1 < 1 or i1 > n then 53 | return {} 54 | end 55 | local k = 1 56 | for i = i1,i2 do 57 | res[k] = values[i] 58 | k = k + 1 59 | end 60 | return res 61 | end 62 | -- add js indexOf function 63 | function table.indexOf(values,value) 64 | if values then 65 | for i=1,#values do 66 | if values[i] == value then return i end 67 | end 68 | end 69 | if type(value)=='table' then return table.indexOfTable(values, value) end 70 | return 0 71 | end 72 | 73 | -- extended for use with tables of tables 74 | function table.indexOfTable(values, value) 75 | if type(value)~='table' then return 0 end 76 | for k,v in ipairs(values) do 77 | if #v==#value then 78 | local match=true 79 | for i=1,#v do 80 | if v[i]~=value[i] then match=false end 81 | end 82 | if match then return k end 83 | end 84 | end 85 | return 0 86 | end 87 | 88 | -- New String functions 89 | -- first letter capitalized 90 | function string:capitalize() 91 | return self:sub(1,1):upper() .. self:sub(2) 92 | end 93 | -- left pad with c char, repeated n times 94 | function string:lpad(c, n) 95 | c=c and c or '0' 96 | n=n and n or 2 97 | local s='' 98 | while #s < n-#self do s=s..c end 99 | return s..self 100 | end 101 | -- right pad with c char, repeated n times 102 | function string:rpad(c, n) 103 | c=c and c or '0' 104 | n=n and n or 2 105 | local s='' 106 | while #s < n-#self do s=s..c end 107 | return self..s 108 | end 109 | -- add js split function 110 | function string:split(delim, maxNb) 111 | -- Eliminate bad cases... 112 | if string.find(self, delim) == nil then 113 | return { self } 114 | end 115 | local result = {} 116 | if delim == '' or not delim then 117 | for i=1,#self do 118 | result[i]=self:sub(i,i) 119 | end 120 | return result 121 | end 122 | if maxNb == nil or maxNb < 1 then 123 | maxNb = 0 -- No limit 124 | end 125 | local pat = "(.-)" .. delim .. "()" 126 | local nb = 0 127 | local lastPos 128 | for part, pos in string.gfind(self, pat) do 129 | nb = nb + 1 130 | result[nb] = part 131 | lastPos = pos 132 | if nb == maxNb then break end 133 | end 134 | -- Handle the last field 135 | if nb ~= maxNb then 136 | result[nb + 1] = string.sub(self, lastPos) 137 | end 138 | return result 139 | end 140 | 141 | function math.round(n, mult) 142 | mult = mult or 1 143 | return math.floor((n + mult/2)/mult) * mult 144 | end 145 | 146 | -------------------------------------------------------------------------------- /assign8/deps/rotLove/rot/noise.lua: -------------------------------------------------------------------------------- 1 | local ROT = require((...):gsub(('.[^./\\]*'):rep(1) .. '$', '')) 2 | local Noise = ROT.Class:extend("Noise") 3 | 4 | function Noise:get() end 5 | 6 | return Noise 7 | -------------------------------------------------------------------------------- /assign8/deps/rotLove/rot/noise/simplex.lua: -------------------------------------------------------------------------------- 1 | --- Simplex Noise Generator. 2 | -- Based on a simple 2d implementation of simplex noise by Ondrej Zara 3 | -- Which is based on a speed-improved simplex noise algorithm for 2D, 3D and 4D in Java. 4 | -- Which is based on example code by Stefan Gustavson (stegu@itn.liu.se). 5 | -- With Optimisations by Peter Eastman (peastman@drizzle.stanford.edu). 6 | -- Better rank ordering method by Stefan Gustavson in 2012. 7 | -- @module ROT.Noise.Simplex 8 | local ROT = require((...):gsub(('.[^./\\]*'):rep(2) .. '$', '')) 9 | local Simplex=ROT.Noise:extend("Simplex") 10 | --- Constructor. 11 | -- 2D simplex noise generator. 12 | -- @tparam int gradients The random values for the noise. 13 | function Simplex:init(gradients) 14 | self._F2=.5*(math.sqrt(3)-1) 15 | self._G2=(3-math.sqrt(3))/6 16 | 17 | self._gradients={ 18 | { 0,-1}, 19 | { 1,-1}, 20 | { 1, 0}, 21 | { 1, 1}, 22 | { 0, 1}, 23 | {-1, 1}, 24 | {-1, 0}, 25 | {-1,-1} 26 | } 27 | local permutations={} 28 | local count =gradients and gradients or 256 29 | for i=1,count do 30 | table.insert(permutations, i) 31 | end 32 | 33 | permutations=table.randomize(permutations) 34 | 35 | self._perms ={} 36 | self._indexes={} 37 | 38 | for i=1,2*count do 39 | table.insert(self._perms, permutations[i%count+1]) 40 | table.insert(self._indexes, self._perms[i] % #self._gradients +1) 41 | end 42 | end 43 | 44 | --- Get noise for a cell 45 | -- Iterate over this function to retrieve noise values 46 | -- @tparam int xin x-position of noise value 47 | -- @tparam int yin y-position of noise value 48 | function Simplex:get(xin, yin) 49 | local perms =self._perms 50 | local indexes=self._indexes 51 | local count =#perms/2 52 | local G2 =self._G2 53 | 54 | local n0, n1, n2, gi=0, 0, 0 55 | 56 | local s =(xin+yin)*self._F2 57 | local i =math.floor(xin+s) 58 | local j =math.floor(yin+s) 59 | local t =(i+j)*G2 60 | local X0=i-t 61 | local Y0=j-t 62 | local x0=xin-X0 63 | local y0=yin-Y0 64 | 65 | local i1, j1 66 | if x0>y0 then 67 | i1=1 68 | j1=0 69 | else 70 | i1=0 71 | j1=1 72 | end 73 | 74 | local x1=x0-i1+G2 75 | local y1=y0-j1+G2 76 | local x2=x0-1+2*G2 77 | local y2=y0-1+2*G2 78 | 79 | local ii=i%count+1 80 | local jj=j%count+1 81 | 82 | local t0=.5- x0*x0 - y0*y0 83 | if t0>=0 then 84 | t0=t0*t0 85 | gi=indexes[ii+perms[jj]] 86 | local grad=self._gradients[gi] 87 | n0=t0*t0*(grad[1]*x0+grad[2]*y0) 88 | end 89 | 90 | local t1=.5- x1*x1 - y1*y1 91 | if t1>=0 then 92 | t1=t1*t1 93 | gi=indexes[ii+i1+perms[jj+j1]] 94 | local grad=self._gradients[gi] 95 | n1=t1*t1*(grad[1]*x1+grad[2]*y1) 96 | end 97 | 98 | local t2=.5- x2*x2 - y2*y2 99 | if t2>=0 then 100 | t2=t2*t2 101 | gi=indexes[ii+1+perms[jj+1]] 102 | local grad=self._gradients[gi] 103 | n2=t2*t2*(grad[1]*x2+grad[2]*y2) 104 | end 105 | return 70*(n0+n1+n2) 106 | end 107 | 108 | return Simplex 109 | -------------------------------------------------------------------------------- /assign8/deps/rotLove/rot/path.lua: -------------------------------------------------------------------------------- 1 | local ROT = require((...):gsub(('.[^./\\]*'):rep(1) .. '$', '')) 2 | local Path = ROT.Class:extend("Path") 3 | 4 | function Path:init(toX, toY, passableCallback, options) 5 | self._toX =toX 6 | self._toY =toY 7 | self._fromX=nil 8 | self._fromY=nil 9 | self._passableCallback=passableCallback 10 | self._options= { topology=8 } 11 | 12 | if options then for k,_ in pairs(options) do self._options[k]=options[k] end end 13 | 14 | self._dirs= self._options.topology==8 and ROT.DIRS.EIGHT or ROT.DIRS.FOUR 15 | if self._options.topology==8 then 16 | self._dirs ={self._dirs[1], 17 | self._dirs[3], 18 | self._dirs[5], 19 | self._dirs[7], 20 | self._dirs[2], 21 | self._dirs[4], 22 | self._dirs[6], 23 | self._dirs[8] } 24 | end 25 | end 26 | 27 | function Path:compute() end 28 | 29 | function Path:_getNeighbors(cx, cy) 30 | local result={} 31 | for i=1,#self._dirs do 32 | local dir=self._dirs[i] 33 | local x=cx+dir[1] 34 | local y=cy+dir[2] 35 | if self._passableCallback(x, y) then 36 | table.insert(result, {x, y}) 37 | end 38 | end 39 | return result 40 | end 41 | 42 | return Path 43 | -------------------------------------------------------------------------------- /assign8/deps/rotLove/rot/path/astar.lua: -------------------------------------------------------------------------------- 1 | --- A* Pathfinding. 2 | -- Simplified A* algorithm: all edges have a value of 1 3 | -- @module ROT.Path.AStar 4 | local ROT = require((...):gsub(('.[^./\\]*'):rep(2) .. '$', '')) 5 | local AStar=ROT.Path:extend("AStar") 6 | --- Constructor. 7 | -- @tparam int toX x-position of destination cell 8 | -- @tparam int toY y-position of destination cell 9 | -- @tparam function passableCallback Function with two parameters (x, y) that returns true if the cell at x,y is able to be crossed 10 | -- @tparam table options Options 11 | -- @tparam[opt=8] int options.topology Directions for movement Accepted values (4 or 8) 12 | function AStar:init(toX, toY, passableCallback, options) 13 | AStar.super.init(self, toX, toY, passableCallback, options) 14 | self._todo={} 15 | self._done={} 16 | self._fromX=nil 17 | self._fromY=nil 18 | end 19 | 20 | --- Compute the path from a starting point 21 | -- @tparam int fromX x-position of starting point 22 | -- @tparam int fromY y-position of starting point 23 | -- @tparam function callback Will be called for every path item with arguments "x" and "y" 24 | function AStar:compute(fromX, fromY, callback) 25 | self._todo={} 26 | self._done={} 27 | self._fromX=tonumber(fromX) 28 | self._fromY=tonumber(fromY) 29 | self._done[self._toX]={} 30 | self:_add(self._toX, self._toY, nil) 31 | 32 | while #self._todo>0 do 33 | local item=table.remove(self._todo, 1) 34 | if item.x == fromX and item.y == fromY then break end 35 | local neighbors=self:_getNeighbors(item.x, item.y) 36 | 37 | for i=1,#neighbors do 38 | local x = neighbors[i][1] 39 | local y = neighbors[i][2] 40 | if not self._done[x] then self._done[x]={} end 41 | if not self._done[x][y] then 42 | self:_add(x, y, item) 43 | end 44 | end 45 | end 46 | 47 | local item=self._done[self._fromX] and self._done[self._fromX][self._fromY] or nil 48 | if not item then return end 49 | 50 | while item do 51 | callback(tonumber(item.x), tonumber(item.y)) 52 | item=item.prev 53 | end 54 | end 55 | 56 | function AStar:_add(x, y, prev) 57 | local h = self:_distance(x, y) 58 | local obj={} 59 | obj.x =x 60 | obj.y =y 61 | obj.prev=prev 62 | obj.g =prev and prev.g+1 or 0 63 | obj.h =h 64 | self._done[x][y]=obj 65 | 66 | local f=obj.g+obj.h 67 | 68 | for i=1,#self._todo do 69 | local item=self._todo[i] 70 | local itemF = item.g + item.h; 71 | if f < itemF or (f == itemF and h < item.h) then 72 | table.insert(self._todo, i, obj) 73 | return 74 | end 75 | end 76 | 77 | table.insert(self._todo, obj) 78 | end 79 | 80 | function AStar:_distance(x, y) 81 | if self._options.topology==4 then 82 | return math.abs(x-self._fromX)+math.abs(y-self._fromY) 83 | elseif self._options.topology==8 then 84 | return math.max(math.abs(x-self._fromX), math.abs(y-self._fromY)) 85 | end 86 | end 87 | 88 | return AStar 89 | -------------------------------------------------------------------------------- /assign8/deps/rotLove/rot/path/dijkstra.lua: -------------------------------------------------------------------------------- 1 | --- Dijkstra Pathfinding. 2 | -- Simplified Dijkstra's algorithm: all edges have a value of 1 3 | -- @module ROT.Path.Dijkstra 4 | local ROT = require((...):gsub(('.[^./\\]*'):rep(2) .. '$', '')) 5 | local Dijkstra=ROT.Path:extend("Dijkstra") 6 | 7 | local Grid = ROT.Type.Grid 8 | 9 | --- Constructor. 10 | -- @tparam int toX x-position of destination cell 11 | -- @tparam int toY y-position of destination cell 12 | -- @tparam function passableCallback Function with two parameters (x, y) that returns true if the cell at x,y is able to be crossed 13 | -- @tparam table options Options 14 | -- @tparam[opt=8] int options.topology Directions for movement Accepted values (4 or 8) 15 | function Dijkstra:init(toX, toY, passableCallback, options) 16 | toX, toY = tonumber(toX), tonumber(toY) 17 | Dijkstra.super.init(self, toX, toY, passableCallback, options) 18 | 19 | self._computed=Grid() 20 | self._todo ={} 21 | 22 | self:_add(toX, toY) 23 | end 24 | 25 | --- Compute the path from a starting point 26 | -- @tparam int fromX x-position of starting point 27 | -- @tparam int fromY y-position of starting point 28 | -- @tparam function callback Will be called for every path item with arguments "x" and "y" 29 | function Dijkstra:compute(fromX, fromY, callback) 30 | fromX, fromY = tonumber(fromX), tonumber(fromY) 31 | 32 | local item = self._computed:getCell(fromX, fromY) 33 | or self:_compute(fromX, fromY) 34 | 35 | while item do 36 | callback(item.x, item.y) 37 | item=item.prev 38 | end 39 | end 40 | 41 | function Dijkstra:_compute(fromX, fromY) 42 | while #self._todo>0 do 43 | local item=table.remove(self._todo, 1) 44 | if item.x == fromX and item.y == fromY then return item end 45 | 46 | local neighbors=self:_getNeighbors(item.x, item.y) 47 | 48 | for i=1,#neighbors do 49 | local x=neighbors[i][1] 50 | local y=neighbors[i][2] 51 | if not self._computed:getCell(x, y) then 52 | self:_add(x, y, item) 53 | end 54 | end 55 | end 56 | end 57 | 58 | function Dijkstra:_add(x, y, prev) 59 | local obj = { x = x, y = y, prev = prev } 60 | 61 | self._computed:setCell(x, y, obj) 62 | table.insert(self._todo, obj) 63 | end 64 | 65 | return Dijkstra 66 | 67 | -------------------------------------------------------------------------------- /assign8/deps/rotLove/rot/rng.lua: -------------------------------------------------------------------------------- 1 | --- The RNG Class. 2 | -- A Lua port of Johannes Baagøe's Alea 3 | -- From http://baagoe.com/en/RandomMusings/javascript/ 4 | -- Johannes Baagøe , 2010 5 | -- Mirrored at: 6 | -- https://github.com/nquinlan/better-random-numbers-for-javascript-mirror 7 | -- @module ROT.RNG 8 | local ROT = require((...):gsub(('.[^./\\]*'):rep(1) .. '$', '')) 9 | local RNG = ROT.Class:extend("RNG") 10 | 11 | require "deps.randomlua" 12 | 13 | function RNG:init(seed) 14 | self.twister = twister(seed) 15 | end 16 | 17 | --- Seed. 18 | -- seed the rng 19 | -- @tparam[opt=os.clock()] number s A number to base the rng from 20 | function RNG:setSeed(seed) 21 | self.twister:randomseed(seed) 22 | end 23 | 24 | --- Random. 25 | -- get a random number 26 | -- @tparam[opt=0] int a lower threshold for random numbers 27 | -- @tparam[opt=1] int b upper threshold for random numbers 28 | -- @treturn number a random number 29 | function RNG:random(a, b) 30 | return self.twister:random(a, b) 31 | end 32 | 33 | RNG.randomseed = RNG.setSeed 34 | 35 | RNG:init() 36 | 37 | return RNG 38 | -------------------------------------------------------------------------------- /assign8/deps/rotLove/rot/scheduler.lua: -------------------------------------------------------------------------------- 1 | --- The Scheduler Prototype 2 | -- @module ROT.Scheduler 3 | local ROT = require((...):gsub(('.[^./\\]*'):rep(1) .. '$', '')) 4 | local Scheduler = ROT.Class:extend("Scheduler") 5 | 6 | function Scheduler:init() 7 | self._queue=ROT.EventQueue:new() 8 | self._repeat ={} 9 | self._current=nil 10 | end 11 | 12 | --- Get Time. 13 | -- Get time counted since start 14 | -- @treturn int elapsed time 15 | function Scheduler:getTime() 16 | return self._queue:getTime() 17 | end 18 | 19 | --- Add. 20 | -- Add an item to the schedule 21 | -- @tparam any item 22 | -- @tparam boolean repeating If true, this item will be rescheduled once it is returned by .next() 23 | -- @treturn ROT.Scheduler self 24 | function Scheduler:add(item, repeating) 25 | if repeating then table.insert(self._repeat, item) end 26 | return self 27 | end 28 | 29 | --- Get scheduled time. 30 | -- Get the time the given item is scheduled for 31 | -- @tparam any item 32 | -- @treturn number time 33 | function Scheduler:getTimeOf(item) 34 | return self._queue:getEventTime(item) 35 | end 36 | 37 | --- Clear. 38 | -- Remove all items from scheduler 39 | -- @treturn ROT.Scheduler self 40 | function Scheduler:clear() 41 | self._queue:clear() 42 | self._repeat={} 43 | self._current=nil 44 | return self 45 | end 46 | 47 | --- Remove. 48 | -- Find and remove an item from the scheduler 49 | -- @tparam any item The previously added item to be removed 50 | -- @treturn boolean true if an item was removed from the scheduler 51 | function Scheduler:remove(item) 52 | local result=self._queue:remove(item) 53 | local index=table.indexOf(self._repeat, item) 54 | if index~=0 then table.remove(self._repeat, index) end 55 | if self._current==item then self._current=nil end 56 | return result 57 | end 58 | 59 | --- Next. 60 | -- Get the next event from the scheduler and advance the appropriate amount time 61 | -- @treturn event|nil The event previously added by .add() or nil if none are queued 62 | function Scheduler:next() 63 | self._current=self._queue:get() 64 | return self._current 65 | end 66 | 67 | return Scheduler 68 | -------------------------------------------------------------------------------- /assign8/deps/rotLove/rot/scheduler/action.lua: -------------------------------------------------------------------------------- 1 | --- Action based turn scheduler. 2 | -- @module ROT.Scheduler.Action 3 | local ROT = require((...):gsub(('.[^./\\]*'):rep(2) .. '$', '')) 4 | local Action= ROT.Scheduler:extend("Action") 5 | function Action:init() 6 | Action.super.init(self) 7 | self._defaultDuration=1 8 | self._duration=self._defaultDuration 9 | end 10 | 11 | --- Add. 12 | -- Add an item to the scheduler. 13 | -- @tparam any item The item that is returned when this turn comes up 14 | -- @tparam boolean repeating If true, when this turn comes up, it will be added to the queue again 15 | -- @tparam[opt=1] int time an initial delay time 16 | -- @treturn ROT.Scheduler.Action self 17 | function Action:add(item, repeating, time) 18 | self._queue:add(item, time and time or self._defaultDuration) 19 | return Action.super.add(self, item, repeating) 20 | end 21 | 22 | --- Clear. 23 | -- empties this scheduler's event queue, no items will be returned by .next() until more are added with .add() 24 | -- @treturn ROT.Scheduler.Action self 25 | function Action:clear() 26 | self._duration = self._defaultDuration 27 | return Action.super.clear(self) 28 | end 29 | 30 | --- Remove. 31 | -- Looks for the next instance of item in the event queue 32 | -- @treturn ROT.Scheduler.Action self 33 | function Action:remove(item) 34 | if item==self._current then self._duration=self._defaultDuration end 35 | return Action.super.remove(self, item) 36 | end 37 | 38 | --- Next. 39 | -- returns the next item based on that item's last action's duration 40 | -- @return item 41 | function Action:next() 42 | if self._current and table.indexOf(self._repeat, self._current)~=0 then 43 | self._queue:add(self._current, self._duration and self._duration or self._defaultDuration) 44 | self._duration=self._defaultDuration 45 | end 46 | return Action.super.next(self) 47 | end 48 | 49 | --- set duration for the active item 50 | -- after calling next() this function defines the duration of that item's action 51 | -- @tparam int time The amount of time that the current item's action should last. 52 | -- @treturn ROT.Scheduler.Action self 53 | function Action:setDuration(time) 54 | if self._current then self._duration=time end 55 | return self 56 | end 57 | 58 | return Action 59 | -------------------------------------------------------------------------------- /assign8/deps/rotLove/rot/scheduler/simple.lua: -------------------------------------------------------------------------------- 1 | --- The simple scheduler. 2 | -- @module ROT.Scheduler.Simple 3 | local ROT = require((...):gsub(('.[^./\\]*'):rep(2) .. '$', '')) 4 | local Simple= ROT.Scheduler:extend("Simple") 5 | 6 | --- Add. 7 | -- Add an item to the schedule 8 | -- @tparam any item 9 | -- @tparam boolean repeating If true, this item will be rescheduled once it is returned by .next() 10 | -- @treturn ROT.Scheduler.Simple self 11 | function Simple:add(item, repeating) 12 | self._queue:add(item, 0) 13 | return Simple.super.add(self, item, repeating) 14 | end 15 | 16 | --- Next. 17 | -- Get the next item from the scheduler and advance the appropriate amount time 18 | -- @treturn item|nil The item previously added by .add() or nil if none are queued 19 | function Simple:next() 20 | if self._current and table.indexOf(self._repeat, self._current)~=0 then 21 | self._queue:add(self._current, 0) 22 | end 23 | return Simple.super.next(self) 24 | end 25 | 26 | return Simple 27 | 28 | --- Get Time. 29 | -- Get time counted since start 30 | -- @treturn int elapsed time 31 | -- @function Simple:getTime() 32 | 33 | --- Clear. 34 | -- Remove all items from scheduler 35 | -- @treturn ROT.Scheduler.Simple self 36 | -- @function Simple:clear() 37 | 38 | --- Remove. 39 | -- Find and remove an item from the scheduler 40 | -- @tparam any item The previously added item to be removed 41 | -- @treturn boolean true if an item was removed from the scheduler 42 | -- @function Simple:remove(item) 43 | -------------------------------------------------------------------------------- /assign8/deps/rotLove/rot/scheduler/speed.lua: -------------------------------------------------------------------------------- 1 | --- The Speed based scheduler 2 | -- @module ROT.Scheduler.Speed 3 | local ROT = require((...):gsub(('.[^./\\]*'):rep(2) .. '$', '')) 4 | local Speed= ROT.Scheduler:extend("Speed") 5 | --- Add. 6 | -- Add an item to the schedule 7 | -- @tparam userdata item Any class/module/userdata with a :getSpeed() function. The value returned by getSpeed() should be a number. 8 | -- @tparam boolean repeating If true, this item will be rescheduled once it is returned by .next() 9 | -- @tparam number time Initial time offset, defaults to 1/item:getSpeed() 10 | -- @treturn ROT.Scheduler.Speed self 11 | function Speed:add(item, repeating, time) 12 | self._queue:add(item, time or (1/item:getSpeed())) 13 | return Speed.super.add(self, item, repeating) 14 | end 15 | 16 | --- Next. 17 | -- Get the next item from the scheduler and advance the appropriate amount time 18 | -- @treturn item|nil The item previously added by .add() or nil if none are queued 19 | function Speed:next() 20 | if self._current and table.indexOf(self._repeat, self._current)~=0 then 21 | self._queue:add(self._current, 1/self._current:getSpeed()) 22 | end 23 | return Speed.super.next(self) 24 | end 25 | 26 | return Speed 27 | 28 | --- Get Time. 29 | -- Get time counted since start 30 | -- @treturn int elapsed time 31 | -- @function Speed:getTime() 32 | 33 | --- Clear. 34 | -- Remove all items from scheduler 35 | -- @treturn ROT.Scheduler.Speed self 36 | -- @function Speed:clear() 37 | 38 | --- Remove. 39 | -- Find and remove an item from the scheduler 40 | -- @tparam any item The previously added item to be removed 41 | -- @treturn boolean true if an item was removed from the scheduler 42 | -- @function Speed:remove(item) 43 | -------------------------------------------------------------------------------- /assign8/deps/rotLove/rot/type/grid.lua: -------------------------------------------------------------------------------- 1 | --- Grid. 2 | -- @module ROT.Type.Grid 3 | local ROT = require((...):gsub(('.[^./\\]*'):rep(2) .. '$', '')) 4 | local Grid = ROT.Class:extend("Grid") 5 | 6 | -- Grid class 7 | 8 | function Grid:init() 9 | self:clear() 10 | end 11 | 12 | function Grid:clear() 13 | self._points = ROT.Type.PointSet() 14 | self._values = {} 15 | end 16 | 17 | function Grid:removeCell(x, y) 18 | local i = self._points:find(x, y) 19 | if not i then return end 20 | local n = #self._points - 1 21 | local oldValue = self._values[i] 22 | self._points:pluck(i) 23 | self._values[i] = self._values[n] 24 | self._values[n] = nil 25 | return oldValue 26 | end 27 | 28 | function Grid:setCell(x, y, value) 29 | if value == nil then return self:removeCell(x, y) end 30 | local i, j = self._points:push(x, y) 31 | local oldValue = j and self._values[j] 32 | self._values[i or j] = value 33 | return oldValue 34 | end 35 | 36 | function Grid:getCell(x, y) 37 | local i = self._points:find(x, y) 38 | return i and self._values[i] 39 | end 40 | 41 | local function iterate(self, i) 42 | i = i - 2 43 | if i > 0 then 44 | local x, y = self._points:peek(i) 45 | return i, x, y, self._values[i] 46 | end 47 | end 48 | 49 | function Grid:each() 50 | return iterate, self, #self._points + 1 51 | end 52 | 53 | function Grid:getRandom() 54 | local x, y = self._points:getRandom() 55 | return x, y, self:getCell(x, y) 56 | end 57 | 58 | return Grid 59 | 60 | -------------------------------------------------------------------------------- /assign8/deps/rotLove/rot/type/pointSet.lua: -------------------------------------------------------------------------------- 1 | --- Pair set. 2 | -- An unordered collection of unique value-pairs. 3 | -- @module ROT.Type.PointSet 4 | local ROT = require((...):gsub(('.[^./\\]*'):rep(2) .. '$', '')) 5 | local PointSet = ROT.Class:extend("PointSet") 6 | 7 | function PointSet:init() 8 | self._index = {} 9 | end 10 | 11 | local function hash(x, y) 12 | return x and y * 0x4000000 + x or false -- 26-bit x and y 13 | end 14 | 15 | function PointSet:find(x, y) 16 | return self._index[hash(x, y)] 17 | end 18 | 19 | function PointSet:peek(i) 20 | return self[i], self[i + 1] 21 | end 22 | 23 | function PointSet:poke(i, x, y) 24 | self._index[hash(self:peek(i))] = nil 25 | self._index[hash(x, y)] = i 26 | self._index[false] = nil 27 | self[i], self[i + 1] = x, y 28 | return self 29 | end 30 | 31 | function PointSet:push(x, y) 32 | local key = hash(x, y) 33 | local i = self._index[key] 34 | if i then return nil, i end 35 | i = #self + 1 36 | self:poke(i, x, y) 37 | self._index[key] = i 38 | self._index[false] = nil 39 | return i 40 | end 41 | 42 | function PointSet:pluck(i) 43 | local last, x, y = #self - 1, self:peek(i) 44 | self:poke(i, self:peek(last)):poke(last) 45 | self._index[hash(x, y)] = nil 46 | self._index[hash(self:peek(i))] = i 47 | self._index[false] = nil 48 | return x, y 49 | end 50 | 51 | function PointSet:prune(x, y) 52 | local i = self:find(x, y) 53 | return i and self:pluck(i) 54 | end 55 | 56 | local function iterate(self, i) 57 | i = i - 2 58 | if i > 0 then 59 | return i, self:peek(i) 60 | end 61 | end 62 | 63 | function PointSet:each() 64 | return iterate, self, #self + 1 65 | end 66 | 67 | function PointSet:getRandom() 68 | local i = self._rng:random(1, #self / 2) * 2 - 1 69 | return self:peek(i) 70 | end 71 | 72 | return PointSet 73 | 74 | -------------------------------------------------------------------------------- /assign8/game/entity.lua: -------------------------------------------------------------------------------- 1 | local ROT = require 'deps/rotLove/rot' 2 | local termfx = require "termfx" 3 | local class = require "class.class" 4 | local types = require "class.types" 5 | local Point = require "point.point" 6 | local tiles = require "game.tiles" 7 | 8 | local id = 0 9 | 10 | local Entity = class.class({class.Object}, function(Class) 11 | function Class:constructor(game, pos) 12 | self.game = game 13 | self._pos = pos 14 | self._id = id 15 | self._health = 100 16 | id = id + 1 17 | table.insert(self.game.entities, self) 18 | end 19 | 20 | function Class:id() return self._id end 21 | function Class:pos() return self._pos end 22 | function Class:set_pos(p) self._pos = p end 23 | function Class:char() return "*" end 24 | function Class:color() return termfx.color.CYAN end 25 | function Class:collide(_) end 26 | function Class:think() end 27 | function Class:die() end 28 | function Class:health() return self._health end 29 | 30 | function Class:set_health(h) 31 | self._health = h 32 | if h <= 0 then 33 | self:die() 34 | self.game:delete_entity(self) 35 | end 36 | end 37 | 38 | -- Returns a list of positions that represent the shortest path from 39 | -- a:pos() to b:pos(), including the endpoints. 40 | function Class:path_to(e) 41 | local src = self:pos() 42 | local dst = e:pos() 43 | local dj = ROT.Path.Dijkstra( 44 | dst:x(), dst:y(), function(x, y) 45 | return not tiles.WallTile:is(self.game.tiles[x][y]) 46 | end) 47 | 48 | local path = {} 49 | dj:compute( 50 | src:x(), src:y(), function(x, y) 51 | table.insert(path, Point:new(x, y)) 52 | end) 53 | return path 54 | end 55 | 56 | function Class:compute_lighting(intensity) 57 | local _, r, g, b = termfx.colorinfo(self:color()) 58 | return termfx.rgb2color( 59 | math.ceil(r * intensity / 256.0 * 5.0), 60 | math.ceil(g * intensity / 256.0 * 5.0), 61 | math.ceil(b * intensity / 256.0 * 5.0)) 62 | end 63 | 64 | function Class:visible_tiles() 65 | local src = self:pos() 66 | local fov = ROT.FOV.Precise:new(function(_, x, y) 67 | if x < 1 or x > #self.game.tiles or 68 | y < 1 or y > #self.game.tiles[1] 69 | then return false end 70 | return tiles.GroundTile:is(self.game.tiles[x][y]) 71 | end) 72 | 73 | local visible = {} 74 | fov:compute( 75 | src:x(), src:y(), 10, function(x, y, _, _) 76 | table.insert(visible, Point:new(x, y)) 77 | end) 78 | return visible 79 | end 80 | 81 | -- Returns true if the current entitiy can see entity e, otherwise false. 82 | function Class:can_see(e) 83 | local dst = e:pos() 84 | for _, p in ipairs(self:visible_tiles()) do 85 | if p == dst then 86 | return true 87 | end 88 | end 89 | return false 90 | end 91 | 92 | function Class:__eq(other) 93 | return self:id() == other:id() 94 | end 95 | end, { 96 | game = types.Any, 97 | _id = types.Number, 98 | _health = types.Number, 99 | _pos = Point, 100 | }) 101 | 102 | return Entity 103 | -------------------------------------------------------------------------------- /assign8/game/game_tests.lua: -------------------------------------------------------------------------------- 1 | -- luacheck: std max+busted 2 | require 'busted.runner'() 3 | 4 | local ROT = require 'deps/rotLove/rot' 5 | local termfx = require "termfx" 6 | require "deps.randomlua" 7 | 8 | local function map(func, array) 9 | local new_array = {} 10 | for i, v in ipairs(array) do new_array[i] = func(v) end 11 | return new_array 12 | end 13 | 14 | local keys = { 15 | left = termfx.key.ARROW_LEFT, 16 | right = termfx.key.ARROW_RIGHT, 17 | up = termfx.key.ARROW_UP, 18 | down = termfx.key.ARROW_DOWN, 19 | wait = termfx.key.TAB, 20 | } 21 | 22 | local function monsterPositions(game) 23 | local monsters = game:monsters() 24 | return map(function(m) 25 | local pos = m:pos() 26 | return {x = pos:x(), y = pos:y()} 27 | end, monsters) 28 | end 29 | 30 | describe("Game Tests", function() 31 | it("Idle Monster Test", function() 32 | ROT.RNG:init(50) 33 | _G.game_random = _G.twister(50) 34 | 35 | local game = require("game.game"):new() 36 | 37 | assert.are.same( 38 | {{x = 45, y = 24}, {x = 50, y = 5}, {x = 13, y = 20}}, 39 | monsterPositions(game)) 40 | game:handle_input({char = "", key = keys.wait}) 41 | game:handle_input({char = "", key = keys.wait}) 42 | game:handle_input({char = "", key = keys.wait}) 43 | assert.are.same( 44 | {{x = 43, y = 24}, {x = 48, y = 5}, {x = 14, y = 20}}, 45 | monsterPositions(game)) 46 | end) 47 | 48 | it("Monster Follow / Attack", function() 49 | ROT.RNG:init(22) 50 | _G.game_random = _G.twister(22) 51 | 52 | local game = require("game.game"):new() 53 | for _=1, 12 do 54 | game:handle_input({char = "", key = keys.right}) 55 | end 56 | 57 | assert.are.same({_x = 59, _y = 7}, game:monsters()[1]:pos()) 58 | end) 59 | 60 | it("Monster Run away", function() 61 | ROT.RNG:init(25) 62 | _G.game_random = _G.twister(25) 63 | 64 | local game = require("game.game"):new() 65 | for _=1, 2 do game:handle_input({char = "", key = keys.wait}) end 66 | for _=1, 9 do game:handle_input({char = "", key = keys.right}) end 67 | for _=1, 5 do game:handle_input({char = "", key = keys.wait}) end 68 | 69 | assert.are.same({_x = 22, _y = 12}, game:monsters()[3]:pos()) 70 | end) 71 | 72 | it("Monster Lose Sight", function() 73 | ROT.RNG:init(32) 74 | _G.game_random = _G.twister(32) 75 | 76 | local game = require("game.game"):new() 77 | game:handle_input({char = "", key = keys.right}) 78 | game:handle_input({char = "", key = keys.down}) 79 | game:handle_input({char = "", key = keys.right}) 80 | game:handle_input({char = "", key = keys.down}) 81 | game:handle_input({char = "", key = keys.down}) 82 | game:handle_input({char = "", key = keys.right}) 83 | game:handle_input({char = "", key = keys.down}) 84 | game:handle_input({char = "", key = keys.right}) 85 | game:handle_input({char = "", key = keys.down}) 86 | game:handle_input({char = "", key = keys.down}) 87 | for _=1, 10 do game:handle_input({char = "", key = keys.wait}) end 88 | 89 | assert.are.same({_x = 17, _y = 6}, game:monsters()[3]:pos()) 90 | end) 91 | end) 92 | -------------------------------------------------------------------------------- /assign8/game/hero.lua: -------------------------------------------------------------------------------- 1 | local class = require "class.class" 2 | local Entity = require "game.entity" 3 | 4 | local Hero = class.class({Entity}, function(Class) 5 | function Class:collide(e) 6 | self.game:log("You hit a monster for 10 damage.") 7 | e:set_health(e:health() - 10) 8 | end 9 | 10 | function Class:set_health(h) 11 | self.game:log(string.format('Your health is now %d', h)) 12 | 13 | Entity.set_health(self, h) 14 | end 15 | end, {}) 16 | 17 | return Hero 18 | -------------------------------------------------------------------------------- /assign8/game/light.lua: -------------------------------------------------------------------------------- 1 | local class = require "class.class" 2 | local types = require "class.types" 3 | local Entity = require "game.entity" 4 | 5 | local Light = class.class({Entity}, function(Class) 6 | function Class:constructor(game, pos, intensity) 7 | Entity.constructor(self, game, pos) 8 | self._intensity = intensity 9 | end 10 | 11 | function Class:intensity() 12 | return self._intensity 13 | end 14 | end, { 15 | _intensity = types.Number 16 | }) 17 | 18 | return Light 19 | -------------------------------------------------------------------------------- /assign8/game/monster.lua: -------------------------------------------------------------------------------- 1 | local termfx = require "termfx" 2 | local class = require "class.class" 3 | local types = require "class.types" 4 | local Entity = require "game.entity" 5 | local Hero = require "game.hero" 6 | local Point = require "point.point" 7 | 8 | local Monster = class.class({Entity}, function(Class) 9 | function Class:constructor(...) 10 | Entity.constructor(self, ...) 11 | self._state_machine = coroutine.create(function() self:logic() end) 12 | end 13 | 14 | function Class:logic() 15 | local hero = self.game:hero() 16 | while true do 17 | if self:can_see(hero) then 18 | -- Your code here. 19 | else 20 | -- Idle 21 | local rand_vec = Point:new(_G.game_random:random(3) - 2, _G.game_random:random(3) - 2) 22 | self.game:try_move(self, rand_vec) 23 | coroutine.yield() 24 | end 25 | end 26 | end 27 | 28 | function Class:char() return "%" end 29 | 30 | function Class:color() return termfx.color.RED end 31 | 32 | function Class:collide(e) 33 | if Hero:is(e) then 34 | self.game:log("A monster hits you for 2 damage.") 35 | e:set_health(e:health() - 2) 36 | end 37 | end 38 | 39 | function Class:die() 40 | self.game:log("The monster dies.") 41 | end 42 | 43 | function Class:think() 44 | local status, err = coroutine.resume(self._state_machine) 45 | if not status then error(err) end 46 | end 47 | end, {_state_machine = types.Any}) 48 | 49 | return Monster 50 | -------------------------------------------------------------------------------- /assign8/game/tiles.lua: -------------------------------------------------------------------------------- 1 | local class = require "class.class" 2 | local types = require "class.types" 3 | 4 | local mod = {} 5 | 6 | mod.Tile = class.class({class.Object}, function(Class) 7 | function Class:constructor() 8 | self.seen = false 9 | end 10 | 11 | function Class:char() 12 | return error("char has not been overridden.") 13 | end 14 | 15 | function Class:seen_char() 16 | return error("seen_char has not been overridden.") 17 | end 18 | end, { 19 | seen = types.Boolean 20 | }) 21 | 22 | mod.GroundTile = class.class({mod.Tile}, function(Class) 23 | function Class:char() return "." end 24 | function Class:seen_char() return " " end 25 | end, {}) 26 | 27 | mod.WallTile = class.class({mod.Tile}, function(Class) 28 | function Class:char() return "#" end 29 | function Class:seen_char() return "+" end 30 | end, {}) 31 | 32 | return mod 33 | -------------------------------------------------------------------------------- /assign8/point/benchmark_point.lua: -------------------------------------------------------------------------------- 1 | local LuaPoint = require 'point.point' 2 | local NativePoint = require 'point.native_point' 3 | 4 | local function benchmark(name, func, count) 5 | print("===== " .. name .. " (" .. count .. " iterations) " .. " =====") 6 | 7 | local a, b = LuaPoint:new(64, 59), LuaPoint:new(98, 70) 8 | local na, nb = NativePoint:new(64, 59), NativePoint:new(98, 70) 9 | 10 | local clock = os.clock 11 | 12 | local start_lua = clock() 13 | for _=1, count do func(a, b, LuaPoint) end 14 | local lua_duration = clock() - start_lua 15 | 16 | local start_native = clock() 17 | for _=1, count do func(na, nb, NativePoint) end 18 | local native_duration = clock() - start_native 19 | 20 | print("Pure Lua:", lua_duration) 21 | print("Rust Extension:", native_duration) 22 | end 23 | 24 | benchmark('Point Creation', function(_, _, Point) 25 | local _ = Point:new(64, 59) 26 | end, 500000) 27 | 28 | benchmark('Point Property Access', function(a, b) 29 | local _, _ = a:x(), a:y() 30 | local _, _ = b:x(), b:y() 31 | end, 500000) 32 | 33 | benchmark('Point Arithmetic', function(a, b) 34 | local _ = a + b 35 | local _ = a - b 36 | end, 500000) 37 | 38 | benchmark('Point Distance', function(a, b) 39 | local _ = a:dist(b) 40 | end, 500000) 41 | 42 | benchmark('Point Equality', function(a, b) 43 | local _ = a == b 44 | local _ = a == a 45 | local _ = b == b 46 | end, 500000) 47 | 48 | benchmark('Point To String (Lua)', function(a, b) 49 | local _ = tostring(a) 50 | local _ = tostring(b) 51 | end, 500000) 52 | -------------------------------------------------------------------------------- /assign8/point/native_point.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code, non_camel_case_types, non_snake_case, non_upper_case_globals)] 2 | 3 | mod lauxlib; 4 | 5 | use lauxlib::*; 6 | use std::ffi::{CString}; 7 | use std::os::raw::{c_char, c_int}; 8 | use std::{mem, ptr}; 9 | 10 | fn cstr>(s: T) -> *const c_char { 11 | CString::new(s.into()).unwrap().into_raw() 12 | } 13 | 14 | static mut POINT_NATIVE: *const c_char = ptr::null(); 15 | 16 | unsafe fn lua_pushcfunction(L: *mut lua_State, f: lua_CFunction) { 17 | lua_pushcclosure(L, f, 0); 18 | } 19 | 20 | unsafe fn luaL_getmetatable(L: *mut lua_State, n: *const c_char) -> c_int { 21 | lua_getfield(L, LUA_REGISTRYINDEX, n) 22 | } 23 | 24 | struct Point { 25 | x: lua_Number, 26 | y: lua_Number 27 | } 28 | 29 | unsafe extern "C" fn point_new(L: *mut lua_State) -> c_int { 30 | unimplemented!() 31 | } 32 | 33 | unsafe extern "C" fn point_x(L: *mut lua_State) -> c_int { 34 | unimplemented!() 35 | } 36 | 37 | unsafe extern "C" fn point_y(L: *mut lua_State) -> c_int { 38 | unimplemented!() 39 | } 40 | 41 | unsafe extern "C" fn point_setx(L: *mut lua_State) -> c_int { 42 | unimplemented!() 43 | } 44 | 45 | unsafe extern "C" fn point_sety(L: *mut lua_State) -> c_int { 46 | unimplemented!() 47 | } 48 | 49 | unsafe extern "C" fn point_add(L: *mut lua_State) -> c_int { 50 | unimplemented!() 51 | } 52 | 53 | unsafe extern "C" fn point_sub(L: *mut lua_State) -> c_int { 54 | unimplemented!() 55 | } 56 | 57 | unsafe extern "C" fn point_dist(L: *mut lua_State) -> c_int { 58 | unimplemented!() 59 | } 60 | 61 | unsafe extern "C" fn point_tostring(L: *mut lua_State) -> c_int { 62 | unimplemented!() 63 | } 64 | 65 | unsafe extern "C" fn point_eq(L: *mut lua_State) -> c_int { 66 | let a = luaL_checkudata(L, 1, POINT_NATIVE) as *mut Point; 67 | let b = luaL_checkudata(L, 2, POINT_NATIVE) as *mut Point; 68 | lua_pushboolean(L, if (*a).x == (*b).x && (*a).y == (*b).y { 1 } else { 0 }); 69 | return 1; 70 | } 71 | 72 | #[no_mangle] 73 | pub unsafe extern "C" fn luaopen_point_native_point(L: *mut lua_State) -> isize { 74 | POINT_NATIVE = CString::new("point_native").unwrap().into_raw(); 75 | 76 | let pushfn = |s, f| { 77 | lua_pushstring(L, cstr(s)); 78 | lua_pushcfunction(L, Some(f)); 79 | lua_settable(L, -3); 80 | }; 81 | 82 | luaL_newmetatable(L as *mut lauxlib::lua_State, POINT_NATIVE); 83 | pushfn("__add", point_add); 84 | pushfn("__sub", point_sub); 85 | pushfn("__eq", point_eq); 86 | pushfn("__tostring", point_tostring); 87 | 88 | lua_createtable(L, 1, 0); 89 | pushfn("new", point_new); 90 | pushfn("x", point_x); 91 | pushfn("y", point_y); 92 | pushfn("set_x", point_setx); 93 | pushfn("set_y", point_sety); 94 | pushfn("dist", point_dist); 95 | 96 | lua_pushstring(L, cstr("__index")); 97 | lua_pushvalue(L, -2); 98 | lua_settable(L, -4); 99 | 100 | return 1; 101 | } 102 | -------------------------------------------------------------------------------- /assign8/point/point.lua: -------------------------------------------------------------------------------- 1 | local class = require "class.class" 2 | local types = require "class.types" 3 | 4 | local Point = class.class({class.Object}, function(Class) 5 | function Class:constructor(x, y) 6 | self._x = x 7 | self._y = y 8 | end 9 | 10 | function Class:dist(p) 11 | return ((p:x() - self._x)^2 + (p:y() - self._y)^2)^(0.5) 12 | end 13 | 14 | function Class:x() return self._x end 15 | function Class:y() return self._y end 16 | function Class:set_x(x) self._x = x end 17 | function Class:set_y(y) self._y = y end 18 | 19 | function Class:__add(p) 20 | return Class:new(self:x() + p:x(), self:y() + p:y()) 21 | end 22 | 23 | function Class:__sub(p) 24 | return Class:new(self:x() - p:x(), self:y() - p:y()) 25 | end 26 | 27 | function Class:__eq(p) 28 | return self:x() == p:x() and self:y() == p:y() 29 | end 30 | 31 | function Class:__tostring() 32 | return string.format("{%d, %d}", self:x(), self:y()) 33 | end 34 | end, { 35 | _x = types.Number, 36 | _y = types.Number 37 | }) 38 | 39 | if _G.NATIVE_POINT then 40 | local mod = require "point.native_point" 41 | function mod:is(_) return true end 42 | return mod 43 | else 44 | return Point 45 | end 46 | -------------------------------------------------------------------------------- /assign8/point/point_tests.lua: -------------------------------------------------------------------------------- 1 | -- luacheck: std max+busted 2 | require 'busted.runner'() 3 | 4 | _G.NATIVE_POINT = true 5 | local Point = require "point.point" 6 | 7 | describe("Point", function() 8 | it("has a constructor", function() 9 | local p = Point:new(1, 2) 10 | assert.are.equals(p:x(), 1) 11 | assert.are.equals(p:y(), 2) 12 | end) 13 | 14 | it("can be updated", function() 15 | local p = Point:new(1, 2) 16 | p:set_x(2) 17 | p:set_y(3) 18 | assert.are.equals(p:x(), 2) 19 | assert.are.equals(p:y(), 3) 20 | end) 21 | 22 | it("can be added/subtracted", function() 23 | local p = Point:new(1, 2) + Point:new(3, 4) - Point:new(1, 1) 24 | assert.are.equals(p:x(), 3) 25 | assert.are.equals(p:y(), 5) 26 | end) 27 | end) 28 | -------------------------------------------------------------------------------- /assign8/roguelike.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stanford-cs242/f18-assignments/0646cc427e126f105654405323c4074db3015f56/assign8/roguelike.bin -------------------------------------------------------------------------------- /assign8/roguelike.lua: -------------------------------------------------------------------------------- 1 | require "deps.randomlua" 2 | 3 | local argparse = require "argparse" 4 | 5 | local parser = argparse("rougelike.lua", "CS242 Roguelike Assignment") 6 | parser:option("--seed", "Set the RNG seed.", nil, tonumber) 7 | parser:flag("--lights-on", "Make the entire play field visible.") 8 | parser:flag("--native-point", "Use the native point implementation.") 9 | local args = parser:parse() 10 | 11 | if args.seed then 12 | local ROT = require 'deps/rotLove/rot' 13 | ROT.RNG:init(args.seed) 14 | _G.game_random = _G.twister(args.seed) 15 | else 16 | _G.game_random = _G.twister() 17 | end 18 | 19 | -- Use native point impl if --native-point flag is provided. 20 | if args.native_point then 21 | _G.NATIVE_POINT = true 22 | end 23 | 24 | local game = require("game.game"):new() 25 | 26 | if args.lights_on then 27 | game.lights_on = true 28 | end 29 | 30 | game:start() 31 | -------------------------------------------------------------------------------- /final/grading.py: -------------------------------------------------------------------------------- 1 | import time 2 | import re 3 | import getpass 4 | 5 | import requests 6 | from bs4 import BeautifulSoup 7 | 8 | 9 | # per-assignment breakdown weights 10 | weights = { 11 | 'Assignment 1: Lambda Theory - Program': 0.55, 12 | 'Assignment 1: Lambda Theory - Written': 0.45, 13 | 'Assignment 2: Lambda Practice - Written': 0.25, 14 | 'Assignment 2: Lambda Practice - Program': 0.75, 15 | 'Assignment 3: Collections API - Program': 0.8, 16 | 'Assignment 3: Collections API - Written': 0.2, 17 | 'Assignment 4: WebCoin - Programming': 0.8, 18 | 'Assignment 4: WebCoin - Written': 0.2, 19 | 'Assignment 5: WebAssembler': 1, 20 | 'Assignment 6: Futures': 1, 21 | 'Assignment 7: TCProof - Bugs': 0.3, 22 | 'Assignment 7: TCProof - Program': 0.7, 23 | 'Assignment 8: Roguelike': 1 24 | } 25 | 26 | 27 | def proc_score(stext): 28 | num, denom = [float(x) for x in stext.split(' / ')] 29 | return num * 100 / denom 30 | 31 | 32 | def proc_late(ltext): 33 | latedays = 0 34 | dres = re.search(r'(\d+) Day', ltext) 35 | if dres: 36 | latedays += int(dres.group(1)) 37 | hres = re.search(r'(\d+) Hour', ltext) 38 | if hres: 39 | latedays += 1 40 | mres = re.search(r'(\d+) Minute', ltext) 41 | if mres and not hres: 42 | latedays += 1 43 | 44 | return latedays 45 | 46 | 47 | if __name__ == '__main__': 48 | username = input('Gradescope login email: ') 49 | password = getpass.getpass('Gradescope password: ') 50 | guestlecs = input('How many guest lectures did you attend? ') 51 | 52 | client = requests.session() 53 | res = client.get('https://www.gradescope.com/login') 54 | 55 | soup = BeautifulSoup(res.text, 'html.parser') 56 | 57 | ctoken = soup.find('meta', attrs={'name': 'csrf-token'}) 58 | ctoken = ctoken.attrs['content'] 59 | 60 | atoken = soup.find('input', attrs={'name':'authenticity_token'}) 61 | atoken = atoken.attrs['value'] 62 | 63 | data = { 64 | 'session[email]': username, 65 | 'session[password]': password, 66 | 'authenticity_token': atoken, 67 | 'utf8': '✓', 68 | 'session_remember_me': '0' 69 | } 70 | headers = { 71 | 'cookie': '; '.join([x.name + '=' + x.value for x in client.cookies]), 72 | 'content-type': 'application/x-www-form-urlencoded', 73 | 'X-CSRFToken': ctoken, 74 | 'Referer': 'https://www.gradescope.com/login' 75 | } 76 | client.post('https://www.gradescope.com/login', data=data, headers=headers) 77 | 78 | res = client.get('https://www.gradescope.com/courses/19074') 79 | 80 | assignments = BeautifulSoup(res.text, 'html.parser').find(id='assignments-student-table') 81 | 82 | 83 | grades = [0] * 8 84 | ld_used = [0] * 8 85 | 86 | a8_graded = True 87 | for row in assignments.find_all('tr', role='row')[1:]: 88 | aname = row.find('th', class_='table--primaryLink').text 89 | 90 | if 'Final' in aname: continue 91 | 92 | submission = row.find(class_='submissionStatus').find_all('div') 93 | latedays = 0 94 | if len(submission) == 2 and 'No Submission' in submission[1]: 95 | score = 0 96 | elif 'Assignment 8' in aname and len(submission) > 1 and 'Submitted' in submission[1]: 97 | a8_graded = False 98 | score = 90 99 | latedays = proc_late(submission[2].text) if len(submission) > 2 else 0 100 | else: 101 | score = proc_score(submission[0].text) 102 | latedays = proc_late(submission[1].text) if len(submission) > 1 else 0 103 | 104 | anum = int(re.search(r'\d+', aname).group(0)) 105 | 106 | grades[anum - 1] += score * weights[aname] 107 | ld_used[anum - 1] = max(ld_used[anum-1], latedays) 108 | 109 | # handle latedays 110 | ld_remaining = 5 111 | for i, ld in enumerate(ld_used): 112 | if ld >= ld_remaining: 113 | grades[i] = min(grades[i], 100 - 10 * (ld - ld_remaining)) 114 | ld_remaining = max(ld_remaining - ld, 0) 115 | 116 | 117 | for i, g in enumerate(grades): 118 | print('Grade for Assignment %d: %.2f' % (i+1, g)) 119 | if not a8_graded: 120 | print('**You\'ve submitted Assignment 8 but grades are not yet released; the score of 90 above is a placeholder. Check back once grades are released.**') 121 | 122 | print('Late days used: %d out of 5' % (5 - ld_remaining)) 123 | 124 | 125 | # downweight lowest 126 | lidx = min(list(enumerate(grades[:-1])), key=lambda x: x[1])[0] 127 | 128 | for i, g in enumerate(grades): 129 | if i == lidx: 130 | grades[i] *= 0.05 131 | elif i == 7: 132 | grades[i] *= 0.15 133 | else: 134 | grades[i] *= 0.1 135 | 136 | grade = sum(grades) 137 | grade += 0.02 * float(guestlecs) / 3 * 100 138 | 139 | finals = [70, 80, 90, 100] 140 | for f in finals: 141 | print('If you got a %d on the final, your final grade would be %.2f.' % (f, grade + 0.18 * f)) 142 | 143 | 144 | 145 | 146 | 147 | -------------------------------------------------------------------------------- /final/make_submission.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | zip -r -0 submission.zip proofs.lean 3 | -------------------------------------------------------------------------------- /final/proofs.lean: -------------------------------------------------------------------------------- 1 | -- Required: chapters 1, 2, 3 2 | section part1 3 | variables p q r s : Prop 4 | 5 | theorem and_commutativity : p ∧ q ↔ q ∧ p := 6 | sorry 7 | 8 | theorem demorgans_law : ¬(p ∨ q) ↔ ¬p ∧ ¬q := 9 | sorry 10 | 11 | theorem contraposition : (p → q) → (¬q → ¬p) := 12 | sorry 13 | end part1 14 | 15 | -- Required: chapters 1, 2, 3, 4.1 16 | section part2 17 | variables (α : Type) (p q : α → Prop) 18 | variable r : Prop 19 | 20 | theorem and_forall_dist : (∀ x, p x ∧ q x) ↔ (∀ x, p x) ∧ (∀ x, q x) := 21 | sorry 22 | 23 | theorem unbound_prop : (∀ x, p x ∨ r) ↔ (∀ x, p x) ∨ r := 24 | sorry 25 | 26 | variables (men : Type) (barber : men) 27 | variable (shaves : men → men → Prop) 28 | 29 | theorem barber_paradox : ¬ (∀ x : men, shaves barber x ↔ ¬ shaves x x) := 30 | sorry 31 | end part2 32 | 33 | -- Required: chapters 1, 2, 3, 4.1, 4.4 34 | section part4 35 | open classical 36 | 37 | variables (α : Type) (p q : α → Prop) 38 | variable a : α 39 | variable r : Prop 40 | 41 | theorem forall_inverse : (∀ x, p x) ↔ ¬ (∃ x, ¬ p x) := 42 | sorry 43 | end part4 44 | 45 | -- Required: chapters 1, 2, 3, 4 46 | section part5 47 | variables (real : Type) [ordered_ring real] 48 | variables (log exp : real → real) 49 | variable log_exp_eq : ∀ x, log (exp x) = x 50 | variable exp_log_eq : ∀ {x}, x > 0 → exp (log x) = x 51 | variable exp_pos : ∀ x, exp x > 0 52 | variable exp_add : ∀ x y, exp (x + y) = exp x * exp y 53 | 54 | -- this ensures the assumptions are available in tactic proofs 55 | include log_exp_eq exp_log_eq exp_pos exp_add 56 | 57 | example (x y z : real) : 58 | exp (x + y + z) = exp x * exp y * exp z := 59 | by rw [exp_add, exp_add] 60 | 61 | example (y : real) (h : y > 0) : exp (log y) = y := 62 | exp_log_eq h 63 | 64 | theorem log_mul {x y : real} (hx : x > 0) (hy : y > 0) : 65 | log (x * y) = log x + log y := 66 | sorry 67 | end part5 68 | 69 | -- Required: chapters 1, 2, 3, 4, 7 70 | section part6 71 | inductive Typ 72 | | Nat 73 | | Fun : Typ → Typ → Typ 74 | 75 | inductive Expr 76 | | Nat : ℕ → Expr 77 | | Add : Expr → Expr → Expr 78 | | Lam : Typ → Expr → Expr 79 | | App : Expr -> Expr -> Expr 80 | | Var : ℕ → Expr 81 | 82 | def ProofContext := list Typ 83 | 84 | variable has_type : ProofContext → Expr → Typ → Prop 85 | 86 | variable t_nat : ∀ (gamma : ProofContext), ∀ (n : ℕ), 87 | has_type gamma (Expr.Nat n) Typ.Nat 88 | 89 | variable t_add : ∀ (gamma : ProofContext), ∀ (e1 : Expr), ∀ (e2 : Expr), 90 | (has_type gamma e1 Typ.Nat) ∧ (has_type gamma e2 Typ.Nat) → 91 | has_type gamma (Expr.Add e1 e2) Typ.Nat 92 | 93 | variable t_lam : ∀ (gamma : ProofContext), ∀ (e : Expr), ∀ (t_arg : Typ), ∀ (t_ret : Typ), 94 | has_type (t_arg :: gamma) e t_ret → 95 | has_type gamma (Expr.Lam t_arg e) (Typ.Fun t_arg t_ret) 96 | 97 | variable t_app : ∀ (gamma : ProofContext), ∀ (e1 : Expr), ∀ (e2 : Expr), ∀ (t_arg : Typ), ∀ (t_ret : Typ), 98 | has_type gamma e1 (Typ.Fun t_arg t_ret) ∧ has_type gamma e2 t_arg → 99 | has_type gamma (Expr.App e1 e2) t_ret 100 | 101 | variable t_var : ∀ (gamma : ProofContext), ∀ (t : Typ), ∀ (n : ℕ), 102 | gamma.nth n = some t → has_type gamma (Expr.Var n) t 103 | 104 | def e1 : Expr := (Expr.Add (Expr.Nat 3) (Expr.Nat 2)) 105 | theorem e1_type : has_type [] e1 Typ.Nat := 106 | sorry 107 | 108 | def e2 : Expr := Expr.Lam Typ.Nat (Expr.Var 0) 109 | theorem e2_type : has_type [] e2 (Typ.Fun Typ.Nat Typ.Nat) := 110 | sorry 111 | end part6 112 | -------------------------------------------------------------------------------- /lab1/Makefile: -------------------------------------------------------------------------------- 1 | all: exercise1.native exercise2.native exercise3.native 2 | 3 | BUILD = corebuild 4 | FLAGS = -use-ocamlfind 5 | 6 | %.native: always 7 | $(BUILD) $(FLAGS) $@ 8 | 9 | clean: 10 | rm -rf *.native *.top _build 11 | 12 | always: 13 | 14 | .PHONY: always 15 | -------------------------------------------------------------------------------- /lab1/_tags: -------------------------------------------------------------------------------- 1 | : annot, bin_annot, thread 2 | -------------------------------------------------------------------------------- /lab1/exercise1.ml: -------------------------------------------------------------------------------- 1 | open Core 2 | 3 | exception Unimplemented 4 | 5 | let main () = 6 | let rec gcd (m : int) (n : int) : int = 7 | raise Unimplemented 8 | in 9 | 10 | assert (gcd 5 2 = 1); 11 | assert (gcd 10 2 = 2); 12 | assert (gcd 48 18 = 6); 13 | 14 | let rec fizz_buzz (n : int) : unit = 15 | raise Unimplemented 16 | in 17 | 18 | let read_line () : string = 19 | match In_channel.input_line In_channel.stdin with 20 | | Some s -> s 21 | | None -> assert false 22 | in 23 | 24 | let rec read_password (password : string) : unit = 25 | raise Unimplemented 26 | in 27 | 28 | let substring_match (pattern : string) (source : string) : int option = 29 | raise Unimplemented 30 | in 31 | 32 | assert (substring_match "foo" "foobar" = Some 0); 33 | assert (substring_match "foo" "barfoo" = Some 3); 34 | assert (substring_match "z" "foobar" = None); 35 | 36 | () 37 | 38 | let () = main () 39 | -------------------------------------------------------------------------------- /lab1/exercise2.ml: -------------------------------------------------------------------------------- 1 | open Core 2 | 3 | exception Unimplemented 4 | 5 | module type IntTree = sig 6 | type tree = Leaf | Node of tree * int * tree 7 | val size : tree -> int 8 | val map : (int -> int) -> tree -> tree 9 | val to_string : tree -> string 10 | val binary_search : tree -> int -> int option 11 | end 12 | 13 | module IntTreeImpl : IntTree = struct 14 | type tree = Leaf | Node of tree * int * tree 15 | 16 | let rec size (t : tree) : int = 17 | match t with 18 | | Leaf -> 0 19 | | Node (l, _, r) -> 1 + (size l) + (size r) 20 | 21 | let rec map (f : int -> int) (t : tree) = 22 | raise Unimplemented 23 | 24 | let rec to_string (t : tree) : string = 25 | raise Unimplemented 26 | 27 | let rec binary_search (t : tree) (n : int) : int option = 28 | raise Unimplemented 29 | end 30 | 31 | module IntTreeTests(T : IntTree) = struct 32 | let t : T.tree = T.Node(T.Leaf, 2, T.Leaf) in 33 | assert (T.size t = 1); 34 | assert (T.to_string t = "((), 2, ())"); 35 | assert (T.map (fun x -> x + 1) t = T.Node(T.Leaf, 3, T.Leaf)); 36 | 37 | let t = T.Node(T.Node(T.Leaf, 1, T.Leaf), 3 ,T.Node(T.Leaf, 5, T.Leaf)) in 38 | assert (T.binary_search t 2 = Some 1); 39 | assert (T.binary_search t 3 = Some 3); 40 | assert (T.binary_search t 6 = Some 5); 41 | assert (T.binary_search t 0 = None) 42 | end 43 | 44 | module Tests = IntTreeTests(IntTreeImpl) 45 | -------------------------------------------------------------------------------- /lab1/exercise3.ml: -------------------------------------------------------------------------------- 1 | open Core 2 | 3 | exception Unimplemented 4 | 5 | type binop = Add | Sub 6 | 7 | type expr = 8 | | Int of int 9 | | Bool of bool 10 | | Binop of binop * expr * expr 11 | | Iszero of expr 12 | | If of expr * expr * expr 13 | 14 | type typ = 15 | | IntT 16 | | BoolT 17 | 18 | let rec typecheck (e : expr) : typ option = 19 | match e with 20 | | Int n -> Some(IntT) 21 | | Bool n -> Some(BoolT) 22 | | Binop (_, e1, e2) -> 23 | raise Unimplemented 24 | | Iszero e -> 25 | raise Unimplemented 26 | | If (e1, e2, e3) -> 27 | raise Unimplemented 28 | ;; 29 | 30 | assert (typecheck (Int 0) = Some IntT); 31 | assert (typecheck (Binop(Add, Int 0, Bool false)) = None); 32 | assert (typecheck (Iszero (Int 0)) = Some BoolT); 33 | 34 | type result = 35 | | Step of expr 36 | | Val 37 | 38 | let rec trystep (e : expr) : result = 39 | match e with 40 | | Int _ -> Val 41 | | Bool _ -> Val 42 | | Binop (binop, e1, e2) -> 43 | (match trystep e1 with 44 | | Step e1' -> Step(Binop(binop, e1', e2)) 45 | | Val -> 46 | (match trystep e2 with 47 | | Step e2' -> Step(Binop(binop, e1, e2')) 48 | | Val -> 49 | let (Int n1, Int n2) = (e1, e2) in 50 | Step(Int(match binop with 51 | | Add -> n1 + n2 52 | | Sub -> n1 - n2)))) 53 | | Iszero e -> 54 | raise Unimplemented 55 | | If (e1, e2, e3) -> 56 | raise Unimplemented 57 | 58 | let rec eval (e : expr) : expr = 59 | match trystep e with 60 | | Step e' -> eval e' 61 | | Val -> e 62 | ;; 63 | 64 | assert (eval (Int 0) = (Int 0)); 65 | assert (eval (Binop(Add, Int 1, Int 2)) = (Int 3)); 66 | -------------------------------------------------------------------------------- /lab1/solution/Makefile: -------------------------------------------------------------------------------- 1 | all: exercise1.native exercise2.native exercise3.native 2 | 3 | BUILD = corebuild 4 | FLAGS = -use-ocamlfind 5 | 6 | %.native: always 7 | $(BUILD) $(FLAGS) $@ 8 | 9 | clean: 10 | rm -rf *.native *.top _build 11 | 12 | always: 13 | 14 | .PHONY: always 15 | -------------------------------------------------------------------------------- /lab1/solution/_tags: -------------------------------------------------------------------------------- 1 | : annot, bin_annot, thread 2 | -------------------------------------------------------------------------------- /lab1/solution/exercise1.ml: -------------------------------------------------------------------------------- 1 | open Core 2 | 3 | exception Unimplemented 4 | 5 | let main () = 6 | let rec gcd (m : int) (n : int) : int = 7 | if n = 0 then m 8 | else gcd n (m mod n) 9 | in 10 | 11 | assert (gcd 5 2 = 1); 12 | assert (gcd 10 2 = 2); 13 | assert (gcd 48 18 = 6); 14 | 15 | let rec fizz_buzz (n : int) : unit = 16 | if n mod 3 = 0 then Printf.printf "fizz" 17 | else if n mod 5 = 0 then Printf.printf "buzz"; 18 | 19 | if n > 0 then fizz_buzz (n - 1) 20 | else () 21 | in 22 | 23 | let read_line () : string = 24 | match In_channel.input_line In_channel.stdin with 25 | | Some s -> s 26 | | None -> assert false 27 | in 28 | 29 | let rec read_password (password : string) : unit = 30 | if read_line() <> password then read_password password 31 | in 32 | 33 | let substring_match (pattern : string) (source : string) : int option = 34 | let n = String.length pattern in 35 | let rec aux i = 36 | if i + n > String.length source then None 37 | else if String.slice source i (i + n) = pattern then Some i 38 | else aux (i + 1) 39 | in 40 | aux 0 41 | in 42 | 43 | assert (substring_match "foo" "foobar" = Some 0); 44 | assert (substring_match "foo" "barfoo" = Some 3); 45 | assert (substring_match "z" "foobar" = None); 46 | 47 | () 48 | 49 | let () = main () 50 | -------------------------------------------------------------------------------- /lab1/solution/exercise2.ml: -------------------------------------------------------------------------------- 1 | open Core 2 | 3 | exception Unimplemented 4 | 5 | module type IntTree = sig 6 | type tree = Leaf | Node of tree * int * tree 7 | val size : tree -> int 8 | val map : (int -> int) -> tree -> tree 9 | val to_string : tree -> string 10 | val binary_search : tree -> int -> int option 11 | end 12 | 13 | module IntTreeImpl : IntTree = struct 14 | type tree = Leaf | Node of tree * int * tree 15 | 16 | let rec size (t : tree) : int = 17 | match t with 18 | | Leaf -> 0 19 | | Node (l, _, r) -> 1 + (size l) + (size r) 20 | 21 | let rec map (f : int -> int) (t : tree) = 22 | match t with 23 | | Leaf -> Leaf 24 | | Node (l, x, r) -> Node (map f l, f x, map f r) 25 | 26 | let rec to_string (t : tree) : string = 27 | match t with 28 | | Leaf -> "()" 29 | | Node (l, x, r) -> 30 | Printf.sprintf "(%s, %d, %s)" 31 | (to_string l) x (to_string r) 32 | 33 | let rec binary_search (t : tree) (n : int) : int option = 34 | match t with 35 | | Leaf -> None 36 | | Node (l, x, r) -> 37 | if x <= n then 38 | (match binary_search r n with 39 | | Some x' -> Some x' 40 | | None -> Some x) 41 | else 42 | binary_search l n 43 | end 44 | 45 | module IntTreeTests(T : IntTree) = struct 46 | let t : T.tree = T.Node(T.Leaf, 2, T.Leaf) in 47 | assert (T.size t = 1); 48 | assert (T.to_string t = "((), 2, ())"); 49 | assert (T.map (fun x -> x + 1) t = T.Node(T.Leaf, 3, T.Leaf)); 50 | 51 | let t = T.Node(T.Node(T.Leaf, 1, T.Leaf), 3 ,T.Node(T.Leaf, 5, T.Leaf)) in 52 | assert (T.binary_search t 2 = Some 1); 53 | assert (T.binary_search t 3 = Some 3); 54 | assert (T.binary_search t 6 = Some 5); 55 | assert (T.binary_search t 0 = None) 56 | end 57 | 58 | module Tests = IntTreeTests(IntTreeImpl) 59 | -------------------------------------------------------------------------------- /lab1/solution/exercise3.ml: -------------------------------------------------------------------------------- 1 | open Core 2 | 3 | exception Unimplemented 4 | 5 | type binop = Add | Sub 6 | 7 | type expr = 8 | | Int of int 9 | | Bool of bool 10 | | Binop of binop * expr * expr 11 | | Iszero of expr 12 | | If of expr * expr * expr 13 | 14 | type typ = 15 | | IntT 16 | | BoolT 17 | 18 | let rec typecheck (e : expr) : typ option = 19 | match e with 20 | | Int n -> Some(IntT) 21 | | Bool n -> Some(BoolT) 22 | | Binop (_, e1, e2) -> 23 | (match (typecheck e1, typecheck e2) with 24 | | (Some IntT, Some IntT) -> Some IntT 25 | | _ -> None) 26 | | Iszero e -> 27 | (match typecheck e with 28 | | Some IntT -> Some BoolT 29 | | _ -> None) 30 | | If (e1, e2, e3) -> 31 | (match (typecheck e1, typecheck e2, typecheck e3) with 32 | | (Some BoolT, Some t1, Some t2) when t1 = t2 -> Some t1 33 | | _ -> None) 34 | ;; 35 | 36 | assert (typecheck (Int 0) = Some IntT); 37 | assert (typecheck (Binop(Add, Int 0, Bool false)) = None); 38 | assert (typecheck (Iszero (Int 0)) = Some BoolT); 39 | 40 | type result = 41 | | Step of expr 42 | | Val 43 | 44 | let rec trystep (e : expr) : result = 45 | match e with 46 | | Int _ -> Val 47 | | Bool _ -> Val 48 | | Binop (binop, e1, e2) -> 49 | (match trystep e1 with 50 | | Step e1' -> Step(Binop(binop, e1', e2)) 51 | | Val -> 52 | (match trystep e2 with 53 | | Step e2' -> Step(Binop(binop, e1, e2')) 54 | | Val -> 55 | let (Int n1, Int n2) = (e1, e2) in 56 | Step(Int(match binop with 57 | | Add -> n1 + n2 58 | | Sub -> n1 - n2)))) 59 | | Iszero e -> 60 | (match trystep e with 61 | | Step e' -> Step(Iszero(e')) 62 | | Val -> 63 | let Int n = e in 64 | Step(Bool(n = 0))) 65 | | If (e1, e2, e3) -> 66 | (match trystep e1 with 67 | | Step e1' -> Step(If(e1', e2, e3)) 68 | | Val -> 69 | let Bool b = e1 in 70 | Step(if b then e2 else e3)) 71 | 72 | let rec eval (e : expr) : expr = 73 | match trystep e with 74 | | Step e' -> eval e' 75 | | Val -> e 76 | ;; 77 | 78 | assert (eval (Int 0) = (Int 0)); 79 | assert (eval (Binop(Add, Int 1, Int 2)) = (Int 3)); 80 | -------------------------------------------------------------------------------- /lab2/Cargo.lock: -------------------------------------------------------------------------------- 1 | [[package]] 2 | name = "rustlab" 3 | version = "0.1.0" 4 | 5 | -------------------------------------------------------------------------------- /lab2/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rustlab" 3 | version = "0.1.0" 4 | authors = ["Will Crichton "] 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /lab2/solution/Cargo.lock: -------------------------------------------------------------------------------- 1 | [[package]] 2 | name = "rustlab" 3 | version = "0.1.0" 4 | 5 | -------------------------------------------------------------------------------- /lab2/solution/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rustlab" 3 | version = "0.1.0" 4 | authors = ["Will Crichton "] 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /lab2/solution/src/main.rs: -------------------------------------------------------------------------------- 1 | mod part1; 2 | mod part2; 3 | 4 | fn main() {} 5 | -------------------------------------------------------------------------------- /lab2/solution/src/part1.rs: -------------------------------------------------------------------------------- 1 | use std::{ptr, io}; 2 | 3 | fn password_checker(s: String) { 4 | let mut guesses = 0; 5 | loop { 6 | let mut buffer = String::new(); 7 | if let Err(_) = io::stdin().read_line(&mut buffer) { return; } 8 | if buffer.len() == 0 { return; } 9 | 10 | if &buffer[0..(buffer.len()-1)] == &s { 11 | println!("You guessed it!"); 12 | return; 13 | } else { 14 | println!("Guesses: {}", guesses + 1); 15 | guesses += 1; 16 | } 17 | } 18 | } 19 | 20 | fn add_n(v: Vec, n: i32) -> Vec { 21 | v.into_iter().map(|x| x + n).collect() 22 | } 23 | 24 | fn add_n_inplace(v: &mut Vec, n: i32) { 25 | for x in v.iter_mut() { 26 | *x = *x + n; 27 | } 28 | } 29 | 30 | fn reverse_clone(v: &mut Vec) { 31 | let n = v.len(); 32 | for i in 0..n/2 { 33 | let x: T = v[i].clone(); 34 | v[i] = v[n-i-1].clone(); 35 | v[n-i-1] = x; 36 | } 37 | } 38 | 39 | fn reverse(v: &mut Vec) { 40 | let n = v.len(); 41 | for i in 0..n/2 { 42 | unsafe { 43 | ptr::swap(&mut v[i] as *mut T, &mut v[n-i-1] as *mut T); 44 | } 45 | } 46 | } 47 | 48 | #[cfg(test)] 49 | mod test { 50 | use super::*; 51 | 52 | #[test] 53 | fn test_password_checker() { 54 | //password_checker(String::from("Password1")); 55 | } 56 | 57 | #[test] 58 | fn test_add_n() { 59 | assert_eq!(add_n(vec![1], 2).pop().unwrap(), 3); 60 | } 61 | 62 | #[test] 63 | fn test_add_n_inplace() { 64 | let mut v = vec![1]; 65 | add_n_inplace(&mut v, 2); 66 | assert_eq!(v[0], 3); 67 | } 68 | 69 | #[test] 70 | fn test_reverse() { 71 | let mut v = vec![1, 2, 3]; 72 | reverse(&mut v); 73 | assert_eq!(v[0], 3); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /lab2/solution/src/part2.rs: -------------------------------------------------------------------------------- 1 | use std::collections::{HashMap, HashSet}; 2 | 3 | struct Event { 4 | pub name: String, 5 | pub month: u8, 6 | pub day: u8, 7 | pub year: u32 8 | } 9 | 10 | /* You need to complete two functions in this implementation 11 | * has_conflict() and update_event(). Note that the argument(s) and 12 | * return values for these two functions are missing below. 13 | * You can refer to tests for more information. */ 14 | impl Event { 15 | pub fn new(name: String, month: u8, day: u8, year: u32) -> Event { 16 | Event { name, month, day, year } 17 | } 18 | 19 | /* This function checks if two events are one the same date */ 20 | pub fn has_conflict(&self, other: &Event) -> bool { 21 | self.month == other.month && self.day == other.day && self.year == other.year 22 | } 23 | 24 | /* This function shifts the date of an event by one day. 25 | * You can assume that the date is not on the last day 26 | * of a month */ 27 | pub fn update_event(&mut self) { 28 | self.day += 1; 29 | } 30 | } 31 | 32 | #[derive(Debug, Clone, Eq, PartialEq)] 33 | struct Trie { 34 | chr: char, 35 | has: bool, 36 | children: Vec, 37 | } 38 | 39 | /* ["a", "cc", "ab"] => 40 | {'\0', false, [ 41 | {'a', true, [{'b', true, []}]}, 42 | {'c', false, [{'c', true, []}]} 43 | ]} 44 | */ 45 | 46 | impl Trie { 47 | pub fn new(strs: &Vec<&str>) -> Trie { 48 | Trie::build(strs, '\0') 49 | } 50 | 51 | fn build(strs: &Vec<&str>, chr: char) -> Trie { 52 | let fc = strs.iter().filter_map(|s| s.chars().next()) 53 | .collect::>(); 54 | Trie { 55 | chr, 56 | has: strs.iter().filter(|s| s.len() == 0).count() > 0, 57 | children: 58 | fc.into_iter().map(|c| { 59 | Trie::build( 60 | &strs.iter().filter(|s| s.chars().next().unwrap() == c). 61 | map(|s| 62 | if s.len() > 1 { &s[1..] } 63 | else { "" }).collect::>(), c) 64 | }).collect::>() 65 | } 66 | } 67 | 68 | pub fn contains(&self, s: &str) -> bool { 69 | if s.len() == 0 { return self.has; } 70 | let chr = s.chars().next().unwrap(); 71 | for child in self.children.iter() { 72 | if child.chr == chr { 73 | return child.contains(&s[1..]); 74 | } 75 | } 76 | return false; 77 | } 78 | } 79 | 80 | #[cfg(test)] 81 | mod test { 82 | use super::*; 83 | 84 | #[test] 85 | fn test_event() { 86 | let event1 = Event::new("Pac-12 Championship".into(), 12, 1, 2017); 87 | let mut event2 = Event::new("Group Project Meeting".into(), 12, 1, 2017); 88 | assert!(event1.has_conflict(&event2)); 89 | 90 | event2.update_event(); 91 | assert_eq!(event2.day, 2); 92 | } 93 | 94 | #[test] 95 | fn test_trie() { 96 | let trie = Trie::new(&vec!["b", "ab"]); 97 | assert_eq!(trie.contains("ab"), true); 98 | assert_eq!(trie.contains("ac"), false); 99 | assert_eq!(trie.contains("a"), false); 100 | assert_eq!(trie.contains("b"), true); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /lab2/src/main.rs: -------------------------------------------------------------------------------- 1 | // mod part1; 2 | // mod part2; 3 | 4 | fn main() {} 5 | -------------------------------------------------------------------------------- /lab2/src/part1.rs: -------------------------------------------------------------------------------- 1 | use std::{ptr, io}; 2 | 3 | fn password_checker(s: String) { 4 | let mut guesses = 0; 5 | loop { 6 | let mut buffer = String::new(); 7 | if let Err(_) = io::stdin().read_line(&mut buffer) { return; } 8 | if buffer.len() == 0 { return; } 9 | 10 | // If the buffer is "Password1" then print "You guessed it!" and return, 11 | // otherwise print the number of guesses so far. 12 | unimplemented!() 13 | } 14 | } 15 | 16 | fn add_n(v: Vec, n: i32) -> Vec { 17 | unimplemented!() 18 | } 19 | 20 | fn add_n_inplace(v: &mut Vec, n: i32) { 21 | unimplemented!() 22 | } 23 | 24 | fn reverse_clone(v: &mut Vec) { 25 | let n = v.len(); 26 | for i in 0..n/2 { 27 | let x: T = v[i].clone(); 28 | v[i] = v[n-i-1].clone(); 29 | v[n-i-1] = x; 30 | } 31 | } 32 | 33 | fn reverse(v: &mut Vec) { 34 | let n = v.len(); 35 | for i in 0..n/2 { 36 | unimplemented!() 37 | } 38 | } 39 | 40 | #[cfg(test)] 41 | mod test { 42 | use super::*; 43 | 44 | #[test] 45 | fn test_password_checker() { 46 | //password_checker(String::from("Password1")); 47 | } 48 | 49 | #[test] 50 | fn test_add_n() { 51 | assert_eq!(add_n(vec![1], 2).pop().unwrap(), 3); 52 | } 53 | 54 | #[test] 55 | fn test_add_n_inplace() { 56 | let mut v = vec![1]; 57 | add_n_inplace(&mut v, 2); 58 | assert_eq!(v[0], 3); 59 | } 60 | 61 | #[test] 62 | fn test_reverse() { 63 | let mut v = vec![1, 2, 3]; 64 | reverse(&mut v); 65 | assert_eq!(v[0], 3); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /lab2/src/part2.rs: -------------------------------------------------------------------------------- 1 | use std::collections::{HashMap, HashSet}; 2 | 3 | struct Event { 4 | pub name: String, 5 | pub month: u8, 6 | pub day: u8, 7 | pub year: u32 8 | } 9 | 10 | /* You need to complete two functions in this implementation 11 | * has_conflict() and update_event(). Note that the argument(s) and 12 | * return values for these two functions are missing below. 13 | * You can refer to tests for more information. */ 14 | impl Event { 15 | pub fn new(name: String, month: u8, day: u8, year: u32) -> Event { 16 | Event { name, month, day, year } 17 | } 18 | 19 | /* This function checks if two events are one the same date */ 20 | pub fn has_conflict() { 21 | // Your code! 22 | } 23 | 24 | /* This function shifts the date of an event by one day. 25 | * You can assume that the date is not on the last day 26 | * of a month */ 27 | pub fn update_event() { 28 | // Your code! 29 | } 30 | } 31 | 32 | #[derive(Debug, Clone, Eq, PartialEq)] 33 | struct Trie { 34 | chr: char, 35 | has: bool, 36 | children: Vec, 37 | } 38 | 39 | /* ["a", "cc", "ab"] => 40 | {'\0', false, [ 41 | {'a', true, [{'b', true, []}]}, 42 | {'c', false, [{'c', true, []}]} 43 | ]} 44 | */ 45 | 46 | impl Trie { 47 | pub fn new(strs: &Vec<&str>) -> Trie { 48 | Trie::build(strs, '\0') 49 | } 50 | 51 | fn build(strs: &Vec<&str>, chr: char) -> Trie { 52 | unimplemented!() 53 | } 54 | 55 | pub fn contains(&self, s: &str) -> bool { 56 | unimplemented!() 57 | } 58 | } 59 | 60 | #[cfg(test)] 61 | mod test { 62 | use super::*; 63 | 64 | #[test] 65 | fn test_event() { 66 | let event1 = Event::new("Pac-12 Championship".into(), 12, 1, 2017); 67 | let mut event2 = Event::new("Group Project Meeting".into(), 12, 1, 2017); 68 | assert!(event1.has_conflict(&event2)); 69 | 70 | event2.update_event(); 71 | assert_eq!(event2.day, 2); 72 | } 73 | 74 | #[test] 75 | fn test_trie() { 76 | let trie = Trie::new(&vec!["b", "ab"]); 77 | assert_eq!(trie.contains("ab"), true); 78 | assert_eq!(trie.contains("ac"), false); 79 | assert_eq!(trie.contains("a"), false); 80 | assert_eq!(trie.contains("b"), true); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /lab3/part1/serialize.lua: -------------------------------------------------------------------------------- 1 | -- parens("(a)((b)(c))(d)") == {"a", "(b)(c)", "d"} 2 | local function parse_parens(s) 3 | local idx = 1 4 | local parts = {} 5 | while true do 6 | local start_idx = idx 7 | local ctr = 0 8 | repeat 9 | if idx > s:len() then 10 | return parts 11 | end 12 | if s:sub(idx, idx) == "(" then 13 | ctr = ctr + 1 14 | elseif s:sub(idx, idx) == ")" then 15 | ctr = ctr - 1 16 | end 17 | idx = idx + 1 18 | until ctr == 0 19 | table.insert(parts, s:sub(start_idx+1, idx-2)) 20 | end 21 | end 22 | 23 | local function serialize(t) 24 | -- TODO 25 | end 26 | 27 | local function deserialize(s) 28 | -- TODO 29 | end 30 | 31 | local values = { 32 | 0, "Hello", "foo bar", {"a", " ", "b"}, {5, 10, 20}, {x = 1, y = "yes"}, {a = {b = {c = 1}}} 33 | } 34 | 35 | function table.equals(t1, t2) 36 | for k, _ in pairs(t1) do 37 | local b 38 | if type(t1[k]) == "table" then 39 | b = table.equals(t1[k], t2[k]) 40 | else 41 | b = t1[k] == t2[k] 42 | end 43 | if not b then return false end 44 | end 45 | return true 46 | end 47 | 48 | for _, value in ipairs(values) do 49 | local value2 = deserialize(serialize(value)) 50 | if type(value) == "table" then assert(table.equals(value, value2)) 51 | else assert(value == value2) end 52 | end 53 | -------------------------------------------------------------------------------- /lab3/part2/metatables.lua: -------------------------------------------------------------------------------- 1 | local function guard(t, keys) 2 | -- TODO 3 | end 4 | 5 | local t = {d = 0} 6 | guard(t, {"a", "b"}) 7 | assert(pcall(function() t.a = 0 end)) 8 | assert(pcall(function() t.b = 0 end)) 9 | assert(not pcall(function() t.c = 0 end)) 10 | assert(pcall(function() t.d = 1 end)) 11 | 12 | 13 | local function multilink(t, parents) 14 | -- TODO 15 | end 16 | 17 | local t = {a = 0} 18 | multilink(t, {{x = 1}, {x = 2, y = 2}, {z = 3}}) 19 | assert(t.a == 0) 20 | assert(t.x == 1) 21 | assert(t.y == 2) 22 | assert(t.z == 3) 23 | -------------------------------------------------------------------------------- /lab3/part3/Makefile: -------------------------------------------------------------------------------- 1 | LFLAGS=$(shell pkg-config --libs lua5.3) 2 | LUA=lua5.3 3 | 4 | default: stringmatch.so 5 | 6 | %.so: %.rs 7 | rustc -O $< --crate-type dylib -o $@ $(CFLAGS) $(LFLAGS) 8 | -------------------------------------------------------------------------------- /lab3/part3/match_test.lua: -------------------------------------------------------------------------------- 1 | local stringmatch = require "stringmatch" 2 | 3 | assert(stringmatch.match("abc", "a") == 1) 4 | assert(stringmatch.match("aaa", "a") == 3) 5 | assert(stringmatch.match("abc", "d") == 0) 6 | assert(stringmatch.match("hello world", "world") == 1) 7 | -------------------------------------------------------------------------------- /lab3/part3/stringmatch.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code, non_camel_case_types, non_snake_case, non_upper_case_globals)] 2 | mod lauxlib; 3 | 4 | use lauxlib::*; 5 | use std::ffi::{CString, CStr}; 6 | use std::os::raw::{c_char, c_int}; 7 | use std::ptr; 8 | 9 | unsafe fn lua_pushcfunction(L: *mut lua_State, f: lua_CFunction) { 10 | lua_pushcclosure(L, f, 0); 11 | } 12 | 13 | unsafe fn luaL_checkstring(L: *mut lua_State, n: c_int) -> *const c_char { 14 | luaL_checklstring(L, n, ptr::null::() as *mut usize) 15 | } 16 | 17 | fn cstr>(s: T) -> *const c_char { 18 | CString::new(s.into()).unwrap().into_raw() 19 | } 20 | 21 | unsafe extern "C" fn stringmatch(L: *mut lua_State) -> c_int { 22 | unimplemented!() 23 | } 24 | 25 | #[no_mangle] 26 | pub unsafe extern "C" fn luaopen_stringmatch(L: *mut lua_State) -> isize { 27 | lua_createtable(L, 1, 0); 28 | lua_pushstring(L, cstr("match")); 29 | lua_pushcfunction(L, Some(stringmatch)); 30 | lua_settable(L, -3); 31 | return 1; 32 | } 33 | -------------------------------------------------------------------------------- /lab3/solution/part1/serialize.lua: -------------------------------------------------------------------------------- 1 | -- parens("(a)((b)(c))(d)") == {"a", "(b)(c)", "d"} 2 | local function parse_parens(s) 3 | local idx = 1 4 | local parts = {} 5 | while true do 6 | local start_idx = idx 7 | local ctr = 0 8 | repeat 9 | if idx > s:len() then 10 | return parts 11 | end 12 | if s:sub(idx, idx) == "(" then 13 | ctr = ctr + 1 14 | elseif s:sub(idx, idx) == ")" then 15 | ctr = ctr - 1 16 | end 17 | idx = idx + 1 18 | until ctr == 0 19 | table.insert(parts, s:sub(start_idx+1, idx-2)) 20 | end 21 | end 22 | 23 | local function serialize(t) 24 | local ty = type(t) 25 | local s 26 | if ty == "number" then 27 | s = tostring(t) 28 | elseif ty == "string" then 29 | s = t 30 | elseif ty == "table" then 31 | s = "" 32 | for k, v in pairs(t) do 33 | s = s .. string.format("((%s)(%s))", serialize(k), serialize(v)) 34 | end 35 | else 36 | return nil 37 | end 38 | 39 | return string.format("(%s)(%s)", ty, s) 40 | end 41 | 42 | local function deserialize(s) 43 | local parts = parse_parens(s) 44 | local ty = parts[1] 45 | local val = parts[2] 46 | if ty == "number" then 47 | return tonumber(val) 48 | elseif ty == "string" then 49 | return val 50 | elseif ty == "table" then 51 | local t = {} 52 | for _, pair in pairs(parse_parens(val)) do 53 | local parts = parse_parens(pair) 54 | local k = deserialize(parts[1]) 55 | local v = deserialize(parts[2]) 56 | t[k] = v 57 | end 58 | return t 59 | else 60 | print("Invalid type", ty) 61 | return nil 62 | end 63 | end 64 | 65 | local values = { 66 | 0, "Hello", "foo bar", {"a", " ", "b"}, {5, 10, 20}, {x = 1, y = "yes"}, {a = {b = {c = 1}}} 67 | } 68 | 69 | function table.equals(t1, t2) 70 | for k, _ in pairs(t1) do 71 | local b 72 | if type(t1[k]) == "table" then 73 | b = table.equals(t1[k], t2[k]) 74 | else 75 | b = t1[k] == t2[k] 76 | end 77 | if not b then return false end 78 | end 79 | return true 80 | end 81 | 82 | for _, value in ipairs(values) do 83 | local value2 = deserialize(serialize(value)) 84 | if type(value) == "table" then assert(table.equals(value, value2)) 85 | else assert(value == value2) end 86 | end 87 | -------------------------------------------------------------------------------- /lab3/solution/part2/metatables.lua: -------------------------------------------------------------------------------- 1 | local function guard(t, keys) 2 | setmetatable(t, {__newindex = function(t, k, v) 3 | local contains = false 4 | for _, k2 in ipairs(keys) do 5 | if k == k2 then contains = true end 6 | end 7 | 8 | if contains then rawset(t, k, v) 9 | else error("Invalid key " .. k) end 10 | end}) 11 | end 12 | 13 | local t = {d = 0} 14 | guard(t, {"a", "b"}) 15 | assert(pcall(function() t.a = 0 end)) 16 | assert(pcall(function() t.b = 0 end)) 17 | assert(not pcall(function() t.c = 0 end)) 18 | assert(pcall(function() t.d = 1 end)) 19 | 20 | 21 | local function multilink(t, parents) 22 | setmetatable(t, {__index = function(t, k) 23 | for _, t2 in ipairs(parents) do 24 | if t2[k] ~= nil then 25 | return t2[k] 26 | end 27 | end 28 | end}) 29 | end 30 | 31 | local t = {a = 0} 32 | multilink(t, {{x = 1}, {x = 2, y = 2}, {z = 3}}) 33 | assert(t.a == 0) 34 | assert(t.x == 1) 35 | assert(t.y == 2) 36 | assert(t.z == 3) 37 | -------------------------------------------------------------------------------- /lab3/solution/part3/Makefile: -------------------------------------------------------------------------------- 1 | LFLAGS=$(shell pkg-config --libs lua5.3) 2 | LUA=lua5.3 3 | 4 | default: stringmatch.so 5 | 6 | %.so: %.rs 7 | rustc -O $< --crate-type dylib -o $@ $(CFLAGS) $(LFLAGS) 8 | -------------------------------------------------------------------------------- /lab3/solution/part3/match_test.lua: -------------------------------------------------------------------------------- 1 | local stringmatch = require "stringmatch" 2 | 3 | assert(stringmatch.match("abc", "a") == 1) 4 | assert(stringmatch.match("aaa", "a") == 3) 5 | assert(stringmatch.match("abc", "d") == 0) 6 | assert(stringmatch.match("hello world", "world") == 1) 7 | -------------------------------------------------------------------------------- /lab3/solution/part3/stringmatch.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code, non_camel_case_types, non_snake_case, non_upper_case_globals)] 2 | mod lauxlib; 3 | 4 | use lauxlib::*; 5 | use std::ffi::{CString, CStr}; 6 | use std::os::raw::{c_char, c_int}; 7 | use std::ptr; 8 | 9 | unsafe fn lua_pushcfunction(L: *mut lua_State, f: lua_CFunction) { 10 | lua_pushcclosure(L, f, 0); 11 | } 12 | 13 | unsafe fn luaL_checkstring(L: *mut lua_State, n: c_int) -> *const c_char { 14 | luaL_checklstring(L, n, ptr::null::() as *mut usize) 15 | } 16 | 17 | fn cstr>(s: T) -> *const c_char { 18 | CString::new(s.into()).unwrap().into_raw() 19 | } 20 | 21 | unsafe extern "C" fn stringmatch(L: *mut lua_State) -> c_int { 22 | let string = CStr::from_ptr(luaL_checkstring(L, 1)).to_str().unwrap(); 23 | let pattern = CStr::from_ptr(luaL_checkstring(L, 2)).to_str().unwrap(); 24 | lua_pushnumber(L, string.matches(pattern).count() as f64); 25 | return 1; 26 | } 27 | 28 | #[no_mangle] 29 | pub unsafe extern "C" fn luaopen_stringmatch(L: *mut lua_State) -> isize { 30 | lua_createtable(L, 1, 0); 31 | lua_pushstring(L, cstr("match")); 32 | lua_pushcfunction(L, Some(stringmatch)); 33 | lua_settable(L, -3); 34 | return 1; 35 | } 36 | --------------------------------------------------------------------------------