nebius/SWE-rebench-V2-PRs huggingface dataset:
Repository: pypa/build
Pull request #161 (2020-10-23 23:54:06)

Default to `{srcdir}/dist` for `outdir` if option is omitted
As discussed in #69 and #157, a predictable default is (marginally :) preferable.

FFY00: Please don't use merge commits, rebase on top of master instead.

```
git reset --hard HEAD~1  # to remove the merge commit
git rebase master
```
layday: Rebased.

Patch:
diff --git a/src/build/__main__.py b/src/build/__main__.py
index 3ee1257..e161bf7 100644
--- a/src/build/__main__.py
+++ b/src/build/__main__.py
@@ -95,8 +95,6 @@ def main_parser():  # type: () -> argparse.ArgumentParser
     """
     Constructs the main parser
     """
-    cwd = os.getcwd()
-    out = os.path.join(cwd, 'dist')
     # mypy does not recognize module.__path__
     # https://github.com/python/mypy/issues/1422
     paths = build.__path__  # type: Iterable[Optional[str]]  # type: ignore
@@ -105,8 +103,7 @@ def main_parser():  # type: () -> argparse.ArgumentParser
         'srcdir',
         type=str,
         nargs='?',
-        metavar='sourcedir',
-        default=cwd,
+        default=os.getcwd(),
         help='source directory (defaults to current directory)',
     )
     parser.add_argument(
@@ -127,7 +124,13 @@ def main_parser():  # type: () -> argparse.ArgumentParser
         action='store_true',
         help='build a wheel',
     )
-    parser.add_argument('--outdir', '-o', metavar='dist', type=str, default=out, help='output directory')
+    parser.add_argument(
+        '--outdir',
+        '-o',
+        metavar='dir',
+        type=str,
+        help='output directory (defaults to {{srcdir}}{sep}dist)'.format(sep=os.sep),
+    )
     parser.add_argument(
         '--skip-dependencies',
         '-x',
@@ -193,7 +196,10 @@ def main(cli_args, prog=None):  # type: (List[str], Optional[str]) -> None
     if not distributions:
         distributions = ['sdist', 'wheel']
 
-    build_package(args.srcdir, args.outdir, distributions, config_settings, not args.no_isolation, args.skip_dependencies)
+    # outdir is relative to srcdir only if omitted.
+    outdir = os.path.join(args.srcdir, 'dist') if args.outdir is None else args.outdir
+
+    build_package(args.srcdir, outdir, distributions, config_settings, not args.no_isolation, args.skip_dependencies)
 
 
 def entrypoint():  # type: () -> None


Test patch:
diff --git a/tests/test_main.py b/tests/test_main.py
index 3a00fc8..5492e1e 100644
--- a/tests/test_main.py
+++ b/tests/test_main.py
@@ -41,12 +41,16 @@ out = os.path.join(cwd, 'dist')
         ),
         (
             ['source'],
-            ['source', out, ['sdist', 'wheel'], {}, True, False],
+            ['source', os.path.join('source', 'dist'), ['sdist', 'wheel'], {}, True, False],
         ),
         (
             ['-o', 'out'],
             [cwd, 'out', ['sdist', 'wheel'], {}, True, False],
         ),
+        (
+            ['source', '-o', 'out'],
+            ['source', 'out', ['sdist', 'wheel'], {}, True, False],
+        ),
         (
             ['-x'],
             [cwd, out, ['sdist', 'wheel'], {}, True, True],
Repository: pypa/build
Pull request #252 (2021-03-08 14:30:06)

build: un-nest `chdir` context manager
An OS error in `_working_directory` would have been incorrectly
transformed into a `BuildBackendException`.


Patch:
diff --git a/src/build/__init__.py b/src/build/__init__.py
index 74f2ae1..8f4c74f 100644
--- a/src/build/__init__.py
+++ b/src/build/__init__.py
@@ -233,13 +233,13 @@ class ProjectBuilder(object):
         """
         get_requires = getattr(self._hook, 'get_requires_for_build_{}'.format(distribution))
 
-        try:
-            with _working_directory(self.srcdir):
+        with _working_directory(self.srcdir):
+            try:
                 return set(get_requires(config_settings))
-        except pep517.wrappers.BackendUnavailable:
-            raise BuildException("Backend '{}' is not available.".format(self._backend))
-        except Exception as e:
-            raise BuildBackendException(e)
+            except pep517.wrappers.BackendUnavailable:
+                raise BuildException("Backend '{}' is not available.".format(self._backend))
+            except Exception as e:
+                raise BuildBackendException(e)
 
     def check_dependencies(self, distribution, config_settings=None):
         # type: (str, Optional[ConfigSettings]) -> Set[Tuple[str, ...]]
@@ -299,14 +299,14 @@ class ProjectBuilder(object):
         else:
             os.mkdir(outdir)
 
-        try:
-            with _working_directory(self.srcdir):
+        with _working_directory(self.srcdir):
+            try:
                 basename = callback(outdir, config_settings, **kwargs)  # type: str
                 return os.path.join(outdir, basename)
-        except pep517.wrappers.BackendUnavailable:
-            raise BuildException("Backend '{}' is not available.".format(self._backend))
-        except Exception as exception:
-            raise BuildBackendException(exception)
+            except pep517.wrappers.BackendUnavailable:
+                raise BuildException("Backend '{}' is not available.".format(self._backend))
+            except Exception as exception:
+                raise BuildBackendException(exception)
 
 
 __all__ = (


Test patch:
diff --git a/tests/test_projectbuilder.py b/tests/test_projectbuilder.py
index ae02be5..c83895c 100644
--- a/tests/test_projectbuilder.py
+++ b/tests/test_projectbuilder.py
@@ -243,6 +243,14 @@ def test_working_directory(tmp_dir):
         assert os.path.realpath(os.curdir) == os.path.realpath(tmp_dir)
 
 
+def test_working_directory_exc_is_not_transformed(mocker, test_flit_path, tmp_dir):
+    mocker.patch('build._working_directory', side_effect=OSError)
+
+    builder = build.ProjectBuilder(test_flit_path)
+    with pytest.raises(OSError):
+        builder._call_backend(lambda: None, tmp_dir)
+
+
 def test_build(mocker, test_flit_path, tmp_dir):
     mocker.patch('pep517.wrappers.Pep517HookCaller', autospec=True)
     mocker.patch('build._working_directory', autospec=True)
Repository: pypa/build
Pull request #752 (2024-03-06 16:15:05)

perf: avoid compiling unused bytecode
Compiling bytecode is supposed to make usage more consistent for interaction. But it compiles everything, which isn't required for a single use non-interactive temporary environment. We can potentially save a bit of time this way.

This will need to be skipped for the uv backend in #751, since uv defaults to not compiling bytecode, and instead requires a flag to do so (most recent version). But flags aren't identical anyway.


henryiii: I’ll leave merging this up to @layday so it doesn’t interfere with #751.

Patch:
diff --git a/src/build/env.py b/src/build/env.py
index 348162e..bfbc5d7 100644
--- a/src/build/env.py
+++ b/src/build/env.py
@@ -261,6 +261,7 @@ class _PipBackend(_EnvBackend):
                 'install',
                 '--use-pep517',
                 '--no-warn-script-location',
+                '--no-compile',
                 '-r',
                 os.path.abspath(req_file.name),
             ]


Test patch:
diff --git a/tests/test_env.py b/tests/test_env.py
index 7bfd8c3..7b1fa2e 100644
--- a/tests/test_env.py
+++ b/tests/test_env.py
@@ -197,6 +197,7 @@ def test_default_impl_install_cmd_well_formed(
                 'install',
                 '--use-pep517',
                 '--no-warn-script-location',
+                '--no-compile',
                 '-r',
                 mocker.ANY,
             ]
Repository: pypa/build
Pull request #755 (2024-03-16 12:31:00)

uv: support double verbosity flag
https://github.com/astral-sh/uv/pull/2301


Patch:
diff --git a/pyproject.toml b/pyproject.toml
index 3f671c1..ac2fd03 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -66,12 +66,12 @@ test = [
 typing = [
   "build[uv]",
   "importlib-metadata >= 5.1",
-  "mypy ~= 1.5.0",
+  "mypy ~= 1.9.0",
   "tomli",
   "typing-extensions >= 3.7.4.3",
 ]
 uv = [
-  "uv >= 0.1.15",
+  "uv >= 0.1.18",
 ]
 virtualenv = [
   "virtualenv >= 20.0.35",
diff --git a/src/build/env.py b/src/build/env.py
index 1e7ff1f..e583e68 100644
--- a/src/build/env.py
+++ b/src/build/env.py
@@ -297,8 +297,7 @@ class _UvBackend(_EnvBackend):
     def install_requirements(self, requirements: Collection[str]) -> None:
         cmd = [self._uv_bin, 'pip']
         if _ctx.verbosity > 1:
-            # uv doesn't support doubling up -v unlike pip.
-            cmd += ['-v']
+            cmd += [f'-{"v" * min(2, _ctx.verbosity - 1)}']
         run_subprocess([*cmd, 'install', *requirements], env={**os.environ, 'VIRTUAL_ENV': self._env_path})
 
     @property


Test patch:
diff --git a/tests/test_env.py b/tests/test_env.py
index 7b1fa2e..035457f 100644
--- a/tests/test_env.py
+++ b/tests/test_env.py
@@ -221,7 +221,7 @@ def test_uv_impl_install_cmd_well_formed(
         assert len(install_call.args) == 1
         assert install_call.args[0][1:] == [
             'pip',
-            *(['-v'] if verbosity > 1 else []),
+            *(['-vv' if verbosity > 2 else '-v'] if verbosity > 1 else []),
             'install',
             'some',
             'requirements',
Repository: MiSawa/xq
Pull request #63 (2022-02-23 04:41:49)

Fix update assignment of modulo operator
This PR fixes `%=` operator. Also adds test for all arithmetic assignment operators.
```sh
❯ jq -c '.[] %= 2' <<< '[1,2,3]'
[1,0,1]

❯ xq -c '.[] %= 2' <<< '[1,2,3]'
Error: compile query

Caused by:
    ParseError(UnrecognizedToken(Loc { line: 0, col: 5, byte_idx: 5 }, "Eq", ["\"(\"", "\"+\"", "\"-\"", "\".\"", "\"..\"", "\"[\"", "\"break\"", "\"def\"", "\"false\"", "\"foreach\"", "\"if\"", "\"label\"", "\"null\"", "\"reduce\"", "\"true\"", "\"try\"", "\"{\"", "FieldStr", "Format", "IdentifierNonKeywordStr", "ModuleIdentifierStr", "ModuleVariableStr", "Number", "StringStart", "TryNoCatch", "VariableStr"]))

❯ xq --version
xq 0.2.2-867924f3feb34b21e41363c38603dd7b739c8666
```


Patch:
diff --git a/src/lang/lexer.rs b/src/lang/lexer.rs
index 296241c..2e0ec5b 100644
--- a/src/lang/lexer.rs
+++ b/src/lang/lexer.rs
@@ -430,6 +430,7 @@ lexer! {
         "-=" = Token::MinusEq,
         "*=" = Token::StarEq,
         "/=" = Token::SlashEq,
+        "%=" = Token::PercentEq,
         "//=" = Token::SlashSlashEq,
         "|=" = Token::PipeEq,
 


Test patch:
diff --git a/tests/hand_written/assignments.rs b/tests/hand_written/assignments.rs
index 34cd18a..484d4ec 100644
--- a/tests/hand_written/assignments.rs
+++ b/tests/hand_written/assignments.rs
@@ -26,15 +26,19 @@ test!(
 );
 
 test!(
-    assignment_sub,
+    assignment_arithmetic,
     r#"
-    {a: [0, 1], b: 2} | .["a"].[0] -= 1
+    .[] += 2, .[] -= 2, .[] *= 2, .[] /= 2, .[] %= 2
     "#,
     r#"
-    null
+    [1,2,3]
     "#,
     r#"
-    {"a": [-1, 1], "b": 2}
+    [3,4,5]
+    [-1,0,1]
+    [2,4,6]
+    [0.5,1,1.5]
+    [1,0,1]
     "#
 );
Repository: MiSawa/xq
Pull request #70 (2022-02-26 07:23:24)

Fix indices/1 filter against null
Better or worse, jq evaluates `null | indices(whatever)` to `null`. About test renaming, I didn't aware of the difference between `from_manual` and `hand_written`. Fixed the tests for `indices/1` to appropriate position (related to #36).


Patch:
diff --git a/src/intrinsic/mod.rs b/src/intrinsic/mod.rs
index 9f65092..06b5ce2 100644
--- a/src/intrinsic/mod.rs
+++ b/src/intrinsic/mod.rs
@@ -258,6 +258,7 @@ pub(crate) fn group_by(context: Value) -> Result<Value> {
 
 fn indices(context: Value, s: Value) -> Result<Value> {
     let ret = match (context, s) {
+        (Value::Null, _) => Value::Null,
         (Value::String(lhs), Value::String(rhs)) => Array::from_vec(if rhs.is_empty() {
             vec![]
         } else {


Test patch:
diff --git a/tests/from_manual/functions.rs b/tests/from_manual/functions.rs
index de8529d..c66163c 100644
--- a/tests/from_manual/functions.rs
+++ b/tests/from_manual/functions.rs
@@ -940,19 +940,6 @@ test!(
 test!(
     indices2,
     r#"
-    indices("")
-    "#,
-    r#"
-    "abcde"
-    "#,
-    r#"
-    []
-    "#
-);
-
-test!(
-    indices3,
-    r#"
     indices(1)
     "#,
     r#"
@@ -964,7 +951,7 @@ test!(
 );
 
 test!(
-    indices4,
+    indices3,
     r#"
     indices([1,2])
     "#,
@@ -976,19 +963,6 @@ test!(
     "#
 );
 
-test!(
-    indices5,
-    r#"
-    indices([])
-    "#,
-    r#"
-    [0,1,2,3]
-    "#,
-    r#"
-    []
-    "#
-);
-
 test!(
     index1,
     r#"
diff --git a/tests/hand_written/mod.rs b/tests/hand_written/mod.rs
index 5362c79..b83b16d 100644
--- a/tests/hand_written/mod.rs
+++ b/tests/hand_written/mod.rs
@@ -112,6 +112,19 @@ test!(
     "#
 );
 
+test!(
+    indices_with_empty_string,
+    r#"
+    indices("")
+    "#,
+    r#"
+    "abcde"
+    "#,
+    r#"
+    []
+    "#
+);
+
 test!(
     indices_with_empty_array,
     r#"
@@ -125,6 +138,19 @@ test!(
     "#
 );
 
+test!(
+    indices_against_null,
+    r#"
+    indices(0)
+    "#,
+    r#"
+    null
+    "#,
+    r#"
+    null
+    "#
+);
+
 test!(
     limit_infinite_stream,
     r#"
Repository: MiSawa/xq
Pull request #76 (2022-02-26 10:13:20)

Fix implementation of csv, tsv formats
This PR fixes implementation of csv and tsv formats.


Patch:
diff --git a/src/intrinsic/string.rs b/src/intrinsic/string.rs
index cb1b3c4..a396e2f 100644
--- a/src/intrinsic/string.rs
+++ b/src/intrinsic/string.rs
@@ -5,6 +5,7 @@ use crate::{
     Array, Number, Value,
 };
 use itertools::Itertools;
+use num::Float;
 use num::ToPrimitive;
 use std::{borrow::Cow, rc::Rc};
 
@@ -149,12 +150,17 @@ where
     let mut ret = String::new();
     for entry in entries.iter() {
         match entry {
-            Value::Null => ret.push(delim),
+            Value::Null => {}
             Value::Boolean(v) => ret.push_str(if *v { "true" } else { "false" }),
-            Value::Number(v) => ret.push_str(&format!("{}", v)),
+            Value::Number(v) => {
+                if !v.is_nan() {
+                    ret.push_str(&format!("{}", v))
+                }
+            }
             Value::String(s) => add_string(&mut ret, s),
             v => return Err(QueryExecutionError::InvalidArgType("(c|t)sv", v.clone())),
         }
+        ret.push(delim);
     }
     if !ret.is_empty() {
         ret.pop();
@@ -164,6 +170,7 @@ where
 
 fn csv(value: Value) -> Result<Value> {
     fn append_quoted_string(s: &mut String, v: &str) {
+        s.push('"');
         for c in v.chars() {
             if c == '"' {
                 s.push_str(r#""""#);
@@ -171,6 +178,7 @@ fn csv(value: Value) -> Result<Value> {
                 s.push(c);
             }
         }
+        s.push('"');
     }
     xsv(value, ',', append_quoted_string)
 }


Test patch:
diff --git a/tests/hand_written/mod.rs b/tests/hand_written/mod.rs
index f0188c8..79f10f1 100644
--- a/tests/hand_written/mod.rs
+++ b/tests/hand_written/mod.rs
@@ -45,6 +45,20 @@ test!(
     "#
 );
 
+test!(
+    format_csv_tsv,
+    r#"
+    [1, "foo", null, 2, nan, "foo,\n\"bar\"\tbaz"] | @csv, @tsv
+    "#,
+    r#"
+    null
+    "#,
+    r#"
+    "1,\"foo\",,2,,\"foo,\n\"\"bar\"\"\tbaz\""
+    "1\tfoo\t\t2\t\tfoo,\\n\"bar\"\\tbaz"
+    "#
+);
+
 test!(
     boolean_comparison,
     r#"
Repository: MiSawa/xq
Pull request #79 (2022-02-26 11:57:01)

Fix modulo operator on floating point numbers
The modulo operator of jq truncates lhs/rhs to integers.


Patch:
diff --git a/src/intrinsic/binary.rs b/src/intrinsic/binary.rs
index 879c107..344cdd4 100644
--- a/src/intrinsic/binary.rs
+++ b/src/intrinsic/binary.rs
@@ -1,7 +1,7 @@
 use crate::{
     lang::ast::BinaryArithmeticOp,
     vm::{bytecode::NamedFn1, QueryExecutionError},
-    Value,
+    Number, Value,
 };
 use num::{Float, ToPrimitive, Zero};
 use std::collections::HashSet;
@@ -149,10 +149,11 @@ fn modulo(lhs: Value, rhs: Value) -> Result<Value, QueryExecutionError> {
     use Value::*;
     Ok(match (lhs, rhs) {
         (Number(lhs), Number(rhs)) => {
-            if rhs.is_zero() {
+            let rhs = number_to_i64(rhs);
+            if rhs == 0 {
                 return Err(QueryExecutionError::DivModByZero);
             }
-            Value::number(lhs % rhs)
+            Value::number(number_to_i64(lhs) % rhs)
         }
         (lhs @ (Null | Boolean(_) | Number(_) | String(_) | Array(_) | Object(_)), rhs) => {
             return Err(QueryExecutionError::IncompatibleBinaryOperator(
@@ -161,3 +162,8 @@ fn modulo(lhs: Value, rhs: Value) -> Result<Value, QueryExecutionError> {
         }
     })
 }
+
+fn number_to_i64(n: Number) -> i64 {
+    n.to_i64()
+        .unwrap_or(if n > Zero::zero() { i64::MAX } else { i64::MIN })
+}


Test patch:
diff --git a/tests/hand_written/mod.rs b/tests/hand_written/mod.rs
index b77435a..810971c 100644
--- a/tests/hand_written/mod.rs
+++ b/tests/hand_written/mod.rs
@@ -514,3 +514,21 @@ test!(
     []
     "#
 );
+
+test!(
+    modulo_floating_point_numbers,
+    r#"
+    (3.5, -6.5) % (1.0, -2.5, 8.5)
+    "#,
+    r#"
+    null
+    "#,
+    r#"
+    0
+    0
+    1
+    0
+    3
+    -6
+    "#
+);
Repository: MiSawa/xq
Pull request #92 (2022-02-28 04:16:01)

Fix isfinite, isinfinite on nan
I noticed that `xq -n "nan | isfinite"` prints `false` but this is different from jq.
```sh
❯ jq -nc '0, nan, infinite, -infinite | [isfinite, isinfinite]'
[true,false]
[true,false]
[false,true]
[false,true]

❯ xq -nc '0, nan, infinite, -infinite | [isfinite, isinfinite]'
[true,false]
[false,true] # oops!
[false,true]
[false,true]

❯ xq --version                                                 
xq 0.2.10-cb245914e46e2808bdaea20e415addeda7b36bad
```


Patch:
diff --git a/prelude.jq b/prelude.jq
index 5edbbf3..a0bdc13 100644
--- a/prelude.jq
+++ b/prelude.jq
@@ -5,6 +5,7 @@ def select(f): if f then . else empty end;
 def map(f): [.[] | f];
 def map_values(f): .[] |= f;
 
+def isfinite: isinfinite | not;
 def nulls: select(type == "null");
 def booleans: select(type == "boolean");
 def numbers: select(type == "number");
@@ -16,7 +17,6 @@ def normals: select(isnormal);
 def finites: select(isfinite);
 def values: select(type != "null");
 def scalars: select(type != "array" and type != "object");
-def isinfinite: isfinite | not;
 
 def recurse(f; cond): def r: ., (f | select(cond) | r); r;
 def recurse(f): recurse(f; . != null);
diff --git a/src/intrinsic/math.rs b/src/intrinsic/math.rs
index 31b45d2..2bf6ae9 100644
--- a/src/intrinsic/math.rs
+++ b/src/intrinsic/math.rs
@@ -32,8 +32,8 @@ pub(crate) fn is_normal(v: Number) -> Result<bool> {
     Ok(v.is_normal())
 }
 
-pub(crate) fn is_finite(v: Number) -> Result<bool> {
-    Ok(v.is_finite())
+pub(crate) fn is_infinite(v: Number) -> Result<bool> {
+    Ok(v.is_infinite())
 }
 
 macro_rules! pub_math_fn {
diff --git a/src/intrinsic/mod.rs b/src/intrinsic/mod.rs
index b733cb2..7bacf6b 100644
--- a/src/intrinsic/mod.rs
+++ b/src/intrinsic/mod.rs
@@ -55,7 +55,7 @@ static INTRINSICS0: phf::Map<&'static str, NamedFn0> = phf_map! {
     "infinite" => NamedFn0 { name: "infinite", func: math::infinite },
     "isnan" => as_math_fn!(is_nan),
     "isnormal" => as_math_fn!(is_normal),
-    "isfinite" => as_math_fn!(is_finite),
+    "isinfinite" => as_math_fn!(is_infinite),
     "floor" => as_math_fn!(floor),
     "sqrt" => as_math_fn!(sqrt),
     "sin" => as_math_fn!(sin),


Test patch:
diff --git a/tests/hand_written/math.rs b/tests/hand_written/math.rs
index 095537c..d711114 100644
--- a/tests/hand_written/math.rs
+++ b/tests/hand_written/math.rs
@@ -1,5 +1,21 @@
 use crate::test;
 
+test!(
+    isfinite_isinfinite,
+    r#"
+    0, nan, infinite, -infinite | [isfinite, isinfinite]
+    "#,
+    r#"
+    null
+    "#,
+    r#"
+    [true,false]
+    [true,false]
+    [false,true]
+    [false,true]
+    "#
+);
+
 test!(
     trigonometric_functions,
     r#"
Repository: MiSawa/xq
Pull request #96 (2022-03-03 14:24:43)

Fix join filter on objects
This PR fixes the join filter to support objects.


Patch:
diff --git a/prelude.jq b/prelude.jq
index a0bdc13..5cb7930 100644
--- a/prelude.jq
+++ b/prelude.jq
@@ -84,7 +84,7 @@ def combinations($n): [limit($n; repeat(.))] | combinations;
 def ltrimstr($s): if startswith($s) then .[($s | length):] else . end;
 def rtrimstr($s): if endswith($s) then .[:-($s | length)] else . end;
 
-def join($sep): def stringify: label $out | ((nulls | ("", break $out)), ((booleans, numbers, strings) | (tostring, break $out)), error("Unsupported element \(.) on join")); if length == 0 then "" else reduce (.[1:][] | stringify) as $e (.[0] | stringify; . + $sep + $e) end;
+def join($sep): if length == 0 then "" else reduce .[] as $e (null; (if . == null then "" else . + $sep end) + ($e | if . == null then "" elif type | . == "boolean" or . == "number" or . == "string" then tostring else error("Unsupported element \(.) on join") end)) end;
 def ascii_downcase: explode | map(if . >= 65 and . <= 90 then .+32 end) | implode;
 def ascii_upcase: explode | map(if . >= 97 and . <= 122 then .-32 end) | implode;
 


Test patch:
diff --git a/tests/hand_written/mod.rs b/tests/hand_written/mod.rs
index 51dca18..4bc1ebf 100644
--- a/tests/hand_written/mod.rs
+++ b/tests/hand_written/mod.rs
@@ -166,6 +166,22 @@ test!(
     "#
 );
 
+test!(
+    join,
+    r#"
+    ([], {}, [0,null,false,true,"abc"], {a:0,b:null,c:false,d:true,e:"abc"}) | join(",")
+    "#,
+    r#"
+    null
+    "#,
+    r#"
+    ""
+    ""
+    "0,,false,true,abc"
+    "0,,false,true,abc"
+    "#
+);
+
 test!(
     limit_infinite_stream,
     r#"
Repository: MiSawa/xq
Pull request #127 (2022-03-15 15:48:53)

Fix surrogate pair parsing to support lowercase literal
Ref: https://github.com/MiSawa/xq/pull/126#issuecomment-1068135011


Patch:
diff --git a/src/lang/lexer.rs b/src/lang/lexer.rs
index e27430b..1ac3e49 100644
--- a/src/lang/lexer.rs
+++ b/src/lang/lexer.rs
@@ -550,7 +550,7 @@ lexer! {
         "\\\\" = Token::StringFragment(StringFragment::Char('\\')),
         "\\/" = Token::StringFragment(StringFragment::Char('/')),
         "\\\"" = Token::StringFragment(StringFragment::Char('"')),
-        "\\uD" ['8' '9' 'a' 'b' 'A' 'B'] $hex_digit $hex_digit "\\uD" ['c'-'f' 'C'-'F'] $hex_digit $hex_digit =? |lexer| {
+        "\\u" ['d' 'D'] ['8' '9' 'a' 'b' 'A' 'B'] $hex_digit $hex_digit "\\u" ['d' 'D'] ['c'-'f' 'C'-'F'] $hex_digit $hex_digit =? |lexer| {
             let higher_surrogate = u32::from_str_radix(&lexer.match_()[2..6], 16).unwrap();
             let lower_surrogate = u32::from_str_radix(&lexer.match_()[8..12], 16).unwrap();
             assert!((0xD800..0xDC00).contains(&higher_surrogate));


Test patch:
diff --git a/tests/hand_written/mod.rs b/tests/hand_written/mod.rs
index 0b7d5c8..8f3f856 100644
--- a/tests/hand_written/mod.rs
+++ b/tests/hand_written/mod.rs
@@ -736,12 +736,13 @@ test!(
 test!(
     surrogate_pair,
     r#"
-    "\uD83E\uDD14"
+    "\ud83d\ude04", "\uD83E\uDD14"
     "#,
     r#"
     null
     "#,
     r#"
+    "😄"
     "🤔"
     "#
 );
Repository: MiSawa/xq
Pull request #143 (2022-04-24 02:07:32)

Change indexing string by out of range to emit null
While the current implementation is same as gojq v0.12.7, I changed in the HEAD version to emit `null` for indexing string by out of range. This is more consistent with array indexing and behaviors of other languages; in JavaScript `"abcde"[10]` results in `undefined`, not `""`. What do you think?



Patch:
diff --git a/src/intrinsic/index.rs b/src/intrinsic/index.rs
index ce05450..84559a4 100644
--- a/src/intrinsic/index.rs
+++ b/src/intrinsic/index.rs
@@ -64,7 +64,7 @@ pub(crate) fn index(value: Value, index: Value) -> Result<(Value, PathElement)>
                 Ok((
                     idx.and_then(|i| s.chars().nth(i))
                         .map(|c| Value::string(String::from(c)))
-                        .unwrap_or_else(|| Value::string("".to_string())),
+                        .unwrap_or_else(|| Value::Null),
                     PathElement::Any(index),
                 ))
             }


Test patch:
diff --git a/tests/hand_written/mod.rs b/tests/hand_written/mod.rs
index 2bb30f9..468bf43 100644
--- a/tests/hand_written/mod.rs
+++ b/tests/hand_written/mod.rs
@@ -319,6 +319,22 @@ test!(
     "#
 );
 
+test!(
+    index_string,
+    r#"
+    .[0, 3, 5, -3]
+    "#,
+    r#"
+    "０１２３４"
+    "#,
+    r#"
+    "０"
+    "３"
+    null
+    "２"
+    "#
+);
+
 test!(
     index_array_by_object,
     r#"