diff --git a/graalpython/com.oracle.graal.python.pegparser.generator/asdl/asdl_java.py b/graalpython/com.oracle.graal.python.pegparser.generator/asdl/asdl_java.py index 65c807a5ff..7ac014e702 100755 --- a/graalpython/com.oracle.graal.python.pegparser.generator/asdl/asdl_java.py +++ b/graalpython/com.oracle.graal.python.pegparser.generator/asdl/asdl_java.py @@ -99,7 +99,8 @@ def generate_sst_node(emitter: java_file.Emitter, c: model.ConcreteClass): # fields for f in c.fields: comment = ' // nullable' if f.is_nullable else '' - emitter.println(f'public final {f.type.java} {f.name.java};{comment}') + final = '' if f.type.python == 'expr' and not f.is_sequence else 'final ' + emitter.println(f'public {final}{f.type.java} {f.name.java};{comment}') # constructor ctor_args = ', '.join(f'{f.type.java} {f.name.java}' for f in c.fields) with emitter.define(f'public {c.name.java}({ctor_args}{", " if ctor_args else ""}SourceRange sourceRange)'): diff --git a/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/sst/ArgTy.java b/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/sst/ArgTy.java index cd8424278d..b714986361 100644 --- a/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/sst/ArgTy.java +++ b/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/sst/ArgTy.java @@ -49,7 +49,7 @@ public final class ArgTy extends SSTNode { public final String arg; - public final ExprTy annotation; // nullable + public ExprTy annotation; // nullable public final Object typeComment; // nullable public ArgTy(String arg, ExprTy annotation, Object typeComment, SourceRange sourceRange) { diff --git a/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/sst/ComprehensionTy.java b/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/sst/ComprehensionTy.java index 20dadbcb5a..c72e03793b 100644 --- a/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/sst/ComprehensionTy.java +++ b/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/sst/ComprehensionTy.java @@ -48,8 +48,8 @@ import com.oracle.graal.python.pegparser.tokenizer.SourceRange; public final class ComprehensionTy extends SSTNode { - public final ExprTy target; - public final ExprTy iter; + public ExprTy target; + public ExprTy iter; public final ExprTy[] ifs; // nullable public final boolean isAsync; diff --git a/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/sst/ConstantValue.java b/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/sst/ConstantValue.java index 389d955be9..8f1f5f210f 100644 --- a/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/sst/ConstantValue.java +++ b/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/sst/ConstantValue.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -142,56 +142,6 @@ public static ConstantValue ofDouble(double v) { return new ConstantValue(v, Kind.DOUBLE); } - public ConstantValue addComplex(ConstantValue right) { - assert right.kind == Kind.COMPLEX; - double ld = toDouble(); - double[] rd = right.getComplex(); - return ofComplex(ld + rd[0], rd[1]); - } - - public ConstantValue subComplex(ConstantValue right) { - assert right.kind == Kind.COMPLEX; - double ld = toDouble(); - double[] rd = right.getComplex(); - return ofComplex(ld - rd[0], -rd[1]); - } - - private double toDouble() { - assert kind == Kind.BIGINTEGER || kind == Kind.DOUBLE || kind == Kind.LONG : kind; - switch (kind) { - case BIGINTEGER: - return getBigInteger().doubleValue(); - case DOUBLE: - return getDouble(); - case LONG: - return getLong(); - default: - throw new IllegalStateException("should not reach here"); - } - } - - public ConstantValue negate() { - assert kind == Kind.BIGINTEGER || kind == Kind.DOUBLE || kind == Kind.LONG || kind == Kind.COMPLEX : kind; - switch (kind) { - case BIGINTEGER: - return ofBigInteger(getBigInteger().negate()); - case DOUBLE: - return ofDouble(-getDouble()); - case LONG: - long v = getLong(); - if (v != Long.MIN_VALUE) { - return ofLong(-v); - } else { - return ofBigInteger(BigInteger.valueOf(v).negate()); - } - case COMPLEX: - double[] complex = getComplex(); - return ofComplex(-complex[0], -complex[1]); - default: - throw new IllegalStateException("should not reach here"); - } - } - public static ConstantValue ofLong(long v) { if (v >= CACHED_MIN && v <= CACHED_MAX) { return CACHED_LONGS[(int) (v - CACHED_MIN)]; diff --git a/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/sst/ExceptHandlerTy.java b/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/sst/ExceptHandlerTy.java index 1b8f05a1cd..f7f475ee38 100644 --- a/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/sst/ExceptHandlerTy.java +++ b/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/sst/ExceptHandlerTy.java @@ -54,7 +54,7 @@ public abstract class ExceptHandlerTy extends SSTNode { } public static final class ExceptHandler extends ExceptHandlerTy { - public final ExprTy type; // nullable + public ExprTy type; // nullable public final String name; // nullable public final StmtTy[] body; // nullable diff --git a/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/sst/ExprTy.java b/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/sst/ExprTy.java index ffce004cde..6e3e3771a4 100644 --- a/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/sst/ExprTy.java +++ b/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/sst/ExprTy.java @@ -71,8 +71,8 @@ public T accept(SSTreeVisitor visitor) { } public static final class NamedExpr extends ExprTy { - public final ExprTy target; - public final ExprTy value; + public ExprTy target; + public ExprTy value; public NamedExpr(ExprTy target, ExprTy value, SourceRange sourceRange) { super(sourceRange); @@ -89,9 +89,9 @@ public T accept(SSTreeVisitor visitor) { } public static final class BinOp extends ExprTy { - public final ExprTy left; + public ExprTy left; public final OperatorTy op; - public final ExprTy right; + public ExprTy right; public BinOp(ExprTy left, OperatorTy op, ExprTy right, SourceRange sourceRange) { super(sourceRange); @@ -111,7 +111,7 @@ public T accept(SSTreeVisitor visitor) { public static final class UnaryOp extends ExprTy { public final UnaryOpTy op; - public final ExprTy operand; + public ExprTy operand; public UnaryOp(UnaryOpTy op, ExprTy operand, SourceRange sourceRange) { super(sourceRange); @@ -129,7 +129,7 @@ public T accept(SSTreeVisitor visitor) { public static final class Lambda extends ExprTy { public final ArgumentsTy args; - public final ExprTy body; + public ExprTy body; public Lambda(ArgumentsTy args, ExprTy body, SourceRange sourceRange) { super(sourceRange); @@ -146,9 +146,9 @@ public T accept(SSTreeVisitor visitor) { } public static final class IfExp extends ExprTy { - public final ExprTy test; - public final ExprTy body; - public final ExprTy orElse; + public ExprTy test; + public ExprTy body; + public ExprTy orElse; public IfExp(ExprTy test, ExprTy body, ExprTy orElse, SourceRange sourceRange) { super(sourceRange); @@ -197,7 +197,7 @@ public T accept(SSTreeVisitor visitor) { } public static final class ListComp extends ExprTy { - public final ExprTy element; + public ExprTy element; public final ComprehensionTy[] generators; // nullable public ListComp(ExprTy element, ComprehensionTy[] generators, SourceRange sourceRange) { @@ -214,7 +214,7 @@ public T accept(SSTreeVisitor visitor) { } public static final class SetComp extends ExprTy { - public final ExprTy element; + public ExprTy element; public final ComprehensionTy[] generators; // nullable public SetComp(ExprTy element, ComprehensionTy[] generators, SourceRange sourceRange) { @@ -231,8 +231,8 @@ public T accept(SSTreeVisitor visitor) { } public static final class DictComp extends ExprTy { - public final ExprTy key; - public final ExprTy value; + public ExprTy key; + public ExprTy value; public final ComprehensionTy[] generators; // nullable public DictComp(ExprTy key, ExprTy value, ComprehensionTy[] generators, SourceRange sourceRange) { @@ -251,7 +251,7 @@ public T accept(SSTreeVisitor visitor) { } public static final class GeneratorExp extends ExprTy { - public final ExprTy element; + public ExprTy element; public final ComprehensionTy[] generators; // nullable public GeneratorExp(ExprTy element, ComprehensionTy[] generators, SourceRange sourceRange) { @@ -268,7 +268,7 @@ public T accept(SSTreeVisitor visitor) { } public static final class Await extends ExprTy { - public final ExprTy value; + public ExprTy value; public Await(ExprTy value, SourceRange sourceRange) { super(sourceRange); @@ -283,7 +283,7 @@ public T accept(SSTreeVisitor visitor) { } public static final class Yield extends ExprTy { - public final ExprTy value; // nullable + public ExprTy value; // nullable public Yield(ExprTy value, SourceRange sourceRange) { super(sourceRange); @@ -297,7 +297,7 @@ public T accept(SSTreeVisitor visitor) { } public static final class YieldFrom extends ExprTy { - public final ExprTy value; + public ExprTy value; public YieldFrom(ExprTy value, SourceRange sourceRange) { super(sourceRange); @@ -312,7 +312,7 @@ public T accept(SSTreeVisitor visitor) { } public static final class Compare extends ExprTy { - public final ExprTy left; + public ExprTy left; public final CmpOpTy[] ops; // nullable public final ExprTy[] comparators; // nullable @@ -331,7 +331,7 @@ public T accept(SSTreeVisitor visitor) { } public static final class Call extends ExprTy { - public final ExprTy func; + public ExprTy func; public final ExprTy[] args; // nullable public final KeywordTy[] keywords; // nullable @@ -350,9 +350,9 @@ public T accept(SSTreeVisitor visitor) { } public static final class FormattedValue extends ExprTy { - public final ExprTy value; + public ExprTy value; public final int conversion; - public final ExprTy formatSpec; // nullable + public ExprTy formatSpec; // nullable public FormattedValue(ExprTy value, int conversion, ExprTy formatSpec, SourceRange sourceRange) { super(sourceRange); @@ -400,7 +400,7 @@ public T accept(SSTreeVisitor visitor) { } public static final class Attribute extends ExprTy { - public final ExprTy value; + public ExprTy value; public final String attr; public final ExprContextTy context; @@ -421,8 +421,8 @@ public T accept(SSTreeVisitor visitor) { } public static final class Subscript extends ExprTy { - public final ExprTy value; - public final ExprTy slice; + public ExprTy value; + public ExprTy slice; public final ExprContextTy context; public Subscript(ExprTy value, ExprTy slice, ExprContextTy context, SourceRange sourceRange) { @@ -442,7 +442,7 @@ public T accept(SSTreeVisitor visitor) { } public static final class Starred extends ExprTy { - public final ExprTy value; + public ExprTy value; public final ExprContextTy context; public Starred(ExprTy value, ExprContextTy context, SourceRange sourceRange) { @@ -512,9 +512,9 @@ public T accept(SSTreeVisitor visitor) { } public static final class Slice extends ExprTy { - public final ExprTy lower; // nullable - public final ExprTy upper; // nullable - public final ExprTy step; // nullable + public ExprTy lower; // nullable + public ExprTy upper; // nullable + public ExprTy step; // nullable public Slice(ExprTy lower, ExprTy upper, ExprTy step, SourceRange sourceRange) { super(sourceRange); diff --git a/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/sst/KeywordTy.java b/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/sst/KeywordTy.java index 3e3fbc736c..93e1202db7 100644 --- a/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/sst/KeywordTy.java +++ b/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/sst/KeywordTy.java @@ -49,7 +49,7 @@ public final class KeywordTy extends SSTNode { public final String arg; // nullable - public final ExprTy value; + public ExprTy value; public KeywordTy(String arg, ExprTy value, SourceRange sourceRange) { super(sourceRange); diff --git a/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/sst/MatchCaseTy.java b/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/sst/MatchCaseTy.java index ae95ba1287..4cb439f035 100644 --- a/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/sst/MatchCaseTy.java +++ b/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/sst/MatchCaseTy.java @@ -49,7 +49,7 @@ public final class MatchCaseTy extends SSTNode { public final PatternTy pattern; - public final ExprTy guard; // nullable + public ExprTy guard; // nullable public final StmtTy[] body; // nullable public MatchCaseTy(PatternTy pattern, ExprTy guard, StmtTy[] body, SourceRange sourceRange) { diff --git a/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/sst/ModTy.java b/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/sst/ModTy.java index 732e480a2d..f2b2855bb4 100644 --- a/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/sst/ModTy.java +++ b/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/sst/ModTy.java @@ -84,7 +84,7 @@ public T accept(SSTreeVisitor visitor) { } public static final class Expression extends ModTy { - public final ExprTy body; + public ExprTy body; public Expression(ExprTy body, SourceRange sourceRange) { super(sourceRange); @@ -100,7 +100,7 @@ public T accept(SSTreeVisitor visitor) { public static final class FunctionType extends ModTy { public final ExprTy[] argTypes; // nullable - public final ExprTy returns; + public ExprTy returns; public FunctionType(ExprTy[] argTypes, ExprTy returns, SourceRange sourceRange) { super(sourceRange); diff --git a/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/sst/PatternTy.java b/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/sst/PatternTy.java index ec48d65cda..1dda51186d 100644 --- a/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/sst/PatternTy.java +++ b/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/sst/PatternTy.java @@ -54,7 +54,7 @@ public abstract class PatternTy extends SSTNode { } public static final class MatchValue extends PatternTy { - public final ExprTy value; + public ExprTy value; public MatchValue(ExprTy value, SourceRange sourceRange) { super(sourceRange); @@ -116,7 +116,7 @@ public T accept(SSTreeVisitor visitor) { } public static final class MatchClass extends PatternTy { - public final ExprTy cls; + public ExprTy cls; public final PatternTy[] patterns; // nullable public final String[] kwdAttrs; // nullable public final PatternTy[] kwdPatterns; // nullable diff --git a/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/sst/StmtTy.java b/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/sst/StmtTy.java index dd6c1e1839..bb12ec1138 100644 --- a/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/sst/StmtTy.java +++ b/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/sst/StmtTy.java @@ -58,7 +58,7 @@ public static final class FunctionDef extends StmtTy { public final ArgumentsTy args; public final StmtTy[] body; // nullable public final ExprTy[] decoratorList; // nullable - public final ExprTy returns; // nullable + public ExprTy returns; // nullable public final Object typeComment; // nullable public final TypeParamTy[] typeParams; // nullable @@ -90,7 +90,7 @@ public static final class AsyncFunctionDef extends StmtTy { public final ArgumentsTy args; public final StmtTy[] body; // nullable public final ExprTy[] decoratorList; // nullable - public final ExprTy returns; // nullable + public ExprTy returns; // nullable public final Object typeComment; // nullable public final TypeParamTy[] typeParams; // nullable @@ -147,7 +147,7 @@ public T accept(SSTreeVisitor visitor) { } public static final class Return extends StmtTy { - public final ExprTy value; // nullable + public ExprTy value; // nullable public Return(ExprTy value, SourceRange sourceRange) { super(sourceRange); @@ -176,7 +176,7 @@ public T accept(SSTreeVisitor visitor) { public static final class Assign extends StmtTy { public final ExprTy[] targets; // nullable - public final ExprTy value; + public ExprTy value; public final Object typeComment; // nullable public Assign(ExprTy[] targets, ExprTy value, Object typeComment, SourceRange sourceRange) { @@ -194,9 +194,9 @@ public T accept(SSTreeVisitor visitor) { } public static final class TypeAlias extends StmtTy { - public final ExprTy name; + public ExprTy name; public final TypeParamTy[] typeParams; // nullable - public final ExprTy value; + public ExprTy value; public TypeAlias(ExprTy name, TypeParamTy[] typeParams, ExprTy value, SourceRange sourceRange) { super(sourceRange); @@ -218,9 +218,9 @@ public T accept(SSTreeVisitor visitor) { } public static final class AugAssign extends StmtTy { - public final ExprTy target; + public ExprTy target; public final OperatorTy op; - public final ExprTy value; + public ExprTy value; public AugAssign(ExprTy target, OperatorTy op, ExprTy value, SourceRange sourceRange) { super(sourceRange); @@ -239,9 +239,9 @@ public T accept(SSTreeVisitor visitor) { } public static final class AnnAssign extends StmtTy { - public final ExprTy target; - public final ExprTy annotation; - public final ExprTy value; // nullable + public ExprTy target; + public ExprTy annotation; + public ExprTy value; // nullable public final boolean isSimple; public AnnAssign(ExprTy target, ExprTy annotation, ExprTy value, boolean isSimple, SourceRange sourceRange) { @@ -261,8 +261,8 @@ public T accept(SSTreeVisitor visitor) { } public static final class For extends StmtTy { - public final ExprTy target; - public final ExprTy iter; + public ExprTy target; + public ExprTy iter; public final StmtTy[] body; // nullable public final StmtTy[] orElse; // nullable public final Object typeComment; // nullable @@ -285,8 +285,8 @@ public T accept(SSTreeVisitor visitor) { } public static final class AsyncFor extends StmtTy { - public final ExprTy target; - public final ExprTy iter; + public ExprTy target; + public ExprTy iter; public final StmtTy[] body; // nullable public final StmtTy[] orElse; // nullable public final Object typeComment; // nullable @@ -309,7 +309,7 @@ public T accept(SSTreeVisitor visitor) { } public static final class While extends StmtTy { - public final ExprTy test; + public ExprTy test; public final StmtTy[] body; // nullable public final StmtTy[] orElse; // nullable @@ -328,7 +328,7 @@ public T accept(SSTreeVisitor visitor) { } public static final class If extends StmtTy { - public final ExprTy test; + public ExprTy test; public final StmtTy[] body; // nullable public final StmtTy[] orElse; // nullable @@ -383,7 +383,7 @@ public T accept(SSTreeVisitor visitor) { } public static final class Match extends StmtTy { - public final ExprTy subject; + public ExprTy subject; public final MatchCaseTy[] cases; // nullable public Match(ExprTy subject, MatchCaseTy[] cases, SourceRange sourceRange) { @@ -400,8 +400,8 @@ public T accept(SSTreeVisitor visitor) { } public static final class Raise extends StmtTy { - public final ExprTy exc; // nullable - public final ExprTy cause; // nullable + public ExprTy exc; // nullable + public ExprTy cause; // nullable public Raise(ExprTy exc, ExprTy cause, SourceRange sourceRange) { super(sourceRange); @@ -456,8 +456,8 @@ public T accept(SSTreeVisitor visitor) { } public static final class Assert extends StmtTy { - public final ExprTy test; - public final ExprTy msg; // nullable + public ExprTy test; + public ExprTy msg; // nullable public Assert(ExprTy test, ExprTy msg, SourceRange sourceRange) { super(sourceRange); @@ -533,7 +533,7 @@ public T accept(SSTreeVisitor visitor) { } public static final class Expr extends StmtTy { - public final ExprTy value; + public ExprTy value; public Expr(ExprTy value, SourceRange sourceRange) { super(sourceRange); diff --git a/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/sst/TypeParamTy.java b/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/sst/TypeParamTy.java index 7d217b12a3..38cc844414 100644 --- a/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/sst/TypeParamTy.java +++ b/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/sst/TypeParamTy.java @@ -55,8 +55,8 @@ public abstract class TypeParamTy extends SSTNode { public static final class TypeVar extends TypeParamTy { public final String name; - public final ExprTy bound; // nullable - public final ExprTy defaultValue; // nullable + public ExprTy bound; // nullable + public ExprTy defaultValue; // nullable public TypeVar(String name, ExprTy bound, ExprTy defaultValue, SourceRange sourceRange) { super(sourceRange); @@ -74,7 +74,7 @@ public T accept(SSTreeVisitor visitor) { public static final class ParamSpec extends TypeParamTy { public final String name; - public final ExprTy defaultValue; // nullable + public ExprTy defaultValue; // nullable public ParamSpec(String name, ExprTy defaultValue, SourceRange sourceRange) { super(sourceRange); @@ -91,7 +91,7 @@ public T accept(SSTreeVisitor visitor) { public static final class TypeVarTuple extends TypeParamTy { public final String name; - public final ExprTy defaultValue; // nullable + public ExprTy defaultValue; // nullable public TypeVarTuple(String name, ExprTy defaultValue, SourceRange sourceRange) { super(sourceRange); diff --git a/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/sst/WithItemTy.java b/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/sst/WithItemTy.java index 75b4f19709..402dcc1790 100644 --- a/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/sst/WithItemTy.java +++ b/graalpython/com.oracle.graal.python.pegparser/src/com/oracle/graal/python/pegparser/sst/WithItemTy.java @@ -48,8 +48,8 @@ import com.oracle.graal.python.pegparser.tokenizer.SourceRange; public final class WithItemTy extends SSTNode { - public final ExprTy contextExpr; - public final ExprTy optionalVars; // nullable + public ExprTy contextExpr; + public ExprTy optionalVars; // nullable public WithItemTy(ExprTy contextExpr, ExprTy optionalVars, SourceRange sourceRange) { super(sourceRange); diff --git a/graalpython/com.oracle.graal.python.test/src/tests/test_parser.py b/graalpython/com.oracle.graal.python.test/src/tests/test_parser.py index 044285e870..48c488a552 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/test_parser.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/test_parser.py @@ -38,6 +38,7 @@ # SOFTWARE. +import ast import types @@ -715,6 +716,52 @@ def check_doc(code, doc): code2 = compile(codestr2, "", "exec", optimize=2) check(code2, 2) + +def test_optimized_ast(): + raw = compile("a * (1 + 2)", "", "exec", flags=ast.PyCF_ONLY_AST) + optimized = compile("a * (1 + 2)", "", "exec", flags=ast.PyCF_OPTIMIZED_AST) + optimized_from_ast = compile(raw, "", "exec", flags=ast.PyCF_OPTIMIZED_AST) + + assert isinstance(raw.body[0].value.right, ast.BinOp) + for tree in (optimized, optimized_from_ast): + assert isinstance(tree.body[0].value.right, ast.Constant) + assert tree.body[0].value.right.value == 3 + + assert compile(raw, "", "exec", flags=ast.PyCF_ONLY_AST) is raw + assert isinstance(ast.parse("__debug__", optimize=0).body[0].value, ast.Name) + assert ast.parse("__debug__", optimize=1).body[0].value.value is False + nested = ast.parse("lambda x=1 + 2: f(3 + 4)", optimize=1).body[0].value + assert nested.args.defaults[0].value == 3 + assert nested.body.args[0].value == 7 + future_tree = compile( + "from __future__ import annotations\nx: 1 + 2", + "", + "exec", + flags=ast.PyCF_OPTIMIZED_AST, + optimize=1, + ) + assert isinstance(future_tree.body[1].annotation, ast.BinOp) + + +def test_ast_optimizer_code_generation(): + code = compile("result = '%s' % (value,)", "", "exec") + assert "%s" not in code.co_consts + namespace = {"value": "optimized"} + exec(code, namespace) + assert namespace["result"] == "optimized" + assert eval(compile("__debug__", "", "eval", optimize=1)) is False + + +def test_ast_optimizer_preserves_future_annotations(): + namespace = {} + exec("""from __future__ import annotations +x: 1 + 2 +def f(a: 1 + 2) -> 1 + 2: pass +""", namespace) + assert namespace["__annotations__"] == {"x": "1 + 2"} + assert namespace["f"].__annotations__ == {"a": "1 + 2", "return": "1 + 2"} + + def test_optimize_doc(): codestr = ''' diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/PythonLanguage.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/PythonLanguage.java index bf1b9f9063..8de2783999 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/PythonLanguage.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/PythonLanguage.java @@ -628,7 +628,8 @@ public RootCallTarget compileModule(PythonContext context, ModTy modIn, Source s mod = modIn; } - RootNode rootNode = compileForBytecodeDSLInterpreter(mod, source, optimize, errorCb, futureFeatures); + int resolvedOptimize = optimize >= 0 ? optimize : getEngineOption(PythonOptions.PythonOptimizeFlag) ? 1 : 0; + RootNode rootNode = compileForBytecodeDSLInterpreter(mod, source, resolvedOptimize, errorCb, futureFeatures); if (topLevel) { GilNode gil = GilNode.getUncached(); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/BuiltinFunctions.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/BuiltinFunctions.java index f9655c9369..4c56340692 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/BuiltinFunctions.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/BuiltinFunctions.java @@ -167,6 +167,7 @@ import com.oracle.graal.python.builtins.objects.type.TypeNodes.IsTypeNode; import com.oracle.graal.python.builtins.objects.type.slots.TpSlotIterNext.CallSlotTpIterNextNode; import com.oracle.graal.python.builtins.objects.type.slots.TpSlotUnaryFunc.CallSlotUnaryNode; +import com.oracle.graal.python.compiler.AstOptimizer; import com.oracle.graal.python.compiler.ParserCallbacksImpl; import com.oracle.graal.python.compiler.bytecode_dsl.BytecodeDSLCompiler; import com.oracle.graal.python.lib.IteratorExhausted; @@ -343,7 +344,7 @@ public void initialize(Python3Core core) { public void postInitialize(Python3Core core) { super.postInitialize(core); PythonModule builtinsModule = core.lookupBuiltinModule(BuiltinNames.T_BUILTINS); - builtinsModule.setAttribute(T___DEBUG__, !core.getContext().getOption(PythonOptions.PythonOptimizeFlag)); + builtinsModule.setAttribute(T___DEBUG__, !core.getLanguage().getEngineOption(PythonOptions.PythonOptimizeFlag)); } // abs(x) @@ -955,7 +956,9 @@ public abstract static class CompileNode extends PythonClinicBuiltinNode { public static final int PyCF_TYPE_COMMENTS = 0x1000; public static final int PyCF_ALLOW_TOP_LEVEL_AWAIT = 0x2000; private static final int PyCF_ALLOW_INCOMPLETE_INPUT = 0x4000; - private static final int PyCF_COMPILE_MASK = PyCF_ONLY_AST | PyCF_ALLOW_TOP_LEVEL_AWAIT | PyCF_TYPE_COMMENTS | PyCF_DONT_IMPLY_DEDENT | PyCF_ALLOW_INCOMPLETE_INPUT; + public static final int PyCF_OPTIMIZED_AST = 0x8000 | PyCF_ONLY_AST; + private static final int PyCF_COMPILE_MASK = PyCF_ONLY_AST | PyCF_ALLOW_TOP_LEVEL_AWAIT | PyCF_TYPE_COMMENTS | PyCF_DONT_IMPLY_DEDENT | PyCF_ALLOW_INCOMPLETE_INPUT | + PyCF_OPTIMIZED_AST; /** * Decides whether this node should attempt to map the filename to a URI for the benefit of @@ -1045,6 +1048,10 @@ Object compile(TruffleString expression, TruffleString filename, TruffleString m Parser parser = BytecodeDSLCompiler.createParser(code.toJavaStringUncached(), parserCb, type, compilerFlags, featureVersion); ModTy mod = (ModTy) parser.parse(); parserCb.triggerDeprecationWarnings(); + int astOptimizationLevel = (flags & PyCF_OPTIMIZED_AST) == PyCF_OPTIMIZED_AST ? resolveOptimizeLevel(context, optimize) : -2; + if (astOptimizationLevel >= 0) { + AstOptimizer.optimize(mod, astOptimizationLevel, (flags & FutureFeature.ANNOTATIONS.flagValue) != 0); + } return AstModuleBuiltins.sst2Obj(getContext(), mod); } CallTarget ct; @@ -1087,11 +1094,20 @@ Object generic(VirtualFrame frame, Object wSource, Object wFilename, TruffleStri if (!dontInherit) { flags = inheritFlags(frame, flags, readCallerFrame); } + checkFlags(flags); + checkOptimize(optimize, optimize); Object saved = BoundaryCallContext.enter(frame, boundaryCallData); try { if (AstModuleBuiltins.isAst(context, wSource)) { ModTy mod = AstModuleBuiltins.obj2sst(inliningTarget, context, wSource, getParserInputType(mode, flags)); + if ((flags & PyCF_ONLY_AST) != 0) { + if ((flags & PyCF_OPTIMIZED_AST) != PyCF_OPTIMIZED_AST) { + return wSource; + } + AstOptimizer.optimize(mod, resolveOptimizeLevel(context, optimize), (flags & FutureFeature.ANNOTATIONS.flagValue) != 0); + return AstModuleBuiltins.sst2Obj(context, mod); + } Source source = PythonUtils.createFakeSource(filename); RootCallTarget rootCallTarget = context.getLanguage(inliningTarget).compileModule(context, mod, source, false, optimize, null, null, flags); return wrapRootCallTarget(rootCallTarget, filename); @@ -1112,6 +1128,13 @@ private static PCode wrapRootCallTarget(RootCallTarget rootCallTarget, TruffleSt return PFactory.createCode(PythonLanguage.get(null), rootCallTarget, filename); } + private static int resolveOptimizeLevel(PythonContext context, int optimize) { + if (optimize >= 0) { + return optimize; + } + return context.getLanguage().getEngineOption(PythonOptions.PythonOptimizeFlag) ? 1 : 0; + } + @TruffleBoundary private void checkSource(TruffleString source) throws PException { if (source.indexOfCodePointUncached(0, 0, source.codePointLengthUncached(TS_ENCODING), TS_ENCODING) > -1) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java index f0c5813458..efe8b8309a 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java @@ -681,10 +681,10 @@ public void postInitialize0(Python3Core core) { PList sysPaths = PFactory.createList(language, path); sys.setAttribute(tsInternedLiteral("path"), sysPaths); sys.setAttribute(tsInternedLiteral("flags"), PFactory.createStructSeq(language, SysModuleBuiltins.FLAGS_DESC, - PInt.intValue(!context.getOption(PythonOptions.PythonOptimizeFlag)), // debug + PInt.intValue(!language.getEngineOption(PythonOptions.PythonOptimizeFlag)), // debug PInt.intValue(context.getOption(PythonOptions.InspectFlag)), // inspect PInt.intValue(context.getOption(PythonOptions.TerminalIsInteractive)), // interactive - PInt.intValue(context.getOption(PythonOptions.PythonOptimizeFlag)), // optimize + PInt.intValue(language.getEngineOption(PythonOptions.PythonOptimizeFlag)), // optimize PInt.intValue(context.getOption(PythonOptions.DontWriteBytecodeFlag)), // dont_write_bytecode PInt.intValue(context.getOption(PythonOptions.NoUserSiteFlag)), // no_user_site PInt.intValue(context.getOption(PythonOptions.NoSiteFlag)), // no_site diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ast/AstModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ast/AstModuleBuiltins.java index 32d5f6218b..a5dbc3d6e6 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ast/AstModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ast/AstModuleBuiltins.java @@ -42,6 +42,7 @@ import static com.oracle.graal.python.builtins.modules.BuiltinFunctions.CompileNode.PyCF_ALLOW_TOP_LEVEL_AWAIT; import static com.oracle.graal.python.builtins.modules.BuiltinFunctions.CompileNode.PyCF_ONLY_AST; +import static com.oracle.graal.python.builtins.modules.BuiltinFunctions.CompileNode.PyCF_OPTIMIZED_AST; import static com.oracle.graal.python.builtins.modules.BuiltinFunctions.CompileNode.PyCF_TYPE_COMMENTS; import static com.oracle.graal.python.nodes.ErrorMessages.EXPECTED_S_NODE_GOT_P; import static com.oracle.graal.python.nodes.SpecialAttributeNames.T___MATCH_ARGS__; @@ -89,6 +90,7 @@ protected List> getNodeFa public void initialize(Python3Core core) { super.initialize(core); addBuiltinConstant("PyCF_ONLY_AST", PyCF_ONLY_AST); + addBuiltinConstant("PyCF_OPTIMIZED_AST", PyCF_OPTIMIZED_AST); addBuiltinConstant("PyCF_TYPE_COMMENTS", PyCF_TYPE_COMMENTS); addBuiltinConstant("PyCF_ALLOW_TOP_LEVEL_AWAIT", PyCF_ALLOW_TOP_LEVEL_AWAIT); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/compiler/AstOptimizer.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/compiler/AstOptimizer.java new file mode 100644 index 0000000000..8000730858 --- /dev/null +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/compiler/AstOptimizer.java @@ -0,0 +1,539 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.oracle.graal.python.compiler; + +import java.math.BigInteger; +import java.util.Arrays; + +import com.oracle.graal.python.builtins.objects.PNone; +import com.oracle.graal.python.builtins.objects.bytes.PBytes; +import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes.ToArrayNode; +import com.oracle.graal.python.builtins.objects.complex.PComplex; +import com.oracle.graal.python.builtins.objects.ellipsis.PEllipsis; +import com.oracle.graal.python.builtins.objects.ints.PInt; +import com.oracle.graal.python.builtins.objects.tuple.PTuple; +import com.oracle.graal.python.compiler.bytecode_dsl.BaseBytecodeDSLVisitor; +import com.oracle.graal.python.lib.PyNumberAddNode; +import com.oracle.graal.python.lib.PyNumberAndNode; +import com.oracle.graal.python.lib.PyNumberFloorDivideNode; +import com.oracle.graal.python.lib.PyNumberInvertNode; +import com.oracle.graal.python.lib.PyNumberLshiftNode; +import com.oracle.graal.python.lib.PyNumberMultiplyNode; +import com.oracle.graal.python.lib.PyNumberNegativeNode; +import com.oracle.graal.python.lib.PyNumberOrNode; +import com.oracle.graal.python.lib.PyNumberPositiveNode; +import com.oracle.graal.python.lib.PyNumberPowerNode; +import com.oracle.graal.python.lib.PyNumberRemainderNode; +import com.oracle.graal.python.lib.PyNumberRshiftNode; +import com.oracle.graal.python.lib.PyNumberSubtractNode; +import com.oracle.graal.python.lib.PyNumberTrueDivideNode; +import com.oracle.graal.python.lib.PyNumberXorNode; +import com.oracle.graal.python.lib.PyObjectGetItem; +import com.oracle.graal.python.lib.PyObjectIsTrueNode; +import com.oracle.graal.python.pegparser.sst.ArgTy; +import com.oracle.graal.python.pegparser.sst.ArgumentsTy; +import com.oracle.graal.python.pegparser.sst.CmpOpTy; +import com.oracle.graal.python.pegparser.sst.ComprehensionTy; +import com.oracle.graal.python.pegparser.sst.ConstantValue; +import com.oracle.graal.python.pegparser.sst.ExprContextTy; +import com.oracle.graal.python.pegparser.sst.ExprTy; +import com.oracle.graal.python.pegparser.sst.ModTy; +import com.oracle.graal.python.pegparser.sst.OperatorTy; +import com.oracle.graal.python.pegparser.sst.SSTNode; +import com.oracle.graal.python.pegparser.sst.StmtTy; +import com.oracle.graal.python.pegparser.sst.TypeParamTy; +import com.oracle.graal.python.pegparser.sst.UnaryOpTy; +import com.oracle.graal.python.runtime.exception.PException; +import com.oracle.graal.python.runtime.sequence.storage.ByteSequenceStorage; +import com.oracle.graal.python.util.PythonUtils; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.strings.TruffleString; + +/** The common AST optimizer used before bytecode generation and for {@code PyCF_OPTIMIZED_AST}. */ +public final class AstOptimizer implements BaseBytecodeDSLVisitor { + private static final int MAX_INT_SIZE = 128; + private static final int MAX_COLLECTION_SIZE = 256; + + private final int optimizationLevel; + private final boolean futureAnnotations; + + private AstOptimizer(int optimizationLevel, boolean futureAnnotations) { + this.optimizationLevel = optimizationLevel; + this.futureAnnotations = futureAnnotations; + } + + @TruffleBoundary + public static void optimize(ModTy mod, int optimizationLevel, boolean futureAnnotations) { + mod.accept(new AstOptimizer(optimizationLevel, futureAnnotations || hasFutureAnnotations(mod))); + } + + @Override + public ExprTy defaultValue(SSTNode node) { + return node instanceof ExprTy expression ? expression : null; + } + + @Override + public ExprTy visitExpr(ExprTy node) { + return node == null ? null : node.accept(this); + } + + @Override + public ExprTy visit(ModTy.FunctionType node) { + return null; + } + + @Override + public ExprTy visit(ExprTy.Name node) { + if (node.context == ExprContextTy.Load && node.id.equals("__debug__")) { + return constant(node, ConstantValue.ofBoolean(optimizationLevel == 0)); + } + return node; + } + + @Override + public ExprTy visit(ExprTy.BinOp node) { + ExprTy optimizedFormat = tryOptimizeFormat(node); + if (optimizedFormat != null) { + return visitExpr(optimizedFormat); + } + BaseBytecodeDSLVisitor.super.visit(node); + ConstantValue left = getConstant(node.left); + ConstantValue right = getConstant(node.right); + if (left != null && right != null) { + try { + Object leftObject = PythonUtils.pythonObjectFromConstantValue(left); + Object rightObject = PythonUtils.pythonObjectFromConstantValue(right); + Object result = foldBinOp(node.op, leftObject, rightObject); + ConstantValue value = asConstantValue(result); + if (value != null) { + return constant(node, value); + } + } catch (PException e) { + // CPython ignores ordinary errors raised while attempting constant folding. + } + } + return node; + } + + @Override + public ExprTy visit(ExprTy.UnaryOp node) { + BaseBytecodeDSLVisitor.super.visit(node); + if (node.op == UnaryOpTy.Not && node.operand instanceof ExprTy.Compare compare && compare.ops.length == 1) { + CmpOpTy inverted = invertComparison(compare.ops[0]); + if (inverted != null) { + return new ExprTy.Compare(compare.left, new CmpOpTy[]{inverted}, compare.comparators, compare.getSourceRange()); + } + } + ConstantValue operand = getConstant(node.operand); + if (operand != null) { + try { + Object result = foldUnaryOp(node.op, PythonUtils.pythonObjectFromConstantValue(operand)); + ConstantValue value = asConstantValue(result); + if (value != null) { + return constant(node, value); + } + } catch (PException e) { + // See visit(BinOp). + } + } + return node; + } + + @Override + public ExprTy visit(ExprTy.Tuple node) { + BaseBytecodeDSLVisitor.super.visit(node); + if (node.context == ExprContextTy.Load) { + ConstantValue[] values = constantElements(node.elements); + if (values != null) { + return constant(node, ConstantValue.ofTuple(values)); + } + } + return node; + } + + @Override + public ExprTy visit(ExprTy.Subscript node) { + BaseBytecodeDSLVisitor.super.visit(node); + ConstantValue value = getConstant(node.value); + ConstantValue slice = getConstant(node.slice); + if (node.context == ExprContextTy.Load && value != null && slice != null) { + try { + Object result = PyObjectGetItem.getUncached().execute(null, null, PythonUtils.pythonObjectFromConstantValue(value), PythonUtils.pythonObjectFromConstantValue(slice)); + ConstantValue constant = asConstantValue(result); + if (constant != null) { + return constant(node, constant); + } + } catch (PException e) { + // See visit(BinOp). + } + } + return node; + } + + @Override + public ExprTy visit(ExprTy.Compare node) { + BaseBytecodeDSLVisitor.super.visit(node); + if (node.ops.length > 0 && (node.ops[node.ops.length - 1] == CmpOpTy.In || node.ops[node.ops.length - 1] == CmpOpTy.NotIn)) { + int last = node.comparators.length - 1; + node.comparators[last] = optimizeIterable(node.comparators[last]); + } + return node; + } + + @Override + public ExprTy visit(StmtTy.For node) { + BaseBytecodeDSLVisitor.super.visit(node); + node.iter = optimizeIterable(node.iter); + return null; + } + + @Override + public ExprTy visit(StmtTy.FunctionDef node) { + visitSequence(node.typeParams); + visitNode(node.args); + visitSequence(node.body); + visitSequence(node.decoratorList); + if (!futureAnnotations) { + node.returns = visitExpr(node.returns); + } + return null; + } + + @Override + public ExprTy visit(StmtTy.AsyncFunctionDef node) { + visitSequence(node.typeParams); + visitNode(node.args); + visitSequence(node.body); + visitSequence(node.decoratorList); + if (!futureAnnotations) { + node.returns = visitExpr(node.returns); + } + return null; + } + + @Override + public ExprTy visit(StmtTy.ClassDef node) { + BaseBytecodeDSLVisitor.super.visit(node); + visitSequence(node.typeParams); + return null; + } + + @Override + public ExprTy visit(StmtTy.AnnAssign node) { + node.target = visitExpr(node.target); + if (!futureAnnotations) { + node.annotation = visitExpr(node.annotation); + } + node.value = visitExpr(node.value); + return null; + } + + @Override + public ExprTy visit(ArgumentsTy node) { + visitSequence(node.posOnlyArgs); + visitSequence(node.args); + visitNode(node.varArg); + visitSequence(node.kwOnlyArgs); + visitSequence(node.kwDefaults); + visitNode(node.kwArg); + visitSequence(node.defaults); + return null; + } + + @Override + public ExprTy visit(ArgTy node) { + if (!futureAnnotations) { + node.annotation = visitExpr(node.annotation); + } + return null; + } + + @Override + public ExprTy visit(StmtTy.TryStar node) { + visitSequence(node.body); + visitSequence(node.handlers); + visitSequence(node.orElse); + visitSequence(node.finalBody); + return null; + } + + @Override + public ExprTy visit(StmtTy.TypeAlias node) { + node.name = visitExpr(node.name); + visitSequence(node.typeParams); + node.value = visitExpr(node.value); + return null; + } + + @Override + public ExprTy visit(ComprehensionTy node) { + BaseBytecodeDSLVisitor.super.visit(node); + node.iter = optimizeIterable(node.iter); + return null; + } + + @Override + public ExprTy visit(TypeParamTy.TypeVar node) { + node.bound = visitExpr(node.bound); + node.defaultValue = visitExpr(node.defaultValue); + return null; + } + + @Override + public ExprTy visit(TypeParamTy.ParamSpec node) { + node.defaultValue = visitExpr(node.defaultValue); + return null; + } + + @Override + public ExprTy visit(TypeParamTy.TypeVarTuple node) { + node.defaultValue = visitExpr(node.defaultValue); + return null; + } + + private static ExprTy optimizeIterable(ExprTy expression) { + if (expression instanceof ExprTy.List list) { + ConstantValue[] constants = constantElements(list.elements); + if (constants != null) { + return constant(expression, ConstantValue.ofTuple(constants)); + } else { + return new ExprTy.Tuple(list.elements, list.context, list.getSourceRange()); + } + } else if (expression instanceof ExprTy.Set set) { + ConstantValue[] constants = constantElements(set.elements); + if (constants != null) { + return constant(expression, ConstantValue.ofFrozenset(constants)); + } + } + return expression; + } + + private static ExprTy tryOptimizeFormat(ExprTy.BinOp node) { + ConstantValue format = getConstant(node.left); + if (node.op != OperatorTy.Mod || format == null || !(node.right instanceof ExprTy.Tuple tuple)) { + return null; + } + if (format.kind != ConstantValue.Kind.CODEPOINTS || tuple.elements.length != 1) { + return null; + } + String spec = format.getCodePoints().toJavaString(); + if (!(spec.equals("%s") || spec.equals("%r") || spec.equals("%a"))) { + return null; + } + ExprTy formatted = new ExprTy.FormattedValue(tuple.elements[0], spec.charAt(1), null, tuple.elements[0].getSourceRange()); + return new ExprTy.JoinedStr(new ExprTy[]{formatted}, node.getSourceRange()); + } + + private static ConstantValue[] constantElements(ExprTy[] elements) { + ConstantValue[] values = new ConstantValue[elements.length]; + for (int i = 0; i < elements.length; i++) { + values[i] = getConstant(elements[i]); + if (values[i] == null) { + return null; + } + } + return values; + } + + private static boolean hasFutureAnnotations(ModTy mod) { + StmtTy[] statements; + if (mod instanceof ModTy.Module module) { + statements = module.body; + } else if (mod instanceof ModTy.Interactive interactive) { + statements = interactive.body; + } else { + return false; + } + if (statements == null) { + return false; + } + for (StmtTy statement : statements) { + if (statement instanceof StmtTy.ImportFrom importFrom && "__future__".equals(importFrom.module)) { + if (importFrom.names != null) { + for (var alias : importFrom.names) { + if ("annotations".equals(alias.name)) { + return true; + } + } + } + } + } + return false; + } + + private static ConstantValue getConstant(ExprTy expression) { + return expression instanceof ExprTy.Constant constant ? constant.value : null; + } + + private static ExprTy.Constant constant(SSTNode node, ConstantValue value) { + return new ExprTy.Constant(value, null, node.getSourceRange()); + } + + private static CmpOpTy invertComparison(CmpOpTy op) { + return switch (op) { + case Is -> CmpOpTy.IsNot; + case IsNot -> CmpOpTy.Is; + case In -> CmpOpTy.NotIn; + case NotIn -> CmpOpTy.In; + default -> null; + }; + } + + private static Object foldBinOp(OperatorTy op, Object left, Object right) { + return switch (op) { + case Add -> PyNumberAddNode.getUncached().execute(null, left, right); + case Sub -> PyNumberSubtractNode.getUncached().execute(null, left, right); + case Mult -> isSafeMultiply(left, right) ? PyNumberMultiplyNode.getUncached().execute(null, left, right) : PNone.NO_VALUE; + case Div -> PyNumberTrueDivideNode.getUncached().execute(null, left, right); + case FloorDiv -> PyNumberFloorDivideNode.getUncached().execute(null, left, right); + case Mod -> left instanceof TruffleString || left instanceof PBytes ? PNone.NO_VALUE : PyNumberRemainderNode.getUncached().execute(null, left, right); + case Pow -> isSafePower(left, right) ? PyNumberPowerNode.getUncached().execute(null, left, right) : PNone.NO_VALUE; + case LShift -> isSafeLshift(left, right) ? PyNumberLshiftNode.getUncached().execute(null, left, right) : PNone.NO_VALUE; + case RShift -> PyNumberRshiftNode.getUncached().execute(null, left, right); + case BitOr -> PyNumberOrNode.getUncached().execute(null, left, right); + case BitXor -> PyNumberXorNode.getUncached().execute(null, left, right); + case BitAnd -> PyNumberAndNode.getUncached().execute(null, left, right); + case MatMult -> PNone.NO_VALUE; + }; + } + + private static Object foldUnaryOp(UnaryOpTy op, Object operand) { + return switch (op) { + case Invert -> PyNumberInvertNode.getUncached().execute(null, operand); + case Not -> !PyObjectIsTrueNode.executeUncached(operand); + case UAdd -> PyNumberPositiveNode.getUncached().execute(null, operand); + case USub -> PyNumberNegativeNode.getUncached().execute(null, operand); + }; + } + + private static ConstantValue asConstantValue(Object value) { + if (value == PNone.NO_VALUE) { + return null; + } else if (value == PNone.NONE) { + return ConstantValue.NONE; + } else if (value == PEllipsis.INSTANCE) { + return ConstantValue.ELLIPSIS; + } else if (value instanceof Boolean bool) { + return ConstantValue.ofBoolean(bool); + } else if (value instanceof Integer integer) { + return ConstantValue.ofLong(integer.longValue()); + } else if (value instanceof Long longValue) { + return ConstantValue.ofLong(longValue); + } else if (value instanceof PInt integer) { + return ConstantValue.ofBigInteger(integer.getValue()); + } else if (value instanceof Double doubleValue) { + return ConstantValue.ofDouble(doubleValue); + } else if (value instanceof PComplex complex) { + return ConstantValue.ofComplex(complex.getReal(), complex.getImag()); + } else if (value instanceof TruffleString string) { + return ConstantValue.ofCodePoints(PythonUtils.truffleStringToCodePoints(string)); + } else if (value instanceof PBytes bytes && bytes.getSequenceStorage() instanceof ByteSequenceStorage storage) { + return ConstantValue.ofBytes(Arrays.copyOf(storage.getInternalByteArray(), storage.length())); + } else if (value instanceof PTuple tuple) { + Object[] objects = ToArrayNode.executeUncached(tuple.getSequenceStorage()); + ConstantValue[] values = new ConstantValue[objects.length]; + for (int i = 0; i < values.length; i++) { + values[i] = asConstantValue(objects[i]); + if (values[i] == null) { + return null; + } + } + return ConstantValue.ofTuple(values); + } + return null; + } + + private static boolean isSafeMultiply(Object left, Object right) { + BigInteger leftInt = asBigInteger(left); + BigInteger rightInt = asBigInteger(right); + if (leftInt != null && rightInt != null && leftInt.signum() != 0 && rightInt.signum() != 0) { + return leftInt.bitLength() + rightInt.bitLength() <= MAX_INT_SIZE; + } + if (leftInt != null) { + return isSafeSequenceRepeat(leftInt, right); + } + if (rightInt != null) { + return isSafeSequenceRepeat(rightInt, left); + } + return true; + } + + private static boolean isSafeSequenceRepeat(BigInteger count, Object sequence) { + int size; + if (sequence instanceof PTuple tuple) { + size = tuple.getSequenceStorage().length(); + } else if (sequence instanceof TruffleString string) { + size = string.codePointLengthUncached(PythonUtils.TS_ENCODING); + } else if (sequence instanceof PBytes bytes) { + size = bytes.getSequenceStorage().length(); + } else { + return true; + } + return count.signum() < 0 || size == 0 || count.compareTo(BigInteger.valueOf(MAX_COLLECTION_SIZE / size)) <= 0; + } + + private static boolean isSafePower(Object left, Object right) { + BigInteger base = asBigInteger(left); + BigInteger exponent = asBigInteger(right); + return base == null || exponent == null || base.signum() == 0 || exponent.signum() <= 0 || + exponent.bitLength() <= 31 && exponent.intValue() <= MAX_INT_SIZE && base.bitLength() <= MAX_INT_SIZE / exponent.intValue(); + } + + private static boolean isSafeLshift(Object left, Object right) { + BigInteger value = asBigInteger(left); + BigInteger shift = asBigInteger(right); + return value == null || shift == null || value.signum() == 0 || shift.signum() == 0 || + shift.signum() > 0 && shift.bitLength() <= 31 && shift.intValue() <= MAX_INT_SIZE && value.bitLength() <= MAX_INT_SIZE - shift.intValue(); + } + + private static BigInteger asBigInteger(Object value) { + if (value instanceof Integer integer) { + return BigInteger.valueOf(integer.longValue()); + } else if (value instanceof Long longValue) { + return BigInteger.valueOf(longValue); + } else if (value instanceof PInt integer) { + return integer.getValue(); + } else if (value instanceof Boolean bool) { + return bool ? BigInteger.ONE : BigInteger.ZERO; + } + return null; + } +} diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/compiler/bytecode_dsl/BaseBytecodeDSLVisitor.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/compiler/bytecode_dsl/BaseBytecodeDSLVisitor.java index d0910aee08..4ab4a9b2c9 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/compiler/bytecode_dsl/BaseBytecodeDSLVisitor.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/compiler/bytecode_dsl/BaseBytecodeDSLVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -73,6 +73,25 @@ default void visitNode(SSTNode node) { } } + default ExprTy visitExpr(ExprTy node) { + visitNode(node); + return node; + } + + @Override + default U visitSequence(SSTNode[] sequence) { + if (sequence != null) { + for (int i = 0; i < sequence.length; i++) { + if (sequence[i] instanceof ExprTy expression) { + sequence[i] = visitExpr(expression); + } else if (sequence[i] != null) { + sequence[i].accept(this); + } + } + } + return null; + } + default T visit(AliasTy node) { return defaultValue(node); } @@ -88,25 +107,25 @@ default T visit(ArgumentsTy node) { } default T visit(ComprehensionTy node) { - visitNode(node.iter); + node.iter = visitExpr(node.iter); visitSequence(node.ifs); - visitNode(node.target); + node.target = visitExpr(node.target); return defaultValue(node); } default T visit(ExprTy.Attribute node) { - visitNode(node.value); + node.value = visitExpr(node.value); return defaultValue(node); } default T visit(ExprTy.Await node) { - visitNode(node.value); + node.value = visitExpr(node.value); return defaultValue(node); } default T visit(ExprTy.BinOp node) { - visitNode(node.left); - visitNode(node.right); + node.left = visitExpr(node.left); + node.right = visitExpr(node.right); return defaultValue(node); } @@ -116,14 +135,14 @@ default T visit(ExprTy.BoolOp node) { } default T visit(ExprTy.Call node) { - visitNode(node.func); + node.func = visitExpr(node.func); visitSequence(node.args); visitSequence(node.keywords); return defaultValue(node); } default T visit(ExprTy.Compare node) { - visitNode(node.left); + node.left = visitExpr(node.left); visitSequence(node.comparators); return defaultValue(node); } @@ -140,27 +159,27 @@ default T visit(ExprTy.Dict node) { default T visit(ExprTy.DictComp node) { visitSequence(node.generators); - visitNode(node.key); - visitNode(node.value); + node.key = visitExpr(node.key); + node.value = visitExpr(node.value); return defaultValue(node); } default T visit(ExprTy.FormattedValue node) { - visitNode(node.formatSpec); - visitNode(node.value); + node.formatSpec = visitExpr(node.formatSpec); + node.value = visitExpr(node.value); return defaultValue(node); } default T visit(ExprTy.GeneratorExp node) { - visitNode(node.element); + node.element = visitExpr(node.element); visitSequence(node.generators); return defaultValue(node); } default T visit(ExprTy.IfExp node) { - visitNode(node.test); - visitNode(node.body); - visitNode(node.orElse); + node.test = visitExpr(node.test); + node.body = visitExpr(node.body); + node.orElse = visitExpr(node.orElse); return defaultValue(node); } @@ -170,7 +189,8 @@ default T visit(ExprTy.JoinedStr node) { } default T visit(ExprTy.Lambda node) { - visitNode(node.body); + visitNode(node.args); + node.body = visitExpr(node.body); return defaultValue(node); } @@ -181,7 +201,7 @@ default T visit(ExprTy.List node) { default T visit(ExprTy.ListComp node) { visitSequence(node.generators); - visitNode(node.element); + node.element = visitExpr(node.element); return defaultValue(node); } @@ -190,8 +210,8 @@ default T visit(ExprTy.Name node) { } default T visit(ExprTy.NamedExpr node) { - visitNode(node.target); - visitNode(node.value); + node.target = visitExpr(node.target); + node.value = visitExpr(node.value); return defaultValue(node); } @@ -202,25 +222,25 @@ default T visit(ExprTy.Set node) { default T visit(ExprTy.SetComp node) { visitSequence(node.generators); - visitNode(node.element); + node.element = visitExpr(node.element); return defaultValue(node); } default T visit(ExprTy.Slice node) { - visitNode(node.lower); - visitNode(node.upper); - visitNode(node.step); + node.lower = visitExpr(node.lower); + node.upper = visitExpr(node.upper); + node.step = visitExpr(node.step); return defaultValue(node); } default T visit(ExprTy.Starred node) { - visitNode(node.value); + node.value = visitExpr(node.value); return defaultValue(node); } default T visit(ExprTy.Subscript node) { - visitNode(node.value); - visitNode(node.slice); + node.value = visitExpr(node.value); + node.slice = visitExpr(node.slice); return defaultValue(node); } @@ -230,32 +250,32 @@ default T visit(ExprTy.Tuple node) { } default T visit(ExprTy.UnaryOp node) { - visitNode(node.operand); + node.operand = visitExpr(node.operand); return defaultValue(node); } default T visit(ExprTy.Yield node) { - visitNode(node.value); + node.value = visitExpr(node.value); return defaultValue(node); } default T visit(ExprTy.YieldFrom node) { - visitNode(node.value); + node.value = visitExpr(node.value); return defaultValue(node); } default T visit(KeywordTy node) { - visitNode(node.value); + node.value = visitExpr(node.value); return defaultValue(node); } default T visit(ModTy.Expression node) { - visitNode(node.body); + node.body = visitExpr(node.body); return defaultValue(node); } default T visit(ModTy.FunctionType node) { - visitNode(node.returns); + node.returns = visitExpr(node.returns); return defaultValue(node); } @@ -270,27 +290,27 @@ default T visit(ModTy.Module node) { } default T visit(StmtTy.AnnAssign node) { - visitNode(node.target); - visitNode(node.annotation); - visitNode(node.value); + node.target = visitExpr(node.target); + node.annotation = visitExpr(node.annotation); + node.value = visitExpr(node.value); return defaultValue(node); } default T visit(StmtTy.Assert node) { - visitNode(node.test); - visitNode(node.msg); + node.test = visitExpr(node.test); + node.msg = visitExpr(node.msg); return defaultValue(node); } default T visit(StmtTy.Assign node) { - visitNode(node.value); + node.value = visitExpr(node.value); visitSequence(node.targets); return defaultValue(node); } default T visit(StmtTy.AsyncFor node) { - visitNode(node.target); - visitNode(node.iter); + node.target = visitExpr(node.target); + node.iter = visitExpr(node.iter); visitSequence(node.body); visitSequence(node.orElse); return defaultValue(node); @@ -299,7 +319,7 @@ default T visit(StmtTy.AsyncFor node) { default T visit(StmtTy.AsyncFunctionDef node) { visitSequence(node.decoratorList); visitNode(node.args); - visitNode(node.returns); + node.returns = visitExpr(node.returns); visitSequence(node.body); return defaultValue(node); } @@ -311,8 +331,8 @@ default T visit(StmtTy.AsyncWith node) { } default T visit(StmtTy.AugAssign node) { - visitNode(node.target); - visitNode(node.value); + node.target = visitExpr(node.target); + node.value = visitExpr(node.value); return defaultValue(node); } @@ -330,13 +350,13 @@ default T visit(StmtTy.Delete node) { } default T visit(StmtTy.Expr node) { - visitNode(node.value); + node.value = visitExpr(node.value); return defaultValue(node); } default T visit(StmtTy.For node) { - visitNode(node.iter); - visitNode(node.target); + node.iter = visitExpr(node.iter); + node.target = visitExpr(node.target); visitSequence(node.body); visitSequence(node.orElse); return defaultValue(node); @@ -345,7 +365,7 @@ default T visit(StmtTy.For node) { default T visit(StmtTy.FunctionDef node) { visitSequence(node.decoratorList); visitNode(node.args); - visitNode(node.returns); + node.returns = visitExpr(node.returns); visitSequence(node.body); return defaultValue(node); } @@ -355,7 +375,7 @@ default T visit(StmtTy.Global node) { } default T visit(StmtTy.If node) { - visitNode(node.test); + node.test = visitExpr(node.test); visitSequence(node.body); visitSequence(node.orElse); return defaultValue(node); @@ -370,14 +390,14 @@ default T visit(StmtTy.ImportFrom node) { } default T visit(StmtTy.Match node) { - visitNode(node.subject); + node.subject = visitExpr(node.subject); visitSequence(node.cases); return defaultValue(node); } default T visit(MatchCaseTy node) { visitNode(node.pattern); - visitNode(node.guard); + node.guard = visitExpr(node.guard); visitSequence(node.body); return defaultValue(node); } @@ -390,7 +410,7 @@ default T visit(PatternTy.MatchAs node) { default T visit(PatternTy.MatchClass node) { visitSequence(node.patterns); visitSequence(node.kwdPatterns); - visitNode(node.cls); + node.cls = visitExpr(node.cls); return defaultValue(node); } @@ -419,7 +439,7 @@ default T visit(PatternTy.MatchStar node) { } default T visit(PatternTy.MatchValue node) { - visitNode(node.value); + node.value = visitExpr(node.value); return defaultValue(node); } @@ -428,13 +448,13 @@ default T visit(StmtTy.Nonlocal node) { } default T visit(StmtTy.Raise node) { - visitNode(node.exc); - visitNode(node.cause); + node.exc = visitExpr(node.exc); + node.cause = visitExpr(node.cause); return defaultValue(node); } default T visit(StmtTy.Return node) { - visitNode(node.value); + node.value = visitExpr(node.value); return defaultValue(node); } @@ -451,13 +471,13 @@ default T visit(StmtTy.TryStar node) { } default T visit(ExceptHandlerTy.ExceptHandler node) { - visitNode(node.type); + node.type = visitExpr(node.type); visitSequence(node.body); return defaultValue(node); } default T visit(StmtTy.While node) { - visitNode(node.test); + node.test = visitExpr(node.test); visitSequence(node.body); visitSequence(node.orElse); return defaultValue(node); @@ -470,8 +490,8 @@ default T visit(StmtTy.With node) { } default T visit(WithItemTy node) { - visitNode(node.contextExpr); - visitNode(node.optionalVars); + node.contextExpr = visitExpr(node.contextExpr); + node.optionalVars = visitExpr(node.optionalVars); return defaultValue(node); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/compiler/bytecode_dsl/BytecodeDSLCompiler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/compiler/bytecode_dsl/BytecodeDSLCompiler.java index 3f896aafdd..7d873180af 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/compiler/bytecode_dsl/BytecodeDSLCompiler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/compiler/bytecode_dsl/BytecodeDSLCompiler.java @@ -47,6 +47,7 @@ import java.util.Map; import com.oracle.graal.python.PythonLanguage; +import com.oracle.graal.python.compiler.AstOptimizer; import com.oracle.graal.python.compiler.ParserCallbacksImpl; import com.oracle.graal.python.pegparser.AbstractParser; import com.oracle.graal.python.nodes.bytecode_dsl.BytecodeDSLCodeUnit; @@ -78,6 +79,7 @@ public static BytecodeDSLCompilerResult compile(PythonLanguage language, ModTy m * when __future__.annotations is imported. */ int futureLineNumber = parseFuture(mod, futureFeatures, parserCallbacks); + AstOptimizer.optimize(mod, optimize, futureFeatures.contains(FutureFeature.ANNOTATIONS)); ScopeEnvironment scopeEnvironment = ScopeEnvironment.analyze(mod, parserCallbacks, futureFeatures); BytecodeDSLCompilerContext ctx = new BytecodeDSLCompilerContext(language, mod, source, optimize, futureFeatures, futureLineNumber, parserCallbacks, scopeEnvironment); RootNodeCompiler compiler = new RootNodeCompiler(ctx, null, mod, futureFeatures); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/compiler/bytecode_dsl/RootNodeCompiler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/compiler/bytecode_dsl/RootNodeCompiler.java index 95daf47282..3461d9d636 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/compiler/bytecode_dsl/RootNodeCompiler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/compiler/bytecode_dsl/RootNodeCompiler.java @@ -91,6 +91,7 @@ import com.oracle.graal.python.builtins.objects.ellipsis.PEllipsis; import com.oracle.graal.python.builtins.objects.function.PArguments; import com.oracle.graal.python.builtins.objects.function.PKeyword; +import com.oracle.graal.python.builtins.objects.object.PythonObject; import com.oracle.graal.python.builtins.objects.type.TypeFlags; import com.oracle.graal.python.compiler.CompilationScope; import com.oracle.graal.python.compiler.MakeTypeParamKind; @@ -367,6 +368,7 @@ private static T[] orderedKeys(HashMap map, T[] base) { } private Object addConstant(Object c) { + assert !(c instanceof PythonObject) : "context-specific object in constants: " + c; Integer v = constants.get(c); if (v == null) { v = constants.size(); @@ -397,35 +399,45 @@ private static ConstantCollection tryCollectConstantCollection(ExprTy[] elements if (elements == null || elements.length == 0) { return null; } + ConstantValue[] values = new ConstantValue[elements.length]; + for (int i = 0; i < elements.length; i++) { + if (!(elements[i] instanceof ExprTy.Constant constant)) { + return null; + } + values[i] = constant.value; + } + return tryCollectConstantCollection(values); + } + + private static ConstantCollection tryCollectConstantCollection(ConstantValue[] values) { + if (values == null || values.length == 0) { + return null; + } CollectionType constantType = null; List constants = new ArrayList<>(); - for (ExprTy e : elements) { - if (e instanceof ExprTy.Constant c) { - if (c.value.kind == ConstantValue.Kind.BOOLEAN) { - constantType = determineConstantType(constantType, CollectionType.BOOLEAN); - constants.add(c.value.getBoolean()); - } else if (c.value.kind == ConstantValue.Kind.LONG) { - long val = c.value.getLong(); - if (val == (int) val) { - constantType = determineConstantType(constantType, CollectionType.INT); - } else { - constantType = determineConstantType(constantType, CollectionType.LONG); - } - constants.add(val); - } else if (c.value.kind == ConstantValue.Kind.DOUBLE) { - constantType = determineConstantType(constantType, CollectionType.DOUBLE); - constants.add(c.value.getDouble()); - } else if (c.value.kind == ConstantValue.Kind.CODEPOINTS) { - constantType = determineConstantType(constantType, CollectionType.OBJECT); - constants.add(codePointsToInternedTruffleString(c.value.getCodePoints())); - } else if (c.value.kind == ConstantValue.Kind.NONE) { - constantType = determineConstantType(constantType, CollectionType.OBJECT); - constants.add(PNone.NONE); + for (ConstantValue value : values) { + if (value.kind == ConstantValue.Kind.BOOLEAN) { + constantType = determineConstantType(constantType, CollectionType.BOOLEAN); + constants.add(value.getBoolean()); + } else if (value.kind == ConstantValue.Kind.LONG) { + long val = value.getLong(); + if (val == (int) val) { + constantType = determineConstantType(constantType, CollectionType.INT); } else { - return null; + constantType = determineConstantType(constantType, CollectionType.LONG); } + constants.add(val); + } else if (value.kind == ConstantValue.Kind.DOUBLE) { + constantType = determineConstantType(constantType, CollectionType.DOUBLE); + constants.add(value.getDouble()); + } else if (value.kind == ConstantValue.Kind.CODEPOINTS) { + constantType = determineConstantType(constantType, CollectionType.OBJECT); + constants.add(codePointsToInternedTruffleString(value.getCodePoints())); + } else if (value.kind == ConstantValue.Kind.NONE) { + constantType = determineConstantType(constantType, CollectionType.OBJECT); + constants.add(PNone.NONE); } else { return null; } @@ -2657,13 +2669,19 @@ private void createConstant(ConstantValue value) { addConstant(value.getBytes()); b.emitLoadBytes(value.getBytes()); break; - case TUPLE: - b.beginMakeTuple(); - for (ConstantValue cv : value.getTupleElements()) { - createConstant(cv); + case TUPLE: { + ConstantCollection constantCollection = tryCollectConstantCollection(value.getTupleElements()); + if (constantCollection != null) { + emitConstantTuple(constantCollection); + } else { + b.beginMakeTuple(); + for (ConstantValue cv : value.getTupleElements()) { + createConstant(cv); + } + b.endMakeTuple(); } - b.endMakeTuple(); break; + } case FROZENSET: b.beginMakeFrozenSet(); for (ConstantValue cv : value.getFrozensetElements()) { @@ -3130,14 +3148,9 @@ public Void visit(ExprTy.Tuple node) { boolean newStatement = beginSourceSection(node, b); beginTraceLineChecked(b); - ConstantCollection constantCollection = tryCollectConstantCollection(node.elements); - if (constantCollection != null) { - emitConstantTuple(constantCollection); - } else { - b.beginMakeTuple(); - emitUnstar(node.elements); - b.endMakeTuple(); - } + b.beginMakeTuple(); + emitUnstar(node.elements); + b.endMakeTuple(); endTraceLineChecked(node, b); endSourceSection(b, newStatement); @@ -3146,19 +3159,6 @@ public Void visit(ExprTy.Tuple node) { @Override public Void visit(ExprTy.UnaryOp node) { - // Basic constant folding for unary negation - if (node.op == UnaryOpTy.USub && node.operand instanceof ExprTy.Constant c) { - if (c.value.kind == ConstantValue.Kind.BIGINTEGER || c.value.kind == ConstantValue.Kind.DOUBLE || c.value.kind == ConstantValue.Kind.LONG || - c.value.kind == ConstantValue.Kind.COMPLEX) { - ConstantValue cv = c.value.negate(); - boolean newStatement = beginSourceSection(node, b); - beginTraceLineChecked(b); - visit(new ExprTy.Constant(cv, null, c.getSourceRange())); - endTraceLineChecked(node, b); - endSourceSection(b, newStatement); - return null; - } - } boolean newStatement = beginSourceSection(node, b); beginTraceLineChecked(b); switch (node.op) { @@ -3475,11 +3475,13 @@ private void checkAnnSubscr(ExprTy expr) { @Override public Void visit(StmtTy.Assert node) { + boolean nonEmptyTuple = node.test instanceof ExprTy.Tuple tuple && tuple.elements.length > 0 || + node.test instanceof ExprTy.Constant constant && constant.value.kind == Kind.TUPLE && constant.value.getTupleElements().length > 0; + if (nonEmptyTuple) { + warn(node, "assertion is always true, perhaps remove parentheses?"); + } if (ctx.optimizationLevel <= 0) { boolean newStatement = beginSourceSection(node, b); - if (node.test instanceof ExprTy.Tuple && ((Tuple) node.test).elements.length > 0) { - ctx.errorCallback.onWarning(WarningType.Syntax, currentLocation, "assertion is always true, perchance remove parentheses?"); - } b.beginIfThen(); b.beginNot(); @@ -5349,7 +5351,7 @@ private void checkPatternKeysLength(int keyLen, PatternContext pc) { } /** - * Will process pattern keys: Attributes evaluation and constant folding. Checks for + * Will process pattern keys: attribute evaluation and constant validation. Checks for * duplicate keys and that only literals and attributes lookups are being matched. *

* Generates array. @@ -5366,16 +5368,10 @@ private void processPatternKeys(ExprTy[] keys, int keyLen, PatternTy.MatchMappin if (key instanceof ExprTy.Attribute) { key.accept(this); } else { - ConstantValue constantValue = null; - if (key instanceof ExprTy.UnaryOp || key instanceof ExprTy.BinOp) { - constantValue = foldConstantOp(key); - } else if (key instanceof ExprTy.Constant) { - constantValue = ((ExprTy.Constant) key).value; - } else { - ctx.errorCallback.onError(ErrorType.Syntax, node.getSourceRange(), "mapping pattern keys may only match literals and attribute lookups"); + if (!(key instanceof ExprTy.Constant constant)) { + throw ctx.errorCallback.onError(ErrorType.Syntax, node.getSourceRange(), "mapping pattern keys may only match literals and attribute lookups"); } - assert constantValue != null; - Object pythonValue = PythonUtils.pythonObjectFromConstantValue(constantValue); + Object pythonValue = PythonUtils.pythonObjectFromConstantValue(constant.value); for (Object o : seen) { // need python like equal - e.g. 1 equals True if (PyObjectRichCompareBool.executeEqUncached(o, pythonValue)) { @@ -5383,7 +5379,7 @@ private void processPatternKeys(ExprTy[] keys, int keyLen, PatternTy.MatchMappin } } seen.add(pythonValue); - createConstant(constantValue); + createConstant(constant.value); } } b.endCollectToObjectArray(); @@ -5875,9 +5871,7 @@ private void doVisitPattern(PatternTy.MatchValue node, PatternContext pc) { b.beginEq(); b.emitLoadLocal(pc.subject); - if (node.value instanceof ExprTy.UnaryOp || node.value instanceof ExprTy.BinOp) { - createConstant(foldConstantOp(node.value)); - } else if (node.value instanceof ExprTy.Constant || node.value instanceof ExprTy.Attribute) { + if (node.value instanceof ExprTy.Constant || node.value instanceof ExprTy.Attribute) { node.value.accept(this); } else { ctx.errorCallback.onError(ErrorType.Syntax, currentLocation, "patterns may only match literals and attribute lookups"); @@ -5893,53 +5887,6 @@ private static boolean wildcardStarCheck(PatternTy pattern) { return pattern instanceof PatternTy.MatchStar && ((PatternTy.MatchStar) pattern).name == null; } - /** - * handles only particular cases when a constant comes either as a unary or binary op - */ - private ConstantValue foldConstantOp(ExprTy value) { - if (value instanceof ExprTy.UnaryOp unaryOp) { - return foldUnaryOpConstant(unaryOp); - } else if (value instanceof ExprTy.BinOp binOp) { - return foldBinOpComplexConstant(binOp); - } - throw new IllegalStateException("should not reach here"); - } - - /** - * handles only unary sub and a numeric constant - */ - private ConstantValue foldUnaryOpConstant(ExprTy.UnaryOp unaryOp) { - assert unaryOp.op == UnaryOpTy.USub; - assert unaryOp.operand instanceof ExprTy.Constant : unaryOp.operand; - ExprTy.Constant c = (ExprTy.Constant) unaryOp.operand; - ConstantValue ret = c.value.negate(); - assert ret != null; - return ret; - } - - /** - * handles only complex which comes as a BinOp - */ - private ConstantValue foldBinOpComplexConstant(ExprTy.BinOp binOp) { - assert (binOp.left instanceof ExprTy.UnaryOp || binOp.left instanceof ExprTy.Constant) && binOp.right instanceof ExprTy.Constant : binOp.left + " " + binOp.right; - assert binOp.op == OperatorTy.Sub || binOp.op == OperatorTy.Add; - ConstantValue left; - if (binOp.left instanceof ExprTy.UnaryOp) { - left = foldUnaryOpConstant((ExprTy.UnaryOp) binOp.left); - } else { - left = ((ExprTy.Constant) binOp.left).value; - } - ExprTy.Constant right = (ExprTy.Constant) binOp.right; - switch (binOp.op) { - case Add: - return left.addComplex(right.value); - case Sub: - return left.subComplex(right.value); - default: - throw new IllegalStateException("wrong constant BinOp operator " + binOp.op); - } - } - @Override public Void visit(MatchCaseTy node) { throw new UnsupportedOperationException("" + node.getClass()); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonOptions.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonOptions.java index ff99173823..4f5a273efe 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonOptions.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonOptions.java @@ -134,7 +134,7 @@ private PythonOptions() { @EngineOption @Option(category = OptionCategory.USER, help = "Equivalent to setting the PYTHONIOENCODING environment variable for the standard launcher.", usageSyntax = "[:]", stability = OptionStability.STABLE) // public static final OptionKey StandardStreamEncoding = new OptionKey<>(T_EMPTY_STRING, TS_OPTION_TYPE); - @Option(category = OptionCategory.USER, help = "Remove assert statements and any code conditional on the value of __debug__.", usageSyntax = "true|false", stability = OptionStability.STABLE) // + @EngineOption @Option(category = OptionCategory.USER, help = "Remove assert statements and any code conditional on the value of __debug__.", usageSyntax = "true|false", stability = OptionStability.STABLE) // public static final OptionKey PythonOptimizeFlag = new OptionKey<>(false); @Option(category = OptionCategory.USER, help = "Equivalent to the Python -v flag. Turn on verbose mode.", usageSyntax = "true|false", stability = OptionStability.STABLE) // diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonSourceOptions.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonSourceOptions.java index 8acd13ed88..a4af8e7766 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonSourceOptions.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonSourceOptions.java @@ -54,7 +54,7 @@ private PythonSourceOptions() { } @Option(category = OptionCategory.USER, stability = OptionStability.STABLE, help = "Optimization level used when compiling this source") // - public static final OptionKey Optimize = new OptionKey<>(0); + public static final OptionKey Optimize = new OptionKey<>(-1); @Option(category = OptionCategory.EXPERT, stability = OptionStability.STABLE, help = "Compiler flags used when compiling this source") // public static final OptionKey Flags = new OptionKey<>(0); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/util/PythonUtils.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/util/PythonUtils.java index 290d46df54..763a070309 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/util/PythonUtils.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/util/PythonUtils.java @@ -68,6 +68,9 @@ import com.oracle.graal.python.PythonLanguage; import com.oracle.graal.python.annotations.Builtin; import com.oracle.graal.python.builtins.objects.PNone; +import com.oracle.graal.python.builtins.objects.common.EconomicMapStorage; +import com.oracle.graal.python.builtins.objects.common.HashingStorage; +import com.oracle.graal.python.builtins.objects.common.HashingStorageNodes.HashingStorageSetItem; import com.oracle.graal.python.builtins.objects.ellipsis.PEllipsis; import com.oracle.graal.python.builtins.objects.function.PBuiltinFunction; import com.oracle.graal.python.builtins.objects.str.PString; @@ -898,13 +901,21 @@ public static Object pythonObjectFromConstantValue(ConstantValue v) { return PFactory.createBytes(PythonLanguage.get(null), v.getBytes()); case CODEPOINTS: return codePointsToInternedTruffleString(v.getCodePoints()); - case TUPLE: - case FROZENSET: - // These cases cannot happen: - // - when called from Sst2ObjVisitor, the SST comes from the parser which never - // emits tuples or frozensets - // - when called from the compiler of pattern matching, the SST has been checked by - // Validator#validatePatternMatchValue() which rejects tuples and frozensets + case TUPLE: { + ConstantValue[] elements = v.getTupleElements(); + Object[] objects = new Object[elements.length]; + for (int i = 0; i < objects.length; i++) { + objects[i] = pythonObjectFromConstantValue(elements[i]); + } + return PFactory.createTuple(PythonLanguage.get(null), objects); + } + case FROZENSET: { + HashingStorage storage = EconomicMapStorage.create(v.getFrozensetElements().length); + for (ConstantValue element : v.getFrozensetElements()) { + storage = HashingStorageSetItem.executeUncached(storage, pythonObjectFromConstantValue(element), PNone.NONE); + } + return PFactory.createFrozenSet(PythonLanguage.get(null), storage); + } default: throw shouldNotReachHere(); }