         pre   = nillify(pre)
 
         if nil?(minor) or (nil?(patch) and not approximate?) do
-          throw :invalid_version
+          :error
         else
           major = binary_to_integer(major)
           minor = binary_to_integer(minor)
           patch = patch && binary_to_integer(patch)
-          pre   = pre && parse_pre(pre) || []
-
-          { major, minor, patch, pre }
+
+          case parse_pre(pre) do
+            { :ok, pre } ->
+              { :ok, { major, minor, patch, pre } }
+            :error ->
+              :error
+          end
         end
       else
-        throw :invalid_version
-      end
-    end
-
-    @spec parse_pre(String.t) :: [String.t | integer]
-    def parse_pre(pre) do
-      String.split(pre, ".") |> Enum.map fn piece ->
-        cond do
-          piece =~ %r/^(0|[1-9][0-9]*)$/ ->
-            binary_to_integer(piece)
-          piece =~ %r/^[0-9]*$/ ->
-            throw :invalid_version
-          true ->
-            piece
-        end
-      end
+        :error
+      end
+    end
+
+    defp parse_pre(nil), do: { :ok, [] }
+    defp parse_pre(pre), do: parse_pre(String.split(pre, "."), [])
+
+    defp parse_pre([piece|t], acc) do
+      cond do
+        piece =~ %r/^(0|[1-9][0-9]*)$/ ->
+          parse_pre(t, [binary_to_integer(piece)|acc])
+        piece =~ %r/^[0-9]*$/ ->
+          :error
+        true ->
+          parse_pre(t, [piece|acc])
+      end
+    end
+
+    defp parse_pre([], acc) do
+      { :ok, Enum.reverse(acc) }
     end
 
     defp valid_requirement?([]), do: false


    defp to_condition(current, [:'||', operator, version | rest]) do
      to_condition({ :orelse, current, to_condition([operator, version]) }, rest)
    end

    defp matchable_to_string({ major, minor, patch, pre }) do

  """
  @spec parse(String.t) :: { :ok, Schema.t } | :error
  def parse(string) when is_binary(string) do
    case Version.Parser.parse_version(string) do
      { :ok, matchable } ->
        { :ok, from_matchable(matchable).source(string).build(get_build(string)) }
     :error ->
       :error
    end
  end

