mirror of
https://github.com/stedolan/jq.git
synced 2024-05-11 05:55:39 +00:00
A string interpolation syntax that I don't hate. Also tests.
You can interpolate values into strings using \(this syntax), e.g. "best \("str" + "ing") ever"
This commit is contained in:
24
lexer.l
24
lexer.l
@ -61,45 +61,31 @@
|
||||
}
|
||||
|
||||
|
||||
\"(\\.|[^\\\"])*\" |
|
||||
-?[0-9.]+([eE][+-]?[0-9]+)? {
|
||||
yylval->literal = jv_parse_sized(yytext, yyleng); return LITERAL;
|
||||
}
|
||||
|
||||
\"(\\.|[^\\\"])* {
|
||||
yylval->literal = jv_invalid_with_msg(jv_string("Unterminated string"));
|
||||
return LITERAL;
|
||||
}
|
||||
|
||||
"@(" {
|
||||
"\"" {
|
||||
yy_push_state(IN_QQSTRING, yyscanner);
|
||||
return QQSTRING_START;
|
||||
}
|
||||
|
||||
<IN_QQSTRING>{
|
||||
"%(" {
|
||||
"\\(" {
|
||||
return enter(QQSTRING_INTERP_START, YY_START, yyscanner);
|
||||
}
|
||||
"%"[^(] {
|
||||
return INVALID_CHARACTER;
|
||||
}
|
||||
")" {
|
||||
"\"" {
|
||||
yy_pop_state(yyscanner);
|
||||
return QQSTRING_END;
|
||||
}
|
||||
"\\"[)%] {
|
||||
char text[2] = {yytext[1], 0};
|
||||
yylval->literal = jv_string(text);
|
||||
return QQSTRING_TEXT;
|
||||
}
|
||||
(\\[^u)%]|\\u[a-zA-Z0-9]{0,4})+ {
|
||||
(\\[^u(]|\\u[a-zA-Z0-9]{0,4})+ {
|
||||
/* pass escapes to the json parser */
|
||||
jv escapes = jv_string_fmt("\"%.*s\"", yyleng, yytext);
|
||||
yylval->literal = jv_parse_sized(jv_string_value(escapes), jv_string_length(jv_copy(escapes)));
|
||||
jv_free(escapes);
|
||||
return QQSTRING_TEXT;
|
||||
}
|
||||
[^\\)%]+ {
|
||||
[^\\\"]+ {
|
||||
yylval->literal = jv_string_sized(yytext, yyleng);
|
||||
return QQSTRING_TEXT;
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ OP(INSERT, NONE, 4, 2)
|
||||
OP(ASSIGN, VARIABLE, 3, 0)
|
||||
|
||||
OP(CALL_BUILTIN_1_1, CFUNC, 1, 1)
|
||||
OP(CALL_BUILTIN_2_1, CFUNC, 2, 1)
|
||||
OP(CALL_BUILTIN_3_1, CFUNC, 3, 1)
|
||||
|
||||
OP(CALL_1_1, UFUNC, 1, 1)
|
||||
|
18
parser.y
18
parser.y
@ -81,7 +81,7 @@
|
||||
%left '*' '/'
|
||||
|
||||
|
||||
%type <blk> Exp Term MkDict MkDictPair ExpD ElseBody QQString FuncDef FuncDefs
|
||||
%type <blk> Exp Term MkDict MkDictPair ExpD ElseBody QQString FuncDef FuncDefs String
|
||||
%{
|
||||
#include "lexer.gen.h"
|
||||
#define FAIL(loc, msg) \
|
||||
@ -295,14 +295,19 @@ Exp ">=" Exp {
|
||||
$$ = gen_binop($1, $3, GREATEREQ);
|
||||
} |
|
||||
|
||||
QQSTRING_START QQString QQSTRING_END {
|
||||
$$ = $2;
|
||||
String {
|
||||
$$ = $1;
|
||||
} |
|
||||
|
||||
Term {
|
||||
$$ = $1;
|
||||
}
|
||||
|
||||
String:
|
||||
QQSTRING_START QQString QQSTRING_END {
|
||||
$$ = $2;
|
||||
}
|
||||
|
||||
FuncDef:
|
||||
"def" IDENT ':' Exp ';' {
|
||||
block body = block_join($4, gen_op_simple(RET));
|
||||
@ -416,11 +421,8 @@ MkDictPair
|
||||
: IDENT ':' ExpD {
|
||||
$$ = gen_dictpair(gen_op_const(LOADK, $1), $3);
|
||||
}
|
||||
| LITERAL ':' ExpD {
|
||||
if (jv_get_kind($1) != JV_KIND_STRING) {
|
||||
FAIL(@1, "Object keys must be strings");
|
||||
}
|
||||
$$ = gen_dictpair(gen_op_const(LOADK, $1), $3);
|
||||
| String ':' ExpD {
|
||||
$$ = gen_dictpair($1, $3);
|
||||
}
|
||||
| IDENT {
|
||||
$$ = gen_dictpair(gen_op_const(LOADK, jv_copy($1)),
|
||||
|
14
testdata
14
testdata
@ -31,7 +31,19 @@ null
|
||||
null
|
||||
[]
|
||||
|
||||
# FIXME: string literals
|
||||
# We test escapes by matching them against Unicode codepoints
|
||||
# FIXME: more tests needed for weird unicode stuff (e.g. utf16 pairs)
|
||||
"Aa\r\n\t\b\f\u03bc"
|
||||
null
|
||||
"Aa\u000d\u000a\u0009\u0008\u000c\u03bc"
|
||||
|
||||
.
|
||||
"Aa\r\n\t\b\f\u03bc"
|
||||
"Aa\u000d\u000a\u0009\u0008\u000c\u03bc"
|
||||
|
||||
"inter\("pol" + "ation")"
|
||||
null
|
||||
"interpolation"
|
||||
|
||||
#
|
||||
# Dictionary construction syntax
|
||||
|
Reference in New Issue
Block a user