Repository: source-academy/js-slang (ts)

Issue:
parse_int function does not match ECMAscript specification
```
parse_int("1",36); // returns 1 intended behavior
parse_int("1",46);
parse_int("uu1",36);
```

```"Error: parseInt expects two arguments a string s, and a positive integer i"``` is thrown while both arguments are as stated in the error. In addition, according to ECMAScript specification, a ```NaN``` is returned for these two cases.

Pull request:
Restrict parse_int radix to [2, 36]
Behaviour now follows ES6 except:

- If either args str or radix is not provided, source error is thrown
- If first arg is not str, source error is thrown
- If second arg is not integer in [2, 36], source error is thrown

Resolves #52.

Patch:
diff --git a/doc/Makefile b/doc/Makefile
index c19b552c..bf9c1f92 100644
--- a/doc/Makefile
+++ b/doc/Makefile
@@ -6,7 +6,7 @@ SPECS = $(SPECSNUMS:%=source_%)
 
 PDFSPECS = $(SPECS:%=%.pdf)
 
-HELPERS = header bnf comments intro names numbers return strings typing objects arrays interpreter lists array_support
+HELPERS = header bnf comments intro names numbers return strings typing objects arrays interpreter lists array_support loops boolean_operators pair_mutators
 
 HELPERSTEX = $(HELPERS:%=source_%.tex)
 
diff --git a/doc/source_1.tex b/doc/source_1.tex
index b4518fea..c7960526 100644
--- a/doc/source_1.tex
+++ b/doc/source_1.tex
@@ -82,6 +82,8 @@
 
 \newpage
 
+\input source_boolean_operators
+
 \input source_return
 
 \input source_names
diff --git a/doc/source_2.tex b/doc/source_2.tex
index 19c06922..0acaef29 100644
--- a/doc/source_2.tex
+++ b/doc/source_2.tex
@@ -92,6 +92,8 @@ Compared to Source \S 1, Source \S 2 has the following changes:
                                                             && \textrm{argument expressions} 
 \end{alignat*}
 
+\input source_boolean_operators
+
 \input source_return
 
 \input source_names
@@ -106,5 +108,8 @@ Compared to Source \S 1, Source \S 2 has the following changes:
 
 \input source_comments
 
+\newpage
+
+\input source_list_library
 
     \end{document}
diff --git a/doc/source_3.tex b/doc/source_3.tex
index 4f898530..c6f295e8 100644
--- a/doc/source_3.tex
+++ b/doc/source_3.tex
@@ -62,7 +62,9 @@ Compared to Source \S 2, Source \S 3 has the following changes:
 &&                       && |   &\quad &&  \textit{block} 
                                                            && \textrm{block statement}\\
 &&                       && |   &\quad &&  \textit{expression} \ \textbf{\texttt{;}}
-                                                           && \textrm{expression statement} \\[1mm] 
+                                                           && \textrm{expression statement} \\
+&&                       && |   &\quad &&  \epsilon
+                                                           && \textrm{empty statement} \\[1mm] 
 && \textit{parameters}   && ::= &\quad &&  \epsilon\ | \  \textit{name} \ 
                                                    (\ \textbf{\texttt{,}} \ \textit{name}\ )\ \ldots
                                                             && \textrm{function parameters}   \\[1mm]
@@ -130,6 +132,10 @@ Compared to Source \S 2, Source \S 3 has the following changes:
 
 \newpage
 
+\input source_boolean_operators
+
+\input source_loops
+
 \input source_return_3
 
 \input source_names
@@ -150,5 +156,8 @@ Compared to Source \S 2, Source \S 3 has the following changes:
 
 \input source_comments
 
+\newpage
+
+\input source_list_library
 
     \end{document}
diff --git a/doc/source_4.tex b/doc/source_4.tex
index d2025855..869d9198 100644
--- a/doc/source_4.tex
+++ b/doc/source_4.tex
@@ -144,6 +144,10 @@ Section ``Interpreter Support'' below.
 
 \newpage
 
+\input source_boolean_operators
+
+\input source_loops
+
 \input source_return_3
 
 \input source_names
@@ -168,5 +172,8 @@ Section ``Interpreter Support'' below.
 
 \input source_comments
 
+\newpage
+
+\input source_list_library
 
     \end{document}
diff --git a/doc/source_array_support.tex b/doc/source_array_support.tex
index 85fbc017..36666d32 100644
--- a/doc/source_array_support.tex
+++ b/doc/source_array_support.tex
@@ -3,7 +3,8 @@
 The following array processing function is supported:
 
 \begin{itemize}
-\item \lstinline{array_length(x)}: Returns the current length of array \lstinline{x}, which is 1 plus the
+\item \lstinline{array_length(x)}: \textit{builtin}, returns
+  the current length of array \lstinline{x}, which is 1 plus the
 highest index \lstinline{i} that has been used so far in an array assignment on \lstinline{x}.
 \end{itemize}
 
diff --git a/doc/source_boolean_operators.tex b/doc/source_boolean_operators.tex
new file mode 100644
index 00000000..1d0b41da
--- /dev/null
+++ b/doc/source_boolean_operators.tex
@@ -0,0 +1,24 @@
+\section*{Binary boolean operators}
+
+\subsection*{Conjunction}
+
+\[
+\textit{expression}_1 \ \textbf{\texttt{\&\&}} \ \textit{expression}_2
+\]
+stands for
+\[
+\textit{expression}_1 \ \textbf{\texttt{?}} \ \textit{expression}_2 \ \textbf{\texttt{:}}\ \textbf{\texttt{false}}
+\]
+
+\subsection*{Disjunction}
+
+\[
+\textit{expression}_1 \ \textbf{\texttt{||}} \ \textit{expression}_2
+\]
+stands for
+\[
+\textit{expression}_1 \ \textbf{\texttt{?}}\ \textbf{\texttt{true}}\  \textbf{\texttt{:}}\ \textit{expression}_2
+\]
+
+
+
diff --git a/doc/source_interpreter.tex b/doc/source_interpreter.tex
index 3ec60cec..19e9be2d 100644
--- a/doc/source_interpreter.tex
+++ b/doc/source_interpreter.tex
@@ -1,24 +1,24 @@
 \section*{Interpreter Support}
 
 \begin{itemize}
-\item \lstinline{is_number(x)}: Returns \lstinline{true} if \lstinline{x} is a number, and 
+\item \lstinline{is_number(x)}: \textit{builtin}, returns \lstinline{true} if \lstinline{x} is a number, and 
 \lstinline{false} otherwise.
-\item \lstinline{is_boolean(x)}: Returns \lstinline{true} if \lstinline{x} is \lstinline{true} or \lstinline{false}, and \lstinline{false} otherwise.
-\item \lstinline{is_string(x)}: Returns \lstinline{true} if \lstinline{x} is a
+\item \lstinline{is_boolean(x)}: \textit{builtin}, returns \lstinline{true} if \lstinline{x} is \lstinline{true} or \lstinline{false}, and \lstinline{false} otherwise.
+\item \lstinline{is_string(x)}: \textit{builtin}, returns \lstinline{true} if \lstinline{x} is a
 string, and \lstinline{false} otherwise.
-\item \lstinline{is_function(x)}: Returns \lstinline{true} if \lstinline{x} is a
+\item \lstinline{is_function(x)}: \textit{builtin}, returns \lstinline{true} if \lstinline{x} is a
 function, and \lstinline{false} otherwise.
-\item \lstinline{is_object(x)}: Returns \lstinline{true} if \lstinline{x} is an
+\item \lstinline{is_object(x)}: \textit{builtin}, returns \lstinline{true} if \lstinline{x} is an
 object, and \lstinline{false} otherwise. Following JavaScript, arrays are considered
 objects.
-\item \lstinline{is_array(x)}: Returns \lstinline{true} if \lstinline{x} is an
+\item \lstinline{is_array(x)}: \textit{builtin}, returns \lstinline{true} if \lstinline{x} is an
 array, and \lstinline{false} otherwise. The empty array \lstinline{[]}, also known
 as the empty list, is an array.
-\item \lstinline{parse(x)}: returns the parse tree that results from parsing
+\item \lstinline{parse(x)}: \textit{builtin}, returns the parse tree that results from parsing
 the string \lstinline{x} as a Source program.
-\item \lstinline{JSON.stringify(x)}: returns a string that represents the given JSON object
+\item \lstinline{JSON.stringify(x)}: \textit{builtin}, returns a string that represents the given JSON object
 \lstinline{x}.
-\item \lstinline{apply_in_underlying_javascript(f, xs)}: calls the function \lstinline{f}
+\item \lstinline{apply_in_underlying_javascript(f, xs)}: \textit{builtin}, calls the function \lstinline{f}
 with arguments \lstinline{xs}. For example:
 \begin{lstlisting}
 function times(x, y) {
diff --git a/doc/source_list_library.tex b/doc/source_list_library.tex
new file mode 100644
index 00000000..e952c0bf
--- /dev/null
+++ b/doc/source_list_library.tex
@@ -0,0 +1,203 @@
+\section*{Appendix: List library}
+
+Those list library functions that are not builtins are pre-declared as follows:
+
+\begin{lstlisting}
+// is_list recurses down the list and checks that it ends with the empty list []
+
+function is_list(xs) {
+    return is_empty_list(xs) || (is_pair(xs) && is_list(tail(xs)));
+}
+
+// equal computes the structural equality 
+// over its arguments
+
+function equal(item1, item2){
+    return (is_pair(item1) && is_pair(item2))
+        || (is_empty_list(item1) && is_empty_list(item2))
+        || item1 === item2;
+}
+
+// returns the length of a given argument list
+// assumes that the argument is a list
+
+function length(xs) {
+    return is_empty_list(xs) 
+	? 0
+        : length(tail(xs));
+}
+
+// map applies first arg f, assumed to be a unary function,
+// to the elements of the second argument, assumed to be a list.
+// f is applied element-by-element: 
+// map(f, [1, [2, []]]) results in [f(1), [f(2), []]]
+
+function map(f, xs) {
+    return (is_empty_list(xs)) 
+        ? []
+        : pair(f(head(xs)), map(f, tail(xs)));
+}
+
+// build_list takes a non-negative integer n as first argument,
+// and a function fun as second argument.
+// build_list returns a list of n elements, that results from 
+// applying fun to the numbers from 0 to n-1.
+
+function build_list(n, fun){
+    function build(i, fun, already_built) {
+	return i < 0
+	    ? already_built
+	    : build(i - 1, fun, pair(fun(i),
+		  		     already_built));
+    }
+    return build(n - 1, fun, []);
+}
+
+// for_each applies first arg fun, assumed to be a unary function,
+// to the elements of the second argument, assumed to be a list.
+// fun is applied element-by-element:
+// for_each(fun, [1, [2, []]]) results in the calls fun(1) and fun(2).
+// for_each returns true.
+
+function for_each(fun, xs) {
+    if (is_empty_list(xs)) {
+	return true;
+    } else {
+        fun(head(xs));
+	return for_each(fun, tail(xs));
+    }
+}
+
+// to_string uses JavaScript's + to turn its argument into a string
+
+function to_string(x) {
+    return x + "";
+}
+
+// list_to_string returns a string that represents the argument list.
+// It applies itself recursively on the elements of the given list.
+// When it encounters a non-list, it applies toString to it.
+
+function list_to_string(xs) {
+    return is_empty_list(xs)
+        ? "[]"
+        : is_pair(xs)
+            ? "[" + list_to_string(head(xs)) + ","+
+                    list_to_string(tail(xs))      + "]"
+            : to_string(xs);
+}
+
+// reverse reverses the argument, assumed to be a list
+
+function reverse(xs) {
+    function rev(original, reversed) {
+	return is_empty_list(original)
+	    ? reversed
+	    : rev(tail(original), 
+	          pair(head(original), reversed));
+    }
+    return rev(xs, []);
+}
+
+// append first argument, assumed to be a list, to the second argument.
+// In the result, the [] at the end of the first argument list
+// is replaced by the second argument, regardless what the second
+// argument consists of.
+
+function append(xs, ys) {
+    return is_empty_list(xs)
+	? ys
+        : pair(head(xs),
+	       append(tail(xs), ys));
+} 
+
+// member looks for a given first-argument element in the 
+// second argument, assumed to be a list. It returns the first 
+// postfix sublist that starts with the given element. It returns [] if the 
+// element does not occur in the list
+
+function member(v, xs){
+    return is_empty_list(xs)
+	? []
+        : (v === head(xs))
+	    ? xs
+	    : member(v, tail(xs));
+}
+
+// removes the first occurrence of a given first-argument element
+// in second-argument, assmed to be a list. Returns the original 
+// list if there is no occurrence.
+
+function remove(v, xs){
+    return is_empty_list(xs)
+	? []
+        : v === head(xs)
+	    ? tail(xs)
+	    : pair(head(xs), 
+		   remove(v, tail(xs)));
+}
+
+// Similar to remove, but removes all instances of v
+// instead of just the first
+
+function remove_all(v, xs) {
+    return is_empty_list(xs)
+	? []
+        : v === head(xs)
+	    ? remove_all(v, tail(xs))
+	    : pair(head(xs), 
+	  	   remove_all(v, tail(xs)));
+}
+
+// filter returns the sublist of elements of the second argument
+// (assumed to be a list), for which the given predicate function
+// returns true.
+
+function filter(pred, xs){
+    return is_empty_list(xs)
+	? xs
+        : pred(head(xs))
+	    ? pair(head(xs),
+		   filter(pred, tail(xs)))
+	    : filter(pred, tail(xs));
+}
+
+// enumerates numbers starting from start, assumed to be a number,
+// using a step size of 1, until the number exceeds end, assumed
+// to be a number
+
+function enum_list(start, end) {
+    return start > end
+	? []
+        : pair(start,
+	       enum_list(start + 1, end));
+}
+
+// Returns the item in xs (assumed to be a list) at index n,
+// assumed to be a non-negative integer.
+// Note: the first item is at position 0
+
+function list_ref(xs, n) {
+    return n === 0
+	? head(xs)
+        : list_ref(tail(xs), n - 1);
+}
+
+// accumulate applies an operation op (assumed to be a binary function)
+// to elements of sequence (assumed to be a list) in a right-to-left order.
+// first apply op to the last element and initial, resulting in r1, then to
+// the  second-last element and r1, resulting in r2, etc, and finally
+// to the first element and r_n-1, where n is the length of the
+// list.
+// accumulate(op, zero, list(1, 2, 3)) results in
+// op(1, op(2, op(3, zero)))
+
+function accumulate(op, initial, sequence) {
+    return is_empty_list(sequence)
+        ? initial
+        : op(head(sequence),
+             accumulate(op, initial, tail(sequence)));
+}
+\end{lstlisting}
+
+
diff --git a/doc/source_lists.tex b/doc/source_lists.tex
index 5f258a27..189d1712 100644
--- a/doc/source_lists.tex
+++ b/doc/source_lists.tex
@@ -3,24 +3,24 @@
 The following list processing functions are supported:
 
 \begin{itemize}
-\item \lstinline{pair(x, y)}: Makes a pair from \lstinline{x} and \lstinline{y}.
-\item \lstinline{is_pair(x)}: Returns \lstinline{true} if \lstinline{x} is a
+\item \lstinline{pair(x, y)}: \textit{builtin}, makes a pair from \lstinline{x} and \lstinline{y}.
+\item \lstinline{is_pair(x)}: \textit{builtin}, returns \lstinline{true} if \lstinline{x} is a
   pair and \lstinline{false} otherwise.
-\item \lstinline{head(x)}: Returns the head (first component) of the pair \lstinline{x}.
-\item \lstinline{tail(x)}: Returns the tail (second component) of the
+\item \lstinline{head(x)}: \textit{builtin}, returns the head (first component) of the pair \lstinline{x}.
+\item \lstinline{tail(x)}: \textit{builtin}, returns the tail (second component) of the
   pair \lstinline{x}.
-\item \lstinline{is_empty_list(xs)}: Returns \lstinline{true} if \lstinline{xs} is the
+\item \lstinline{is_empty_list(xs)}: \textit{builtin}, returns \lstinline{true} if \lstinline{xs} is the
   empty list, and \lstinline{false} otherwise.
 \item \lstinline{is_list(x)}: Returns \lstinline{true} if
   \lstinline{x} is a list as defined in the lectures, and
   \lstinline{false} otherwise. Iterative process; 
 time: $O(n)$, space: $O(1)$, where $n$ is the length of the 
 chain of \lstinline{tail} operations that can be applied to \lstinline{x}.
-\item \lstinline{list(x1, x2,..., xn)}: Returns a list with $n$ elements. The
+\item \lstinline{list(x1, x2,..., xn)}: \textit{builtin}, returns a list with $n$ elements. The
 first element is \lstinline{x1}, the second \lstinline{x2}, etc. Iterative
 process; time: $O(n)$, space: $O(n)$, since the constructed list data structure
 consists of $n$ pairs, each of which takes up a constant amount of space.
-\item \lstinline{draw_list(x)}: Visualizes \lstinline{x} in a separate drawing
+\item \lstinline{draw_list(x)}: \textit{builtin}, visualizes \lstinline{x} in a separate drawing
   area in the Source Academy using a box-and-pointer diagram; time, space:
   $O(n)$, where $n$ is the number of pairs in \lstinline{x}.
 \item \lstinline{equal(x1, x2)}: Returns \lstinline{true} if both
diff --git a/doc/source_loops.tex b/doc/source_loops.tex
new file mode 100644
index 00000000..2e072dad
--- /dev/null
+++ b/doc/source_loops.tex
@@ -0,0 +1,81 @@
+\section*{Loops}
+
+\subsection*{while-loops}
+
+While loops are seen as abbreviations for function applications as follows:
+
+\[
+\textbf{\texttt{while}}\ \textbf{\texttt{(}}\  \textit{expression} \ \textbf{\texttt{)}} \
+\textit{block}
+\]
+stands for
+
+\begin{center}
+  \begin{minipage}{90mm}
+$\textbf{\texttt{function}}$ \lstinline{_body()} $\textbf{\texttt{\{}}\  \textit{block} \ \textbf{\texttt{\}}}$\newline
+\lstinline{_while( () => } $\textit{expression}$ \lstinline{, _body );}
+  \end{minipage}
+\end{center}
+
+where \lstinline{_while} is defined as follows:
+
+\begin{lstlisting}
+function _while(test, body) {
+    if (test()) {
+        body(); 
+        _while(test, body); 
+    } else { 
+        undefined; 
+    }
+}
+\end{lstlisting}
+
+\subsection*{Simple for-loops}
+
+\[\textbf{\texttt{for}}\ \textbf{\texttt{(}} \ 
+                                          \textit{assignment}_1 \textbf{\texttt{;}} 
+\ \textit{expression} \ \textbf{\texttt{;}} \ \textit{assignment}_2 \ \textbf{\texttt{)}} \ 
+                                            \textit{block}
+\]
+stands for
+\begin{center}
+  \begin{minipage}{90mm}
+\begin{lstlisting}
+^$\textrm{\textit{assignment}}_1$^  
+while (^$\textrm{\textit{expression}}$^) {
+    ^$\textrm{\textit{block}}$^
+    ^$\textrm{\textit{assignment}}_2$^
+}
+\end{lstlisting}
+  \end{minipage}
+\end{center}
+
+\subsection*{for-loops with loop control variable}
+
+\[\textbf{\texttt{for}}\ \textbf{\texttt{(}} \ 
+\textbf{\texttt{let}}\ \textit{name}\ \texttt{=}\
+\textit{expression}_1 \textbf{\texttt{;}} 
+\ \textit{expression}_2 \ \textbf{\texttt{;}} \ \textit{assignment} \ \textbf{\texttt{)}} \ 
+                                            \textit{block}
+\]
+stands for
+\begin{center}
+  \begin{minipage}{90mm}
+  \begin{lstlisting}
+{
+    let ^$\textrm{\textit{name}}$^ = ^$\textrm{\textit{expression}}_1$^;
+    for (^$\textrm{\textit{name}}$^ = ^$\textrm{\textit{name}}$^; ^$\textrm{\textit{expression}}_2$^; ^$\textrm{\textit{assignment}}$^) {
+         const _copy_of_name = ^$\textrm{\textit{name}}$^;
+         {
+             const ^$\textrm{\textit{name}}$^ = _copy_of_x;
+             ^$\textrm{\textit{block}}$^
+         }
+    }
+}
+  \end{lstlisting}
+  \end{minipage}
+
+\end{center}
+
+
+
diff --git a/doc/source_names.tex b/doc/source_names.tex
index 3f570173..9308a2c3 100644
--- a/doc/source_names.tex
+++ b/doc/source_names.tex
@@ -23,9 +23,10 @@ Valid names are \verb@x@, \verb@_45@, \verb@$$@ and $\mathtt{\pi}$,
 but always keep in mind that programming is communicating, and therefore the familiarity of the
 audience with the characters used in names is an important aspect of program readability.
 
-The following names can be used, in addition to names that
-are declared using \texttt{\textbf{const}}, \texttt{\textbf{function}} and
-$\texttt{\textbf{=>}}$:
+In addition to names that
+are declared using \texttt{\textbf{const}}, \texttt{\textbf{function}},
+$\texttt{\textbf{=>}}$ (and \texttt{\textbf{let}} in Source \S3 and 4), the following
+names refer to builtin functions and constants:
 \begin{itemize}
 \item \lstinline{math_}$\textit{name}$,
 where $\textit{name}$ is any name specified in the
diff --git a/doc/source_pair_mutators.tex b/doc/source_pair_mutators.tex
index 6f793e78..09c52abc 100644
--- a/doc/source_pair_mutators.tex
+++ b/doc/source_pair_mutators.tex
@@ -3,9 +3,9 @@
 The following pair mutator functions are supported:
 
 \begin{itemize}
-\item \lstinline{set_head(p, x)}: Changes the pair \lstinline{p} such that its head is \lstinline{x}.
+\item \lstinline{set_head(p, x)}: \textit{builtin}, changes the pair \lstinline{p} such that its head is \lstinline{x}.
 Returns \lstinline{undefined}.
-\item \lstinline{set_tail(p, x)}: Changes the pair \lstinline{p} such that its tail is \lstinline{x}.
+\item \lstinline{set_tail(p, x)}: \textit{builtin}, changes the pair \lstinline{p} such that its tail is \lstinline{x}.
 Returns \lstinline{undefined}.
 \end{itemize}
 
diff --git a/doc/source_typing_3.tex b/doc/source_typing_3.tex
new file mode 100644
index 00000000..d3d17775
--- /dev/null
+++ b/doc/source_typing_3.tex
@@ -0,0 +1,46 @@
+
+\section*{Typing}
+
+Expressions evaluate to numbers, boolean values, strings, function objects and arrays. 
+
+Only function values can be applied using the syntax:
+
+\begin{eqnarray*}
+ \textit{expression}    
+                                   & ::=   &  \textit{name}
+                                               \texttt{\textbf{(}}\  \textit{expressions} \
+                                               \texttt{\textbf{)}}\\ 
+\end{eqnarray*}
+
+The following table specifies what arguments Source's operators
+take and what results they return.
+
+\begin{center}
+\begin{tabular}{c|c|c|c}
+operator & argument 1 & argument 2 & result\\ \hline
+\texttt{\textbf{+}} & number   & number     & number\\
+\texttt{\textbf{+}} & string   & any        & string\\
+\texttt{\textbf{+}} & any      & string     & string\\
+\texttt{\textbf{-}} & number   & number     & number\\
+\texttt{\textbf{*}} & number   & number     & number\\
+\texttt{\textbf{/}} & number   & number     & number\\
+\texttt{\textbf{\%}} & number   & number     & number\\
+\texttt{\textbf{===}} & any   & any     & bool\\
+\texttt{\textbf{!==}} & any   & any     & bool\\
+\texttt{\textbf{>}} & number   & number     & bool\\
+\texttt{\textbf{>}} & string   & string     & bool\\
+\texttt{\textbf{<}} & number   & number     & bool\\
+\texttt{\textbf{<}} & string   & string     & bool\\
+\texttt{\textbf{>=}} & number   & number     & bool\\
+\texttt{\textbf{>=}} & string   & string     & bool\\
+\texttt{\textbf{<=}}    & number   & number     & bool\\
+\texttt{\textbf{<=}} & string   & string     & bool\\
+\texttt{\textbf{\&\&}} & bool & bool & bool\\
+\texttt{\textbf{||}}   & bool & bool & bool\\
+\texttt{\textbf{!}}    & bool &      & bool\\
+\texttt{\textbf{-}}    & number &    & number
+\end{tabular}
+\end{center}
+
+Preceding \texttt{\textbf{?}} and following \texttt{\textbf{if}}, Source only allows
+boolean expressions.
diff --git a/doc/source_typing_4.tex b/doc/source_typing_4.tex
new file mode 100644
index 00000000..fd19452b
--- /dev/null
+++ b/doc/source_typing_4.tex
@@ -0,0 +1,46 @@
+
+\section*{Typing}
+
+Expressions evaluate to numbers, boolean values, strings, function objects, arrays and objects.
+
+Only function values can be applied using the syntax:
+
+\begin{eqnarray*}
+ \textit{expression}    
+                                   & ::=   &  \textit{name}
+                                               \texttt{\textbf{(}}\  \textit{expressions} \
+                                               \texttt{\textbf{)}}\\ 
+\end{eqnarray*}
+
+The following table specifies what arguments Source's operators
+take and what results they return.
+
+\begin{center}
+\begin{tabular}{c|c|c|c}
+operator & argument 1 & argument 2 & result\\ \hline
+\texttt{\textbf{+}} & number   & number     & number\\
+\texttt{\textbf{+}} & string   & any        & string\\
+\texttt{\textbf{+}} & any      & string     & string\\
+\texttt{\textbf{-}} & number   & number     & number\\
+\texttt{\textbf{*}} & number   & number     & number\\
+\texttt{\textbf{/}} & number   & number     & number\\
+\texttt{\textbf{\%}} & number   & number     & number\\
+\texttt{\textbf{===}} & any   & any     & bool\\
+\texttt{\textbf{!==}} & any   & any     & bool\\
+\texttt{\textbf{>}} & number   & number     & bool\\
+\texttt{\textbf{>}} & string   & string     & bool\\
+\texttt{\textbf{<}} & number   & number     & bool\\
+\texttt{\textbf{<}} & string   & string     & bool\\
+\texttt{\textbf{>=}} & number   & number     & bool\\
+\texttt{\textbf{>=}} & string   & string     & bool\\
+\texttt{\textbf{<=}}    & number   & number     & bool\\
+\texttt{\textbf{<=}} & string   & string     & bool\\
+\texttt{\textbf{\&\&}} & bool & bool & bool\\
+\texttt{\textbf{||}}   & bool & bool & bool\\
+\texttt{\textbf{!}}    & bool &      & bool\\
+\texttt{\textbf{-}}    & number &    & number
+\end{tabular}
+\end{center}
+
+Preceding \texttt{\textbf{?}} and following \texttt{\textbf{if}}, Source only allows
+boolean expressions.
diff --git a/package.json b/package.json
index 09683ee8..9f97227e 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "js-slang",
-  "version": "0.1.9",
+  "version": "0.1.10",
   "description": "Javascript-based interpreter for slang, written in Typescript",
   "author": {
     "name": "Source Academy",
diff --git a/src/interpreter.ts b/src/interpreter.ts
index 4df480e3..6a76a2a1 100644
--- a/src/interpreter.ts
+++ b/src/interpreter.ts
@@ -175,9 +175,6 @@ export const evaluators: { [nodeType: string]: Evaluator<es.Node> } = {
     }
     return res
   },
-  FunctionExpression: function*(node: es.FunctionExpression, context: Context) {
-    return new Closure(node, currentFrame(context), context)
-  },
   ArrowFunctionExpression: function*(node: es.Function, context: Context) {
     return new ArrowClosure(node, currentFrame(context), context)
   },
diff --git a/src/stdlib/misc.ts b/src/stdlib/misc.ts
index 536864d0..6041dd1e 100644
--- a/src/stdlib/misc.ts
+++ b/src/stdlib/misc.ts
@@ -43,13 +43,20 @@ export function array_length(xs: Value[]) {
 }
 array_length.__SOURCE__ = 'array_length(xs)'
 
-export function parse_int(inputString: string, radix: number) {
-  const parsed = parseInt(inputString, radix)
-  if (inputString && radix && parsed) {
-    // the two arguments are provided, and parsed is not NaN
-    return parsed
+/**
+ * Source version of parseInt. Both arguments are required.
+ *
+ * @param str String representation of the integer to be parsed. Required.
+ * @param radix Base to parse the given `str`. Required.
+ *
+ * An error is thrown if `str` is not of type string, or `radix` is not an
+ * integer within the range 2, 36 inclusive.
+ */
+export function parse_int(str: string, radix: number) {
+  if (typeof(str) === 'string' && typeof(radix) === 'number' && Number.isInteger(radix) && 2 <= radix && radix <= 36) {
+    return parseInt(str, radix)
   } else {
-    throw new Error('parse_int expects two arguments a string s, and a positive integer i')
+    throw new Error('parse_int expects two arguments a string s, and a positive integer i between 2 and 36, inclusive.')
   }
 }
 parse_int.__SOURCE__ = 'parse_int(s, i)'
diff --git a/src/syntaxTypes.ts b/src/syntaxTypes.ts
index 134f3e40..357c7861 100644
--- a/src/syntaxTypes.ts
+++ b/src/syntaxTypes.ts
@@ -11,7 +11,6 @@ const syntaxTypes: { [nodeName: string]: number } = {
   BinaryExpression: 1,
   LogicalExpression: 1,
   ConditionalExpression: 1,
-  FunctionExpression: 1,
   ArrowFunctionExpression: 1,
   Identifier: 1,
   Literal: 1,
@@ -45,7 +44,9 @@ const syntaxTypes: { [nodeName: string]: number } = {
   CatchClause: Infinity,
   DoWhileStatement: Infinity,
   ForInStatement: Infinity,
-  SequenceExpression: Infinity
+  SequenceExpression: Infinity,
+  FunctionExpression: Infinity,
+
 }
 
 export default syntaxTypes


Test patch:
diff --git a/src/__tests__/__snapshots__/disallowed_syntax.ts.snap b/src/__tests__/__snapshots__/disallowed_syntax.ts.snap
index f1d6c96e..9fedeab8 100644
--- a/src/__tests__/__snapshots__/disallowed_syntax.ts.snap
+++ b/src/__tests__/__snapshots__/disallowed_syntax.ts.snap
@@ -8,4 +8,8 @@ exports[`Cannot leave blank expressions in for loops 3`] = `"Line 2: For stateme
 
 exports[`Cannot leave blank expressions in for loops 4`] = `"Line 2: For statement cannot have empty init,test,update expressions."`;
 
+exports[`Cannot use js function expressions 1`] = `"Line 2: Function expressions are not allowed"`;
+
 exports[`Cannot use update expressions 1`] = `"Line 3: Update expressions are not allowed"`;
+
+exports[`DEFINITELY CANNOT use named function declarations as expressions 1`] = `"Line 2: Function expressions are not allowed"`;
diff --git a/src/__tests__/disallowed_syntax.ts b/src/__tests__/disallowed_syntax.ts
index c6260d20..15550c0e 100644
--- a/src/__tests__/disallowed_syntax.ts
+++ b/src/__tests__/disallowed_syntax.ts
@@ -57,3 +57,32 @@ test("Cannot use update expressions", () => {
   });
 });
 
+test("Cannot use js function expressions", () => {
+  const code = `
+  map(function(x) {
+    return x + 1;
+  }, list(1));
+  `;
+  const context = mockContext(3);
+  const promise = runInContext(code, context, { scheduler: "preemptive" });
+  return promise.then(obj => {
+    expect(obj.status).toBe("error");
+    const errors = parseError(context.errors);
+    expect(errors).toMatchSnapshot();
+  });
+});
+
+test("DEFINITELY CANNOT use named function declarations as expressions", () => {
+  const code = `
+  map(function a(x) {
+    return x + 1;
+  }, list(1));
+  `;
+  const context = mockContext(3);
+  const promise = runInContext(code, context, { scheduler: "preemptive" });
+  return promise.then(obj => {
+    expect(obj.status).toBe("error");
+    const errors = parseError(context.errors);
+    expect(errors).toMatchSnapshot();
+  });
+});
diff --git a/src/stdlib/__tests__/__snapshots__/misc.ts.snap b/src/stdlib/__tests__/__snapshots__/misc.ts.snap
new file mode 100644
index 00000000..9dcc40e8
--- /dev/null
+++ b/src/stdlib/__tests__/__snapshots__/misc.ts.snap
@@ -0,0 +1,62 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`parse_int with non-integer arg radix throws error 1`] = `
+Object {
+  "status": "error",
+}
+`;
+
+exports[`parse_int with non-integer arg radix throws error 2`] = `"Line 2: Error: parse_int expects two arguments a string s, and a positive integer i between 2 and 36, inclusive."`;
+
+exports[`parse_int with non-string arg str throws error 1`] = `
+Object {
+  "status": "error",
+}
+`;
+
+exports[`parse_int with non-string arg str throws error 2`] = `"Line 2: Error: parse_int expects two arguments a string s, and a positive integer i between 2 and 36, inclusive."`;
+
+exports[`parse_int with radix outside [2, 36] throws error, radix=1 1`] = `
+Object {
+  "status": "error",
+}
+`;
+
+exports[`parse_int with radix outside [2, 36] throws error, radix=1 2`] = `"Line 2: Error: parse_int expects two arguments a string s, and a positive integer i between 2 and 36, inclusive."`;
+
+exports[`parse_int with radix outside [2, 36] throws error, radix=37 1`] = `
+Object {
+  "status": "error",
+}
+`;
+
+exports[`parse_int with radix outside [2, 36] throws error, radix=37 2`] = `"Line 2: Error: parse_int expects two arguments a string s, and a positive integer i between 2 and 36, inclusive."`;
+
+exports[`parse_int with string arg radix throws error 1`] = `
+Object {
+  "status": "error",
+}
+`;
+
+exports[`parse_int with string arg radix throws error 2`] = `"Line 2: Error: parse_int expects two arguments a string s, and a positive integer i between 2 and 36, inclusive."`;
+
+exports[`parse_int with valid args is ok, but invalid str for radix 1`] = `
+Object {
+  "status": "finished",
+  "value": NaN,
+}
+`;
+
+exports[`parse_int with valid args is ok, radix 2 1`] = `
+Object {
+  "status": "finished",
+  "value": 6485,
+}
+`;
+
+exports[`parse_int with valid args is ok, radix 36 1`] = `
+Object {
+  "status": "finished",
+  "value": 39961,
+}
+`;
diff --git a/src/stdlib/__tests__/misc.ts b/src/stdlib/__tests__/misc.ts
new file mode 100644
index 00000000..496ba5ab
--- /dev/null
+++ b/src/stdlib/__tests__/misc.ts
@@ -0,0 +1,112 @@
+import { mockContext } from "../../mocks/context"
+import { parseError, runInContext } from "../../index"
+import { Finished } from "../../types";
+
+test("parse_int with valid args is ok, radix 2", () => {
+  const program = `
+    parse_int('1100101010101', 2);
+  `
+  const context = mockContext()
+  const promise = runInContext(program, context, { scheduler: "preemptive" })
+  return promise.then(obj => {
+    expect(obj).toMatchSnapshot()
+    expect(obj.status).toBe('finished')
+    expect((obj as Finished).value).toBe(parseInt('1100101010101', 2))
+  })
+})
+
+test("parse_int with valid args is ok, radix 36", () => {
+  const program = `
+    parse_int('uu1', 36);
+  `
+  const context = mockContext()
+  const promise = runInContext(program, context, { scheduler: "preemptive" })
+  return promise.then(obj => {
+    expect(obj).toMatchSnapshot()
+    expect(obj.status).toBe('finished')
+    expect((obj as Finished).value).toBe(parseInt('uu1', 36))
+  })
+})
+
+test("parse_int with valid args is ok, but invalid str for radix", () => {
+  const program = `
+    parse_int('uu1', 2);
+  `
+  const context = mockContext()
+  const promise = runInContext(program, context, { scheduler: "preemptive" })
+  return promise.then(obj => {
+    expect(obj).toMatchSnapshot()
+    expect(obj.status).toBe('finished')
+    expect((obj as Finished).value).toBe(parseInt('uu1', 2))
+  })
+})
+
+test("parse_int with non-string arg str throws error", () => {
+  const program = `
+    parse_int(42, 2);
+  `
+  const context = mockContext()
+  const promise = runInContext(program, context, { scheduler: "preemptive" })
+  return promise.then(obj => {
+    expect(obj).toMatchSnapshot()
+    expect(obj.status).toBe('error')
+    const errors = parseError(context.errors)
+    expect(errors).toMatchSnapshot()
+  })
+})
+
+test("parse_int with non-integer arg radix throws error", () => {
+  const program = `
+    parse_int(42, 2.1);
+  `
+  const context = mockContext()
+  const promise = runInContext(program, context, { scheduler: "preemptive" })
+  return promise.then(obj => {
+    expect(obj).toMatchSnapshot()
+    expect(obj.status).toBe('error')
+    const errors = parseError(context.errors)
+    expect(errors).toMatchSnapshot()
+  })
+})
+
+test("parse_int with radix outside [2, 36] throws error, radix=1", () => {
+  const program = `
+    parse_int('10', 1);
+  `
+  const context = mockContext()
+  const promise = runInContext(program, context, { scheduler: "preemptive" })
+  return promise.then(obj => {
+    expect(obj).toMatchSnapshot()
+    expect(obj.status).toBe('error')
+    const errors = parseError(context.errors)
+    expect(errors).toMatchSnapshot()
+  })
+})
+
+test("parse_int with radix outside [2, 36] throws error, radix=37", () => {
+  const program = `
+    parse_int('10', 37);
+  `
+  const context = mockContext()
+  const promise = runInContext(program, context, { scheduler: "preemptive" })
+  return promise.then(obj => {
+    expect(obj).toMatchSnapshot()
+    expect(obj.status).toBe('error')
+    const errors = parseError(context.errors)
+    expect(errors).toMatchSnapshot()
+  })
+})
+
+test("parse_int with string arg radix throws error", () => {
+  const program = `
+    parse_int(42, '2');
+  `
+  const context = mockContext()
+  const promise = runInContext(program, context, { scheduler: "preemptive" })
+  return promise.then(obj => {
+    expect(obj).toMatchSnapshot()
+    expect(obj.status).toBe('error')
+    const errors = parseError(context.errors)
+    expect(errors).toMatchSnapshot()
+  })
+})