Merge pull request #20708 from github/tausbn/python-add-support-for-template-string-literals

Python: Add support for template string literals
This commit is contained in:
Taus
2026-01-06 14:33:51 +01:00
committed by GitHub
27 changed files with 67414 additions and 60332 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,21 @@
// We must wrap the DB types, as these cannot appear in argument lists
class Expr_ extends @py_expr {
string toString() { result = "Expr" }
}
class ExprParent_ extends @py_expr_parent {
string toString() { result = "ExprList" }
}
query predicate py_exprs_without_template_strings(Expr_ id, int kind, ExprParent_ parent, int idx) {
py_exprs(id, kind, parent, idx) and
// From the dbscheme:
//
// case @py_expr.kind of
// ...
// | 39 = @py_SpecialOperation
// | 40 = @py_TemplateString
// | 41 = @py_JoinedTemplateString
// | 42 = @py_TemplateStringPart;
not kind in [40, 41, 42]
}

View File

@@ -0,0 +1,4 @@
description: Remove support for template string literals
compatibility: backwards
py_TemplateString_lists.rel: delete
py_exprs.rel: run py_exprs.qlo py_exprs_without_template_strings

View File

@@ -56,6 +56,15 @@ class StringPart(AstBase):
self.text = text
self.s = s
class TemplateStringPart(AstBase):
'''A string constituent of a template string literal'''
__slots__ = "text", "s",
def __init__(self, text, s):
self.text = text
self.s = s
class alias(AstBase):
__slots__ = "value", "asname",
@@ -356,6 +365,19 @@ class JoinedStr(expr):
def __init__(self, values):
self.values = values
class TemplateString(expr):
__slots__ = "prefix", "values",
def __init__(self, prefix, values):
self.prefix = prefix
self.values = values
class JoinedTemplateString(expr):
__slots__ = "strings",
def __init__(self, strings):
self.strings = strings
class Lambda(expr):
__slots__ = "args", "inner_scope",

View File

@@ -186,12 +186,20 @@ FormattedStringLiteral.set_name("Fstring")
FormattedValue = ClassNode("FormattedValue", expr, descriptive_name='formatted value')
AnnAssign = ClassNode("AnnAssign", stmt, descriptive_name='annotated assignment')
AssignExpr = ClassNode('AssignExpr', expr, "assignment expression")
SpecialOperation = ClassNode('SpecialOperation', expr, "special operation")
TemplateString = ClassNode('TemplateString', expr, 'template string literal')
template_string_list = ListNode(TemplateString)
JoinedTemplateString = ClassNode("JoinedTemplateString", expr, descriptive_name='joined template string')
TemplateStringPart = ClassNode('TemplateStringPart', expr, "string part of a template string")
type_parameter = ClassNode('type_parameter', descriptive_name='type parameter')
type_parameter.field('location', location)
type_parameter_list = ListNode(type_parameter)
@@ -435,6 +443,9 @@ Subscript.field('value', expr)
Subscript.field('index', expr)
Subscript.field('ctx', expr_context, 'context')
TemplateString.field('prefix', string, 'prefix')
TemplateString.field('values', expr_list, 'values')
Try.field('body', stmt_list)
Try.field('orelse', stmt_list, 'else block')
Try.field('handlers', stmt_list, 'exception handlers')
@@ -484,10 +495,15 @@ PlaceHolder.field('ctx', expr_context, 'context')
StringPart.field('text', string)
StringPart.field('location', location)
TemplateStringPart.field('text', string)
Await.field('value', expr, 'expression waited upon')
FormattedStringLiteral.field('values', expr_list)
JoinedTemplateString.field('strings', template_string_list)
FormattedValue.field('value', expr, "expression to be formatted")
FormattedValue.field('conversion', string, 'type conversion')
FormattedValue.field('format_spec', FormattedStringLiteral, 'format specifier')

View File

@@ -273,6 +273,8 @@ list_fields = {
ast.Print: ("values",),
ast.Set: ("elts",),
ast.Str: ("implicitly_concatenated_parts",),
ast.TemplateString: ("values",),
ast.JoinedTemplateString: ("strings",),
ast.TypeAlias: ("type_parameters",),
ast.Try: ("body", "handlers", "orelse", "finalbody"),
ast.Tuple: ("elts",),

View File

@@ -10,7 +10,7 @@ from io import BytesIO
#Semantic version of extractor.
#Update this if any changes are made
VERSION = "7.1.6"
VERSION = "7.1.7"
PY_EXTENSIONS = ".py", ".pyw"

View File

@@ -0,0 +1,194 @@
Module: [1, 0] - [18, 0]
body: [
Assign: [1, 0] - [1, 14]
targets: [
Name: [1, 0] - [1, 4]
variable: Variable('name', None)
ctx: Store
]
value:
Str: [1, 7] - [1, 14]
s: 'World'
prefix: '"'
implicitly_concatenated_parts: None
Assign: [2, 0] - [2, 15]
targets: [
Name: [2, 0] - [2, 5]
variable: Variable('value', None)
ctx: Store
]
value:
Num: [2, 8] - [2, 15]
n: 42.5678
text: '42.5678'
Assign: [3, 0] - [3, 15]
targets: [
Name: [3, 0] - [3, 5]
variable: Variable('first', None)
ctx: Store
]
value:
Str: [3, 8] - [3, 15]
s: 'first'
prefix: '"'
implicitly_concatenated_parts: None
Assign: [4, 0] - [4, 17]
targets: [
Name: [4, 0] - [4, 6]
variable: Variable('second', None)
ctx: Store
]
value:
Str: [4, 9] - [4, 17]
s: 'second'
prefix: '"'
implicitly_concatenated_parts: None
If: [6, 0] - [6, 5]
test:
Num: [6, 3] - [6, 4]
n: 1
text: '1'
body: [
Expr: [7, 4] - [7, 7]
value:
TemplateString: [7, 4] - [7, 7]
prefix: 't"'
values: []
]
orelse: None
If: [8, 0] - [8, 5]
test:
Num: [8, 3] - [8, 4]
n: 2
text: '2'
body: [
Expr: [9, 4] - [9, 21]
value:
TemplateString: [9, 4] - [9, 21]
prefix: 't"'
values: [
TemplateStringPart: [9, 6] - [9, 13]
text: '"Hello, "'
s: 'Hello, '
Name: [9, 14] - [9, 18]
variable: Variable('name', None)
ctx: Load
TemplateStringPart: [9, 19] - [9, 20]
text: '"!"'
s: '!'
]
]
orelse: None
If: [10, 0] - [10, 5]
test:
Num: [10, 3] - [10, 4]
n: 3
text: '3'
body: [
Expr: [11, 4] - [11, 42]
value:
TemplateString: [11, 4] - [11, 42]
prefix: 't"'
values: [
TemplateStringPart: [11, 6] - [11, 13]
text: '"Value: "'
s: 'Value: '
Name: [11, 14] - [11, 19]
variable: Variable('value', None)
ctx: Load
TemplateStringPart: [11, 24] - [11, 31]
text: '", Hex: "'
s: ', Hex: '
Name: [11, 32] - [11, 37]
variable: Variable('value', None)
ctx: Load
]
]
orelse: None
If: [12, 0] - [12, 5]
test:
Num: [12, 3] - [12, 4]
n: 4
text: '4'
body: [
Expr: [13, 4] - [13, 29]
value:
TemplateString: [13, 4] - [13, 29]
prefix: 't"'
values: [
TemplateStringPart: [13, 6] - [13, 28]
text: '"Just a regular string."'
s: 'Just a regular string.'
]
]
orelse: None
If: [14, 0] - [14, 5]
test:
Num: [14, 3] - [14, 4]
n: 5
text: '5'
body: [
Expr: [15, 4] - [15, 50]
value:
TemplateString: [15, 4] - [15, 50]
prefix: 't"'
values: [
TemplateStringPart: [15, 6] - [15, 15]
text: '"Multiple "'
s: 'Multiple '
Name: [15, 16] - [15, 21]
variable: Variable('first', None)
ctx: Load
TemplateStringPart: [15, 22] - [15, 27]
text: '" and "'
s: ' and '
Name: [15, 28] - [15, 34]
variable: Variable('second', None)
ctx: Load
TemplateStringPart: [15, 35] - [15, 49]
text: '" placeholders."'
s: ' placeholders.'
]
]
orelse: None
If: [16, 0] - [16, 5]
test:
Num: [16, 3] - [16, 4]
n: 6
text: '6'
body: [
Expr: [17, 4] - [17, 66]
value:
JoinedTemplateString: [17, 4] - [17, 66]
strings: [
TemplateString: [17, 4] - [17, 31]
prefix: 't"'
values: [
TemplateStringPart: [17, 6] - [17, 30]
text: '"Implicit concatenation: "'
s: 'Implicit concatenation: '
]
TemplateString: [17, 32] - [17, 49]
prefix: 't"'
values: [
TemplateStringPart: [17, 34] - [17, 41]
text: '"Hello, "'
s: 'Hello, '
Name: [17, 42] - [17, 46]
variable: Variable('name', None)
ctx: Load
TemplateStringPart: [17, 47] - [17, 48]
text: '"!"'
s: '!'
]
TemplateString: [17, 50] - [17, 66]
prefix: 't"'
values: [
TemplateStringPart: [17, 52] - [17, 65]
text: '" How are you?"'
s: ' How are you?'
]
]
]
orelse: None
]

View File

@@ -0,0 +1,17 @@
name = "World"
value = 42.5678
first = "first"
second = "second"
if 1:
t""
if 2:
t"Hello, {name}!"
if 3:
t"Value: {value:.2f}, Hex: {value:#x}"
if 4:
t"Just a regular string."
if 5:
t"Multiple {first} and {second} placeholders."
if 6:
t"Implicit concatenation: " t"Hello, {name}!" t" How are you?"

View File

@@ -117,6 +117,9 @@
(string string_content: (_) @part)
{ let @part.node = (ast-node @part "StringPart") }
(template_string string_content: (_) @part)
{ let @part.node = (ast-node @part "TemplateStringPart") }
; A string concatenation that contains no interpolated expressions is just a `Str` (and its children
; will be `StringPart`s). A string concatenation that contains interpolated expressions is a
; `JoinedStr`, however.
@@ -142,6 +145,12 @@
}
}
(template_string) @tstring
{ let @tstring.node = (ast-node @tstring "TemplateString") }
(concatenated_template_string) @tstrings
{ let @tstrings.node = (ast-node @tstrings "JoinedTemplateString") }
(pair) @kvpair
{ let @kvpair.node = (ast-node @kvpair "KeyValuePair") }
@@ -2052,6 +2061,44 @@
;;;;;; End of JoinedStr (`f"foo"`)
;;;;;; JoinedTemplateString / TemplateString (`t"foo"`)
; Record the prefix of the template string.
(template_string) @tstring
{
attr (@tstring.node) prefix = (string-prefix @tstring)
}
; Attach raw children (string parts and interpolations) to the template string node.
(template_string (string_content) @part) @tmpl_any
{
edge @tmpl_any.node -> @part.node
attr (@tmpl_any.node -> @part.node) values = (named-child-index @part)
attr (@part.node) ctx = "load"
let safe_string = (concatenate-strings (string-safe-prefix @tmpl_any) (source-text @part) (string-quotes @tmpl_any))
attr (@part.node) s = safe_string
attr (@part.node) text = safe_string
}
(template_string (interpolation expression: (_) @part) @interp) @tmpl_any
{
edge @tmpl_any.node -> @part.node
attr (@tmpl_any.node -> @part.node) values = (named-child-index @interp)
attr (@part.node) ctx = "load"
}
; Concatenated template strings simply have a list-like field containing the template strings that
; are concatenated together.
(concatenated_template_string (template_string) @tstring) @tmpl_concat
{
edge @tmpl_concat.node -> @tstring.node
attr (@tmpl_concat.node -> @tstring.node) strings = (named-child-index @tstring)
attr (@tstring.node) ctx = "load"
}
;;;;;; End of JoinedTemplateString / TemplateString (`t"foo"`)
;;;;;; List (`[...]`)

View File

@@ -140,15 +140,22 @@ pub mod extra_functions {
}
fn safe(&self) -> Prefix {
// Remove format (f/F) and template (t/T) flags when generating a safe prefix.
Prefix {
flags: self.flags.clone().replace("f", "").replace("F", ""),
flags: self
.flags
.clone()
.replace("f", "")
.replace("F", "")
.replace("t", "")
.replace("T", ""),
quotes: self.quotes.clone(),
}
}
}
fn get_prefix(s: &str) -> Prefix {
let flags_matcher = regex::Regex::new("^[bfurBFUR]{0,2}").unwrap();
let flags_matcher = regex::Regex::new("^[bfurtBFURT]{0,2}").unwrap();
let mut end = 0;
let flags = match flags_matcher.find(s) {
Some(m) => {
@@ -170,7 +177,7 @@ pub mod extra_functions {
quotes = "}";
}
Prefix {
flags: flags.to_lowercase().to_owned(),
flags: flags.to_owned(),
quotes: quotes.to_owned(),
}
}
@@ -198,6 +205,12 @@ pub mod extra_functions {
let p = get_prefix("\"\"\"\"\"\"");
assert_eq!(p.flags, "");
assert_eq!(p.quotes, "\"\"\"");
let p = get_prefix("t\"hello\"");
assert_eq!(p.flags, "t");
assert_eq!(p.quotes, "\"");
let p = get_prefix("Tr'world'");
assert_eq!(p.flags, "Tr");
assert_eq!(p.quotes, "'");
}
fn get_string_contents(s: String) -> String {
@@ -227,6 +240,10 @@ pub mod extra_functions {
assert_eq!(get_string_contents(s.to_owned()), "");
let s = "''''''";
assert_eq!(get_string_contents(s.to_owned()), "");
let s = "t\"tmpl\"";
assert_eq!(get_string_contents(s.to_owned()), "tmpl");
let s = "Tr'world'";
assert_eq!(get_string_contents(s.to_owned()), "world");
}
pub struct StringPrefix;
@@ -291,7 +308,11 @@ pub mod extra_functions {
let node = graph[parameters.param()?.into_syntax_node_ref()?];
parameters.finish()?;
let prefix = get_prefix(&source[node.byte_range()]).full();
let prefix = prefix.replace("f", "").replace("F", "");
let prefix = prefix
.replace("f", "")
.replace("F", "")
.replace("t", "")
.replace("T", "");
Ok(Value::String(prefix))
}
}

View File

@@ -55,6 +55,7 @@ module.exports = grammar({
$._string_start,
$._string_content,
$._string_end,
$._template_string_start,
],
inline: $ => [
@@ -423,6 +424,8 @@ module.exports = grammar({
),
$.string,
$.concatenated_string,
$.template_string,
$.concatenated_template_string,
$.none,
$.true,
$.false
@@ -765,6 +768,8 @@ module.exports = grammar({
$.keyword_identifier,
$.string,
$.concatenated_string,
$.template_string,
$.concatenated_template_string,
$.integer,
$.float,
$.true,
@@ -1099,6 +1104,20 @@ module.exports = grammar({
field('suffix', alias($._string_end, '"'))
),
concatenated_template_string: $ => seq(
$.template_string,
repeat1($.template_string)
),
template_string: $ => seq(
field('prefix', alias($._template_string_start, '"')),
repeat(choice(
field('interpolation', $.interpolation),
field('string_content', $.string_content)
)),
field('suffix', alias($._string_end, '"'))
),
string_content: $ => prec.right(0, repeat1(
choice(
$._escape_interpolation,

View File

@@ -1800,6 +1800,14 @@
"type": "SYMBOL",
"name": "concatenated_string"
},
{
"type": "SYMBOL",
"name": "template_string"
},
{
"type": "SYMBOL",
"name": "concatenated_template_string"
},
{
"type": "SYMBOL",
"name": "none"
@@ -3891,6 +3899,14 @@
"type": "SYMBOL",
"name": "concatenated_string"
},
{
"type": "SYMBOL",
"name": "template_string"
},
{
"type": "SYMBOL",
"name": "concatenated_template_string"
},
{
"type": "SYMBOL",
"name": "integer"
@@ -5982,6 +5998,77 @@
}
]
},
"concatenated_template_string": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "template_string"
},
{
"type": "REPEAT1",
"content": {
"type": "SYMBOL",
"name": "template_string"
}
}
]
},
"template_string": {
"type": "SEQ",
"members": [
{
"type": "FIELD",
"name": "prefix",
"content": {
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "_template_string_start"
},
"named": false,
"value": "\""
}
},
{
"type": "REPEAT",
"content": {
"type": "CHOICE",
"members": [
{
"type": "FIELD",
"name": "interpolation",
"content": {
"type": "SYMBOL",
"name": "interpolation"
}
},
{
"type": "FIELD",
"name": "string_content",
"content": {
"type": "SYMBOL",
"name": "string_content"
}
}
]
}
},
{
"type": "FIELD",
"name": "suffix",
"content": {
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "_string_end"
},
"named": false,
"value": "\""
}
}
]
},
"string_content": {
"type": "PREC_RIGHT",
"value": 0,
@@ -6710,6 +6797,10 @@
{
"type": "SYMBOL",
"name": "_string_end"
},
{
"type": "SYMBOL",
"name": "_template_string_start"
}
],
"inline": [

View File

@@ -241,6 +241,10 @@
"type": "concatenated_string",
"named": true
},
{
"type": "concatenated_template_string",
"named": true
},
{
"type": "dictionary",
"named": true
@@ -305,6 +309,10 @@
"type": "subscript",
"named": true
},
{
"type": "template_string",
"named": true
},
{
"type": "true",
"named": true
@@ -1000,6 +1008,21 @@
]
}
},
{
"type": "concatenated_template_string",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": true,
"types": [
{
"type": "template_string",
"named": true
}
]
}
},
{
"type": "conditional_expression",
"named": true,
@@ -2460,6 +2483,10 @@
"type": "concatenated_string",
"named": true
},
{
"type": "concatenated_template_string",
"named": true
},
{
"type": "false",
"named": true
@@ -2472,6 +2499,10 @@
"type": "string",
"named": true
},
{
"type": "template_string",
"named": true
},
{
"type": "true",
"named": true
@@ -3257,6 +3288,52 @@
}
}
},
{
"type": "template_string",
"named": true,
"fields": {
"interpolation": {
"multiple": true,
"required": false,
"types": [
{
"type": "interpolation",
"named": true
}
]
},
"prefix": {
"multiple": false,
"required": true,
"types": [
{
"type": "\"",
"named": false
}
]
},
"string_content": {
"multiple": true,
"required": false,
"types": [
{
"type": "string_content",
"named": true
}
]
},
"suffix": {
"multiple": false,
"required": true,
"types": [
{
"type": "\"",
"named": false
}
]
}
}
},
{
"type": "try_statement",
"named": true,

File diff suppressed because it is too large Load Diff

View File

@@ -17,6 +17,7 @@ enum TokenType {
STRING_START,
STRING_CONTENT,
STRING_END,
TEMPLATE_STRING_START,
};
struct Delimiter {
@@ -28,6 +29,7 @@ struct Delimiter {
Format = 1 << 4,
Triple = 1 << 5,
Bytes = 1 << 6,
Template = 1 << 7,
};
Delimiter() : flags(0) {}
@@ -36,6 +38,14 @@ struct Delimiter {
return flags & Format;
}
bool is_template() const {
return flags & Template;
}
bool can_interpolate() const {
return is_format() || is_template();
}
bool is_raw() const {
return flags & Raw;
}
@@ -59,6 +69,10 @@ struct Delimiter {
flags |= Format;
}
void set_template() {
flags |= Template;
}
void set_raw() {
flags |= Raw;
}
@@ -154,7 +168,7 @@ struct Scanner {
int32_t end_character = delimiter.end_character();
bool has_content = false;
while (lexer->lookahead) {
if ((lexer->lookahead == '{' || lexer->lookahead == '}') && delimiter.is_format()) {
if ((lexer->lookahead == '{' || lexer->lookahead == '}') && delimiter.can_interpolate()) {
lexer->mark_end(lexer);
lexer->result_symbol = STRING_CONTENT;
return has_content;
@@ -322,13 +336,17 @@ struct Scanner {
}
}
if (first_comment_indent_length == -1 && valid_symbols[STRING_START]) {
bool expects_string_start = valid_symbols[STRING_START] || valid_symbols[TEMPLATE_STRING_START];
if (first_comment_indent_length == -1 && expects_string_start) {
Delimiter delimiter;
bool has_flags = false;
while (lexer->lookahead) {
if (lexer->lookahead == 'f' || lexer->lookahead == 'F') {
delimiter.set_format();
} else if (lexer->lookahead == 't' || lexer->lookahead == 'T') {
delimiter.set_template();
} else if (lexer->lookahead == 'r' || lexer->lookahead == 'R') {
delimiter.set_raw();
} else if (lexer->lookahead == 'b' || lexer->lookahead == 'B') {
@@ -372,7 +390,7 @@ struct Scanner {
if (delimiter.end_character()) {
delimiter_stack.push_back(delimiter);
lexer->result_symbol = STRING_START;
lexer->result_symbol = delimiter.is_template() ? TEMPLATE_STRING_START : STRING_START;
return true;
} else if (has_flags) {
return false;

View File

@@ -123,7 +123,6 @@ struct TSLanguage {
unsigned (*serialize)(void *, char *);
void (*deserialize)(void *, const char *, unsigned);
} external_scanner;
const TSStateId *primary_state_ids;
};
/*

View File

@@ -0,0 +1,4 @@
---
category: feature
---
* The Python extractor now supports template strings as defined in [PEP-750](https://peps.python.org/pep-0750/), through the classes `TemplateString` and `JoinedTemplateString`.

View File

@@ -218,6 +218,9 @@ class DictItemListParent extends DictItemListParent_ { }
/** A list of strings (the primitive type string not Bytes or Unicode) */
class StringList extends StringList_ { }
/** A list of template strings. */
class TemplateStringList extends TemplateStringList_ { }
/** A list of aliases in an import statement */
class AliasList extends AliasList_ { }
@@ -273,3 +276,9 @@ class ParamSpec extends ParamSpec_, TypeParameter {
override Expr getAChildNode() { result = this.getName() }
}
/** A template string literal. */
class TemplateString extends TemplateString_, Expr { }
/** An (implicitly) concatenated list of template strings. */
class JoinedTemplateString extends JoinedTemplateString_, Expr { }

View File

@@ -768,6 +768,20 @@ class Fstring_ extends @py_Fstring, Expr {
override string toString() { result = "Fstring" }
}
/** INTERNAL: See the class `JoinedTemplateString` for further information. */
class JoinedTemplateString_ extends @py_JoinedTemplateString, Expr {
/** Gets the strings of this joined template string. */
TemplateStringList getStrings() { py_TemplateString_lists(result, this) }
/** Gets the nth string of this joined template string. */
TemplateString getString(int index) { result = this.getStrings().getItem(index) }
/** Gets a string of this joined template string. */
TemplateString getAString() { result = this.getStrings().getAnItem() }
override string toString() { result = "JoinedTemplateString" }
}
/** INTERNAL: See the class `KeyValuePair` for further information. */
class KeyValuePair_ extends @py_KeyValuePair, DictItem {
/** Gets the location of this key-value pair. */
@@ -1373,6 +1387,48 @@ class TemplateDottedNotation_ extends @py_TemplateDottedNotation, Expr {
override string toString() { result = "TemplateDottedNotation" }
}
/** INTERNAL: See the class `TemplateString` for further information. */
class TemplateString_ extends @py_TemplateString, Expr {
/** Gets the prefix of this template string literal. */
string getPrefix() { py_strs(result, this, 2) }
/** Gets the values of this template string literal. */
ExprList getValues() { py_expr_lists(result, this, 3) }
/** Gets the nth value of this template string literal. */
Expr getValue(int index) { result = this.getValues().getItem(index) }
/** Gets a value of this template string literal. */
Expr getAValue() { result = this.getValues().getAnItem() }
override ExprParent getParent() { py_exprs(this, _, result, _) }
override string toString() { result = "TemplateString" }
}
/** INTERNAL: See the class `TemplateStringPart` for further information. */
class TemplateStringPart_ extends @py_TemplateStringPart, Expr {
/** Gets the text of this string part of a template string. */
string getText() { py_strs(result, this, 2) }
override string toString() { result = "TemplateStringPart" }
}
/** INTERNAL: See the class `TemplateStringList` for further information. */
class TemplateStringList_ extends @py_TemplateString_list {
/** Gets a parent of this template string literal list */
JoinedTemplateString getParent() { py_TemplateString_lists(this, result) }
/** Gets an item of this template string literal list */
Expr getAnItem() { py_exprs(result, _, this, _) }
/** Gets the nth item of this template string literal list */
Expr getItem(int index) { py_exprs(result, _, this, index) }
/** Gets a textual representation of this element. */
string toString() { result = "TemplateStringList" }
}
/** INTERNAL: See the class `TemplateWrite` for further information. */
class TemplateWrite_ extends @py_TemplateWrite, Stmt {
/** Gets the value of this template write statement. */

View File

@@ -715,7 +715,7 @@ private module InterModulePointsTo {
i.getImportedModuleName() = name and
PointsToInternal::module_imported_as(value, name) and
origin = f and
context.appliesTo(f)
context.appliesTo(pragma[only_bind_into](f))
)
}

View File

@@ -530,6 +530,10 @@ py_extracted_version(int module : @py_Module ref,
/* <Field> Fstring.values = 2, expr_list */
/* <Parent> Fstring = FormattedValue */
/* <Field> JoinedTemplateString.location = 0, location */
/* <Field> JoinedTemplateString.parenthesised = 1, bool */
/* <Field> JoinedTemplateString.strings = 2, TemplateString_list */
/* <Field> KeyValuePair.location = 0, location */
/* <Field> KeyValuePair.value = 1, expr */
/* <Field> KeyValuePair.key = 2, expr */
@@ -709,6 +713,17 @@ py_extracted_version(int module : @py_Module ref,
/* <Field> TemplateDottedNotation.attr = 3, str */
/* <Field> TemplateDottedNotation.ctx = 4, expr_context */
/* <Field> TemplateString.location = 0, location */
/* <Field> TemplateString.parenthesised = 1, bool */
/* <Field> TemplateString.prefix = 2, str */
/* <Field> TemplateString.values = 3, expr_list */
/* <Parent> TemplateString = TemplateStringList */
/* <Field> TemplateStringPart.location = 0, location */
/* <Field> TemplateStringPart.parenthesised = 1, bool */
/* <Field> TemplateStringPart.text = 2, str */
/* <Parent> TemplateStringList = JoinedTemplateString */
/* <Field> TemplateWrite.location = 0, location */
/* <Field> TemplateWrite.value = 1, expr */
@@ -835,6 +850,9 @@ py_StringParts(unique int id : @py_StringPart,
py_StringPart_lists(unique int id : @py_StringPart_list,
unique int parent : @py_Bytes_or_Str ref);
py_TemplateString_lists(unique int id : @py_TemplateString_list,
unique int parent : @py_JoinedTemplateString ref);
py_aliases(unique int id : @py_alias,
int parent : @py_alias_list ref,
int idx : int ref);
@@ -1010,7 +1028,10 @@ case @py_expr.kind of
| 36 = @py_Fstring
| 37 = @py_FormattedValue
| 38 = @py_AssignExpr
| 39 = @py_SpecialOperation;
| 39 = @py_SpecialOperation
| 40 = @py_TemplateString
| 41 = @py_JoinedTemplateString
| 42 = @py_TemplateStringPart;
case @py_expr_context.kind of
0 = @py_AugLoad
@@ -1105,11 +1126,11 @@ case @py_unaryop.kind of
@py_expr_context_parent = @py_Attribute | @py_List | @py_Name | @py_PlaceHolder | @py_Starred | @py_Subscript | @py_TemplateDottedNotation | @py_Tuple;
@py_expr_list_parent = @py_Assign | @py_BoolExpr | @py_Call | @py_ClassExpr | @py_Compare | @py_Delete | @py_Fstring | @py_Function | @py_List | @py_Print | @py_Set | @py_SpecialOperation | @py_Tuple | @py_arguments | @py_comprehension;
@py_expr_list_parent = @py_Assign | @py_BoolExpr | @py_Call | @py_ClassExpr | @py_Compare | @py_Delete | @py_Fstring | @py_Function | @py_List | @py_Print | @py_Set | @py_SpecialOperation | @py_TemplateString | @py_Tuple | @py_arguments | @py_comprehension;
@py_expr_or_stmt = @py_expr | @py_stmt;
@py_expr_parent = @py_AnnAssign | @py_Assert | @py_Assign | @py_AssignExpr | @py_Attribute | @py_AugAssign | @py_Await | @py_BinaryExpr | @py_Call | @py_Case | @py_Compare | @py_DictComp | @py_DictUnpacking | @py_ExceptGroupStmt | @py_ExceptStmt | @py_Exec | @py_Expr_stmt | @py_Filter | @py_For | @py_FormattedValue | @py_Function | @py_FunctionExpr | @py_GeneratorExp | @py_Guard | @py_If | @py_IfExp | @py_ImportMember | @py_ImportStar | @py_KeyValuePair | @py_ListComp | @py_MatchAsPattern | @py_MatchCapturePattern | @py_MatchClassPattern | @py_MatchKeywordPattern | @py_MatchLiteralPattern | @py_MatchStmt | @py_MatchValuePattern | @py_ParamSpec | @py_Print | @py_Raise | @py_Repr | @py_Return | @py_SetComp | @py_Slice | @py_Starred | @py_Subscript | @py_TemplateDottedNotation | @py_TemplateWrite | @py_TypeAlias | @py_TypeVar | @py_TypeVarTuple | @py_UnaryExpr | @py_While | @py_With | @py_Yield | @py_YieldFrom | @py_alias | @py_arguments | @py_comprehension | @py_expr_list | @py_keyword | @py_parameter_list;
@py_expr_parent = @py_AnnAssign | @py_Assert | @py_Assign | @py_AssignExpr | @py_Attribute | @py_AugAssign | @py_Await | @py_BinaryExpr | @py_Call | @py_Case | @py_Compare | @py_DictComp | @py_DictUnpacking | @py_ExceptGroupStmt | @py_ExceptStmt | @py_Exec | @py_Expr_stmt | @py_Filter | @py_For | @py_FormattedValue | @py_Function | @py_FunctionExpr | @py_GeneratorExp | @py_Guard | @py_If | @py_IfExp | @py_ImportMember | @py_ImportStar | @py_KeyValuePair | @py_ListComp | @py_MatchAsPattern | @py_MatchCapturePattern | @py_MatchClassPattern | @py_MatchKeywordPattern | @py_MatchLiteralPattern | @py_MatchStmt | @py_MatchValuePattern | @py_ParamSpec | @py_Print | @py_Raise | @py_Repr | @py_Return | @py_SetComp | @py_Slice | @py_Starred | @py_Subscript | @py_TemplateDottedNotation | @py_TemplateString_list | @py_TemplateWrite | @py_TypeAlias | @py_TypeVar | @py_TypeVarTuple | @py_UnaryExpr | @py_While | @py_With | @py_Yield | @py_YieldFrom | @py_alias | @py_arguments | @py_comprehension | @py_expr_list | @py_keyword | @py_parameter_list;
@py_location_parent = @py_DictUnpacking | @py_KeyValuePair | @py_StringPart | @py_comprehension | @py_expr | @py_keyword | @py_pattern | @py_stmt | @py_type_parameter;
@@ -1125,7 +1146,7 @@ case @py_unaryop.kind of
@py_str_list_parent = @py_Global | @py_Nonlocal;
@py_str_parent = @py_Attribute | @py_Class | @py_ClassExpr | @py_FormattedValue | @py_Function | @py_FunctionExpr | @py_ImportExpr | @py_ImportMember | @py_Module | @py_SpecialOperation | @py_Str | @py_StringPart | @py_TemplateDottedNotation | @py_keyword | @py_str_list;
@py_str_parent = @py_Attribute | @py_Class | @py_ClassExpr | @py_FormattedValue | @py_Function | @py_FunctionExpr | @py_ImportExpr | @py_ImportMember | @py_Module | @py_SpecialOperation | @py_Str | @py_StringPart | @py_TemplateDottedNotation | @py_TemplateString | @py_TemplateStringPart | @py_keyword | @py_str_list;
@py_type_parameter_list_parent = @py_ClassExpr | @py_Function | @py_TypeAlias;

View File

@@ -5,6 +5,10 @@
<k>@py_TypeVar</k><v>100</v></e><e>
<k>@py_TypeVarTuple</k><v>100</v></e><e>
<k>@py_type_parameter_list</k><v>100</v></e><e>
<k>@py_TemplateStringPart</k><v>100</v></e><e>
<k>@py_TemplateString_list</k><v>100</v></e><e>
<k>@py_JoinedTemplateString</k><v>100</v></e><e>
<k>@py_TemplateString</k><v>100</v></e><e>
<k>@py_Guard</k><v>100</v></e><e>
<k>@py_MatchAsPattern</k><v>100</v></e><e>
<k>@py_MatchOrPattern</k><v>100</v></e><e>
@@ -7959,6 +7963,21 @@
</dependencies>
</relation>
<relation>
<name>py_TemplateString_lists</name>
<cardinality>1000</cardinality>
<columnsizes>
<e>
<k>id</k>
<v>1000</v>
</e>
<e>
<k>parent</k>
<v>1000</v>
</e>
</columnsizes>
<dependencies/>
</relation>
<relation>
<name>py_aliases</name>
<cardinality>21374</cardinality>
<columnsizes>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
description: Add support for template string literals
compatibility: backwards