rapydscript-ns 0.8.1 → 0.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CONTRIBUTORS +3 -2
- package/PYTHON_FEATURE_COVERAGE.md +109 -0
- package/README.md +320 -34
- package/TODO.md +17 -48
- package/hack_demo.pyj +112 -0
- package/package.json +1 -4
- package/src/ast.pyj +30 -6
- package/src/baselib-builtins.pyj +104 -10
- package/src/baselib-containers.pyj +146 -1
- package/src/baselib-errors.pyj +3 -0
- package/src/baselib-internal.pyj +10 -0
- package/src/baselib-str.pyj +34 -0
- package/src/monaco-language-service/analyzer.js +1 -13
- package/src/monaco-language-service/builtins.js +10 -0
- package/src/monaco-language-service/completions.js +54 -2
- package/src/monaco-language-service/diagnostics.js +54 -4
- package/src/monaco-language-service/index.js +9 -5
- package/src/output/codegen.pyj +37 -2
- package/src/output/functions.pyj +31 -9
- package/src/output/loops.pyj +64 -2
- package/src/output/operators.pyj +53 -1
- package/src/output/statements.pyj +7 -3
- package/src/output/stream.pyj +6 -0
- package/src/parse.pyj +77 -13
- package/src/tokenizer.pyj +1 -0
- package/test/python_features.pyj +1184 -0
- package/test/unit/language-service-bundle.js +83 -0
- package/test/unit/language-service-completions.js +109 -0
- package/test/unit/language-service.js +123 -1
- package/test/unit/run-language-service.js +1 -0
- package/tools/lint.js +1 -1
- package/tools/self.js +1 -9
- package/web-repl/language-service.js +129 -26
- package/web-repl/rapydscript.js +3 -3
package/src/output/loops.pyj
CHANGED
|
@@ -47,16 +47,49 @@ def print_do_loop(self, output):
|
|
|
47
47
|
output.space()
|
|
48
48
|
output.print("while")
|
|
49
49
|
output.space()
|
|
50
|
-
|
|
50
|
+
if self.python_truthiness:
|
|
51
|
+
output.with_parens(def(): output.print('ρσ_bool('), self.condition.print(output), output.print(')');)
|
|
52
|
+
else:
|
|
53
|
+
output.with_parens(def(): self.condition.print(output);)
|
|
51
54
|
output.semicolon()
|
|
52
55
|
|
|
53
56
|
def print_while_loop(self, output):
|
|
57
|
+
# while/else: wrap in a labeled block; break inside will skip the else
|
|
58
|
+
forelse_label = None
|
|
59
|
+
if self.belse:
|
|
60
|
+
forelse_label = output.new_forelse_label()
|
|
61
|
+
output.forelse_stack.push(forelse_label)
|
|
62
|
+
output.print(forelse_label + ':')
|
|
63
|
+
output.space()
|
|
64
|
+
output.print('{')
|
|
65
|
+
output.newline()
|
|
66
|
+
output.set_indentation(output.next_indent())
|
|
67
|
+
output.indent()
|
|
68
|
+
else:
|
|
69
|
+
output.forelse_stack.push(None)
|
|
70
|
+
|
|
54
71
|
output.print("while")
|
|
55
72
|
output.space()
|
|
56
|
-
|
|
73
|
+
if self.python_truthiness:
|
|
74
|
+
output.with_parens(def(): output.print('ρσ_bool('), self.condition.print(output), output.print(')');)
|
|
75
|
+
else:
|
|
76
|
+
output.with_parens(def(): self.condition.print(output);)
|
|
57
77
|
output.space()
|
|
58
78
|
self._do_print_body(output)
|
|
59
79
|
|
|
80
|
+
output.forelse_stack.pop()
|
|
81
|
+
|
|
82
|
+
if forelse_label:
|
|
83
|
+
if self.belse and self.belse.body and self.belse.body.length:
|
|
84
|
+
output.newline()
|
|
85
|
+
for stmt in self.belse.body:
|
|
86
|
+
output.indent()
|
|
87
|
+
stmt.print(output)
|
|
88
|
+
output.newline()
|
|
89
|
+
output.set_indentation(output._indentation - output.options.indent_level)
|
|
90
|
+
output.indent()
|
|
91
|
+
output.print('}')
|
|
92
|
+
|
|
60
93
|
def is_simple_for_in(self):
|
|
61
94
|
# return true if this loop can be simplified into a basic for (i in j) loop
|
|
62
95
|
if is_node_type(self.object, AST_BaseCall)
|
|
@@ -131,6 +164,21 @@ def print_for_in(self, output):
|
|
|
131
164
|
else:
|
|
132
165
|
self.object.print(output)
|
|
133
166
|
|
|
167
|
+
# for/else: wrap in a labeled block; break inside will use the label to skip else
|
|
168
|
+
forelse_label = None
|
|
169
|
+
if self.belse:
|
|
170
|
+
forelse_label = output.new_forelse_label()
|
|
171
|
+
output.forelse_stack.push(forelse_label)
|
|
172
|
+
output.print(forelse_label + ':')
|
|
173
|
+
output.space()
|
|
174
|
+
output.print('{')
|
|
175
|
+
output.newline()
|
|
176
|
+
output.set_indentation(output.next_indent())
|
|
177
|
+
output.indent()
|
|
178
|
+
else:
|
|
179
|
+
# Push null so nested for loops don't mistakenly grab an outer forelse label
|
|
180
|
+
output.forelse_stack.push(None)
|
|
181
|
+
|
|
134
182
|
if is_simple_for(self):
|
|
135
183
|
# optimize range() into a simple for loop
|
|
136
184
|
increment = None
|
|
@@ -227,6 +275,20 @@ def print_for_in(self, output):
|
|
|
227
275
|
output.space()
|
|
228
276
|
self._do_print_body(output)
|
|
229
277
|
|
|
278
|
+
output.forelse_stack.pop()
|
|
279
|
+
|
|
280
|
+
if forelse_label:
|
|
281
|
+
# Emit else body, then close the labeled block
|
|
282
|
+
if self.belse and self.belse.body and self.belse.body.length:
|
|
283
|
+
output.newline()
|
|
284
|
+
for stmt in self.belse.body:
|
|
285
|
+
output.indent()
|
|
286
|
+
stmt.print(output)
|
|
287
|
+
output.newline()
|
|
288
|
+
output.set_indentation(output._indentation - output.options.indent_level)
|
|
289
|
+
output.indent()
|
|
290
|
+
output.print('}')
|
|
291
|
+
|
|
230
292
|
def print_list_comprehension(self, output):
|
|
231
293
|
tname = self.constructor.name.slice(4)
|
|
232
294
|
result_obj = {'ListComprehension':'[]', 'DictComprehension':('Object.create(null)' if self.is_jshash else '{}'), 'SetComprehension':'ρσ_set()'}[tname]
|
package/src/output/operators.pyj
CHANGED
|
@@ -110,6 +110,16 @@ def print_unary_prefix(self, output):
|
|
|
110
110
|
if op is '~':
|
|
111
111
|
output.print('ρσ_op_invert('), self.expression.print(output), output.print(')')
|
|
112
112
|
return
|
|
113
|
+
if op is '!' and self.python_truthiness:
|
|
114
|
+
output.print('!ρσ_bool(')
|
|
115
|
+
if self.parenthesized:
|
|
116
|
+
output.with_parens(def():
|
|
117
|
+
self.expression.print(output)
|
|
118
|
+
)
|
|
119
|
+
else:
|
|
120
|
+
self.expression.print(output)
|
|
121
|
+
output.print(')')
|
|
122
|
+
return
|
|
113
123
|
output.print(op)
|
|
114
124
|
if /^[a-z]/i.test(op):
|
|
115
125
|
output.space()
|
|
@@ -284,6 +294,36 @@ def print_binary_op(self, output):
|
|
|
284
294
|
output.spaced(nan_check, '!==' if self.operator is '===' else '===', nan_check)
|
|
285
295
|
else:
|
|
286
296
|
output.spaced(self.left, self.operator, self.right)
|
|
297
|
+
elif (self.operator is '&&' or self.operator is '||') and self.python_truthiness:
|
|
298
|
+
# Python `and`/`or` use Python truthiness (only when from __python__ import truthiness is set).
|
|
299
|
+
# `a and b` → `ρσ_bool(a) ? b : a` (returns a if falsy, else b)
|
|
300
|
+
# `a or b` → `ρσ_bool(a) ? a : b` (returns a if truthy, else b)
|
|
301
|
+
# For non-simple left operands, cache in ρσ_expr_temp to avoid double evaluation.
|
|
302
|
+
is_and = self.operator is '&&'
|
|
303
|
+
if is_node_type(self.left, AST_SymbolRef):
|
|
304
|
+
output.print('(ρσ_bool(')
|
|
305
|
+
self.left.print(output)
|
|
306
|
+
output.print(') ? ')
|
|
307
|
+
if is_and:
|
|
308
|
+
self.right.print(output)
|
|
309
|
+
output.print(' : ')
|
|
310
|
+
self.left.print(output)
|
|
311
|
+
else:
|
|
312
|
+
self.left.print(output)
|
|
313
|
+
output.print(' : ')
|
|
314
|
+
self.right.print(output)
|
|
315
|
+
output.print(')')
|
|
316
|
+
else:
|
|
317
|
+
output.print('(ρσ_expr_temp = ')
|
|
318
|
+
self.left.print(output)
|
|
319
|
+
output.print(', ρσ_bool(ρσ_expr_temp) ? ')
|
|
320
|
+
if is_and:
|
|
321
|
+
self.right.print(output)
|
|
322
|
+
output.print(' : ρσ_expr_temp)')
|
|
323
|
+
else:
|
|
324
|
+
output.print('ρσ_expr_temp : ')
|
|
325
|
+
self.right.print(output)
|
|
326
|
+
output.print(')')
|
|
287
327
|
else:
|
|
288
328
|
output.spaced(self.left, self.operator, self.right)
|
|
289
329
|
|
|
@@ -368,6 +408,13 @@ def print_assign(self, output):
|
|
|
368
408
|
self.right.print(output)
|
|
369
409
|
)
|
|
370
410
|
return
|
|
411
|
+
if self.operator is '**=':
|
|
412
|
+
output.assign(self.left)
|
|
413
|
+
if output.options.js_version > 6:
|
|
414
|
+
output.print('(('), self.left.print(output), output.spaced(')', '**', '('), self.right.print(output), output.print('))')
|
|
415
|
+
else:
|
|
416
|
+
output.print('Math.pow('), self.left.print(output), output.comma(), self.right.print(output), output.print(')')
|
|
417
|
+
return
|
|
371
418
|
if self.operator is '=' and self.is_chained():
|
|
372
419
|
left_hand_sides, rhs = self.traverse_chain()
|
|
373
420
|
is_compound_assign = False
|
|
@@ -390,7 +437,12 @@ def print_assign(self, output):
|
|
|
390
437
|
|
|
391
438
|
def print_conditional(self, output, condition, consequent, alternative):
|
|
392
439
|
condition, consequent, alternative = self.condition, self.consequent, self.alternative
|
|
393
|
-
|
|
440
|
+
if self.python_truthiness:
|
|
441
|
+
output.print('ρσ_bool(')
|
|
442
|
+
condition.print(output)
|
|
443
|
+
output.print(')')
|
|
444
|
+
else:
|
|
445
|
+
output.with_parens(def(): condition.print(output);)
|
|
394
446
|
output.space()
|
|
395
447
|
output.print("?")
|
|
396
448
|
output.space()
|
|
@@ -156,15 +156,16 @@ def print_with(self, output):
|
|
|
156
156
|
output.with_block(def():
|
|
157
157
|
output.indent(), output.assign('ρσ_with_exception'), output.print('e'), output.end_statement()
|
|
158
158
|
)
|
|
159
|
+
reversed_exits = exits.slice().reverse()
|
|
159
160
|
output.newline(), output.indent(), output.spaced('if', '(ρσ_with_exception', '===', 'undefined)')
|
|
160
161
|
output.with_block(def():
|
|
161
|
-
for clause in
|
|
162
|
+
for clause in reversed_exits:
|
|
162
163
|
output.indent(), output.print(clause + '.__exit__()'), output.end_statement()
|
|
163
164
|
)
|
|
164
165
|
output.space(), output.print('else'), output.space()
|
|
165
166
|
output.with_block(def():
|
|
166
167
|
output.indent(), output.assign('ρσ_with_suppress'), output.print('false'), output.end_statement()
|
|
167
|
-
for clause in
|
|
168
|
+
for clause in reversed_exits:
|
|
168
169
|
output.indent()
|
|
169
170
|
output.spaced('ρσ_with_suppress', '|=', 'ρσ_bool(' + clause + '.__exit__(ρσ_with_exception.constructor,',
|
|
170
171
|
'ρσ_with_exception,', 'ρσ_with_exception.stack))')
|
|
@@ -175,7 +176,10 @@ def print_with(self, output):
|
|
|
175
176
|
def print_assert(self, output):
|
|
176
177
|
if output.options.discard_asserts:
|
|
177
178
|
return
|
|
178
|
-
|
|
179
|
+
if self.python_truthiness:
|
|
180
|
+
output.spaced('if', '(!ρσ_bool('), self.condition.print(output), output.spaced('))', 'throw new AssertionError')
|
|
181
|
+
else:
|
|
182
|
+
output.spaced('if', '(!('), self.condition.print(output), output.spaced('))', 'throw new AssertionError')
|
|
179
183
|
if self.message:
|
|
180
184
|
output.print('(')
|
|
181
185
|
self.message.print(output)
|
package/src/output/stream.pyj
CHANGED
|
@@ -76,6 +76,12 @@ class OutputStream:
|
|
|
76
76
|
self.with_counter = 0
|
|
77
77
|
self.try_else_counter = 0
|
|
78
78
|
self.match_counter = 0
|
|
79
|
+
self.forelse_counter = 0
|
|
80
|
+
self.forelse_stack = v'[]'
|
|
81
|
+
|
|
82
|
+
def new_forelse_label(self):
|
|
83
|
+
self.forelse_counter += 1
|
|
84
|
+
return 'ρσ_forelse_' + self.forelse_counter
|
|
79
85
|
|
|
80
86
|
def new_try_else_counter(self):
|
|
81
87
|
self.try_else_counter += 1
|
package/src/parse.pyj
CHANGED
|
@@ -24,12 +24,13 @@ AST_Undefined, AST_Var, AST_VarDef, AST_Verbatim, AST_While, AST_With, AST_WithC
|
|
|
24
24
|
AST_Yield, AST_Await, AST_Assert, AST_Existential, AST_NamedExpr, AST_AnnotatedAssign, AST_Super, AST_Starred, is_node_type,
|
|
25
25
|
AST_Match, AST_MatchCase,
|
|
26
26
|
AST_MatchWildcard, AST_MatchCapture, AST_MatchLiteral, AST_MatchOr,
|
|
27
|
-
AST_MatchAs, AST_MatchStar, AST_MatchSequence, AST_MatchMapping, AST_MatchClass
|
|
27
|
+
AST_MatchAs, AST_MatchStar, AST_MatchSequence, AST_MatchMapping, AST_MatchClass,
|
|
28
|
+
TreeWalker
|
|
28
29
|
)
|
|
29
30
|
from tokenizer import tokenizer, is_token, RESERVED_WORDS
|
|
30
31
|
|
|
31
32
|
COMPILER_VERSION = '__COMPILER_VERSION__'
|
|
32
|
-
PYTHON_FLAGS = {'dict_literals':True, 'overload_getitem':True, 'bound_methods':True, 'hash_literals':True, 'overload_operators':True}
|
|
33
|
+
PYTHON_FLAGS = {'dict_literals':True, 'overload_getitem':True, 'bound_methods':True, 'hash_literals':True, 'overload_operators':True, 'truthiness':True}
|
|
33
34
|
|
|
34
35
|
|
|
35
36
|
def get_compiler_version():
|
|
@@ -116,7 +117,7 @@ FORBIDDEN_CLASS_VARS = 'prototype constructor'.split(' ')
|
|
|
116
117
|
# -----[ Parser (constants) ]-----
|
|
117
118
|
UNARY_PREFIX = make_predicate('typeof void delete ~ - + ! @')
|
|
118
119
|
|
|
119
|
-
ASSIGNMENT = make_predicate('= += -= /= //= *= %= >>= <<= >>>= |= ^= &=')
|
|
120
|
+
ASSIGNMENT = make_predicate('= += -= /= //= *= **= %= >>= <<= >>>= |= ^= &=')
|
|
120
121
|
|
|
121
122
|
PRECEDENCE = (def(a, ret):
|
|
122
123
|
for i in range(a.length):
|
|
@@ -336,7 +337,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
336
337
|
continue
|
|
337
338
|
|
|
338
339
|
# recursive descent into conditional, loop and exception bodies
|
|
339
|
-
for option in ('body', 'alternative', 'bcatch', 'condition'):
|
|
340
|
+
for option in ('body', 'alternative', 'bcatch', 'belse', 'condition'):
|
|
340
341
|
opt = stmt[option]
|
|
341
342
|
if opt:
|
|
342
343
|
extend(scan_for_local_vars(opt))
|
|
@@ -402,6 +403,23 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
402
403
|
|
|
403
404
|
elif is_node_type(body, AST_ForIn):
|
|
404
405
|
add_for_in(body)
|
|
406
|
+
# Also scan conditions for walrus operators (e.g. comprehension filters)
|
|
407
|
+
if body.condition:
|
|
408
|
+
extend(scan_for_local_vars(body.condition))
|
|
409
|
+
if body.clauses:
|
|
410
|
+
for clause in body.clauses:
|
|
411
|
+
if clause.condition:
|
|
412
|
+
extend(scan_for_local_vars(clause.condition))
|
|
413
|
+
|
|
414
|
+
else:
|
|
415
|
+
# Generic expression node — walk for walrus operators, stopping at scope boundaries
|
|
416
|
+
if body.walk:
|
|
417
|
+
body.walk(new TreeWalker(def(node):
|
|
418
|
+
if is_node_type(node, AST_NamedExpr):
|
|
419
|
+
push(node.name.name)
|
|
420
|
+
if is_node_type(node, AST_Scope):
|
|
421
|
+
return True # prune: don't descend into inner function scopes
|
|
422
|
+
))
|
|
405
423
|
|
|
406
424
|
return localvars
|
|
407
425
|
|
|
@@ -550,7 +568,8 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
550
568
|
croak('Assignments in do loop conditions are not allowed')
|
|
551
569
|
semicolon()
|
|
552
570
|
return tmp
|
|
553
|
-
)()
|
|
571
|
+
)(),
|
|
572
|
+
'python_truthiness': S.scoped_flags.get('truthiness', False)
|
|
554
573
|
})
|
|
555
574
|
elif tmp_ is "while":
|
|
556
575
|
while_cond = expression(True)
|
|
@@ -558,9 +577,21 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
558
577
|
croak('Assignments in while loop conditions are not allowed')
|
|
559
578
|
if not is_('punc', ':'):
|
|
560
579
|
croak('Expected a colon after the while statement')
|
|
580
|
+
while_body = in_loop(statement)
|
|
581
|
+
while_belse = None
|
|
582
|
+
if is_("keyword", "else"):
|
|
583
|
+
start = S.token
|
|
584
|
+
next()
|
|
585
|
+
while_belse = new AST_Else({
|
|
586
|
+
'start': start,
|
|
587
|
+
'body': block_(),
|
|
588
|
+
'end': prev()
|
|
589
|
+
})
|
|
561
590
|
return new AST_While({
|
|
562
591
|
'condition': while_cond,
|
|
563
|
-
'body':
|
|
592
|
+
'body': while_body,
|
|
593
|
+
'belse': while_belse,
|
|
594
|
+
'python_truthiness': S.scoped_flags.get('truthiness', False)
|
|
564
595
|
})
|
|
565
596
|
elif tmp_ is "for":
|
|
566
597
|
if is_('js'):
|
|
@@ -622,7 +653,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
622
653
|
if is_('punc', ','):
|
|
623
654
|
next()
|
|
624
655
|
msg = expression(False)
|
|
625
|
-
return new AST_Assert({'start': start, 'condition':cond, 'message':msg, 'end':prev()})
|
|
656
|
+
return new AST_Assert({'start': start, 'condition':cond, 'message':msg, 'end':prev(), 'python_truthiness': S.scoped_flags.get('truthiness', False)})
|
|
626
657
|
elif tmp_ is "if":
|
|
627
658
|
return if_()
|
|
628
659
|
elif tmp_ is "pass":
|
|
@@ -647,10 +678,17 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
647
678
|
})
|
|
648
679
|
|
|
649
680
|
tmp = expression(True)
|
|
681
|
+
cause = None
|
|
682
|
+
if is_("keyword", "from"):
|
|
683
|
+
next()
|
|
684
|
+
cause = expression(True)
|
|
650
685
|
semicolon()
|
|
651
|
-
|
|
686
|
+
node = new AST_Throw({
|
|
652
687
|
'value': tmp
|
|
653
688
|
})
|
|
689
|
+
if cause is not None:
|
|
690
|
+
node.cause = cause
|
|
691
|
+
return node
|
|
654
692
|
elif tmp_ is "try":
|
|
655
693
|
return try_()
|
|
656
694
|
elif tmp_ is "nonlocal":
|
|
@@ -1116,11 +1154,22 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1116
1154
|
'object': obj
|
|
1117
1155
|
}
|
|
1118
1156
|
|
|
1157
|
+
body = in_loop(statement)
|
|
1158
|
+
belse = None
|
|
1159
|
+
if is_("keyword", "else"):
|
|
1160
|
+
start = S.token
|
|
1161
|
+
next()
|
|
1162
|
+
belse = new AST_Else({
|
|
1163
|
+
'start': start,
|
|
1164
|
+
'body': block_(),
|
|
1165
|
+
'end': prev()
|
|
1166
|
+
})
|
|
1119
1167
|
return new AST_ForIn({
|
|
1120
1168
|
'init': init,
|
|
1121
1169
|
'name': lhs,
|
|
1122
1170
|
'object': obj,
|
|
1123
|
-
'body':
|
|
1171
|
+
'body': body,
|
|
1172
|
+
'belse': belse
|
|
1124
1173
|
})
|
|
1125
1174
|
|
|
1126
1175
|
# A native JavaScript for loop - for v"var i=0; i<5000; i++":
|
|
@@ -1865,7 +1914,8 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1865
1914
|
return new AST_If({
|
|
1866
1915
|
'condition': cond,
|
|
1867
1916
|
'body': body,
|
|
1868
|
-
'alternative': belse
|
|
1917
|
+
'alternative': belse,
|
|
1918
|
+
'python_truthiness': S.scoped_flags.get('truthiness', False)
|
|
1869
1919
|
})
|
|
1870
1920
|
|
|
1871
1921
|
def is_docstring(stmt):
|
|
@@ -1917,10 +1967,19 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1917
1967
|
next()
|
|
1918
1968
|
exceptions = []
|
|
1919
1969
|
if not is_("punc", ":") and not is_("keyword", "as"):
|
|
1970
|
+
# Accept both: except TypeError, ValueError:
|
|
1971
|
+
# and: except (TypeError, ValueError):
|
|
1972
|
+
paren_wrapped = is_("punc", "(")
|
|
1973
|
+
if paren_wrapped:
|
|
1974
|
+
next()
|
|
1920
1975
|
exceptions.push(as_symbol(AST_SymbolVar))
|
|
1921
1976
|
while is_("punc", ","):
|
|
1922
1977
|
next()
|
|
1978
|
+
if paren_wrapped and is_("punc", ")"):
|
|
1979
|
+
break # trailing comma inside parens
|
|
1923
1980
|
exceptions.push(as_symbol(AST_SymbolVar))
|
|
1981
|
+
if paren_wrapped:
|
|
1982
|
+
expect(")")
|
|
1924
1983
|
|
|
1925
1984
|
name = None
|
|
1926
1985
|
if is_("keyword", "as"):
|
|
@@ -2670,7 +2729,8 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2670
2729
|
'start': start,
|
|
2671
2730
|
'expression': expr,
|
|
2672
2731
|
'args': func_call_list(),
|
|
2673
|
-
'end': prev()
|
|
2732
|
+
'end': prev(),
|
|
2733
|
+
'python_truthiness': S.scoped_flags.get('truthiness', False) and is_node_type(expr, AST_SymbolRef)
|
|
2674
2734
|
}), True)
|
|
2675
2735
|
S.in_parenthesized_expr = False
|
|
2676
2736
|
return ret
|
|
@@ -2760,6 +2820,8 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2760
2820
|
ex.end = prev()
|
|
2761
2821
|
if S.scoped_flags.get('overload_operators', False) and (start.value is '-' or start.value is '+' or start.value is '~'):
|
|
2762
2822
|
ex.overloaded = True
|
|
2823
|
+
if S.scoped_flags.get('truthiness', False) and start.value is '!':
|
|
2824
|
+
ex.python_truthiness = True
|
|
2763
2825
|
return ex
|
|
2764
2826
|
|
|
2765
2827
|
val = expr_atom(allow_calls)
|
|
@@ -2795,7 +2857,8 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2795
2857
|
'operator': op,
|
|
2796
2858
|
'right': right,
|
|
2797
2859
|
'end': right.end,
|
|
2798
|
-
'overloaded': S.scoped_flags.get('overload_operators', False)
|
|
2860
|
+
'overloaded': S.scoped_flags.get('overload_operators', False),
|
|
2861
|
+
'python_truthiness': S.scoped_flags.get('truthiness', False) and (op is '&&' or op is '||')
|
|
2799
2862
|
})
|
|
2800
2863
|
return expr_op(ret, min_prec, no_in)
|
|
2801
2864
|
return left
|
|
@@ -2815,7 +2878,8 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
2815
2878
|
'condition': ne,
|
|
2816
2879
|
'consequent': expr,
|
|
2817
2880
|
'alternative': expression(False, no_in),
|
|
2818
|
-
'end': peek()
|
|
2881
|
+
'end': peek(),
|
|
2882
|
+
'python_truthiness': S.scoped_flags.get('truthiness', False)
|
|
2819
2883
|
})
|
|
2820
2884
|
return conditional
|
|
2821
2885
|
return expr
|