4444import static com .oracle .graal .python .nodes .SpecialMethodNames .__RMUL__ ;
4545import static com .oracle .graal .python .nodes .SpecialMethodNames .__STR__ ;
4646import static com .oracle .graal .python .runtime .exception .PythonErrorType .IndexError ;
47- import static com .oracle .graal .python .runtime .exception .PythonErrorType .LookupError ;
4847import static com .oracle .graal .python .runtime .exception .PythonErrorType .MemoryError ;
4948import static com .oracle .graal .python .runtime .exception .PythonErrorType .TypeError ;
50- import static com .oracle .graal .python .runtime .exception .PythonErrorType .UnicodeEncodeError ;
5149import static com .oracle .graal .python .runtime .exception .PythonErrorType .ValueError ;
5250
53- import java .nio .ByteBuffer ;
54- import java .nio .CharBuffer ;
55- import java .nio .charset .CharacterCodingException ;
56- import java .nio .charset .Charset ;
5751import java .nio .charset .CharsetEncoder ;
58- import java .nio .charset .CodingErrorAction ;
59- import java .nio .charset .IllegalCharsetNameException ;
6052import java .nio .charset .StandardCharsets ;
61- import java .nio .charset .UnsupportedCharsetException ;
6253import java .util .Arrays ;
6354import java .util .List ;
6455import java .util .Locale ;
7566import com .oracle .graal .python .builtins .CoreFunctions ;
7667import com .oracle .graal .python .builtins .PythonBuiltinClassType ;
7768import com .oracle .graal .python .builtins .PythonBuiltins ;
69+ import com .oracle .graal .python .builtins .modules .BuiltinFunctions ;
70+ import com .oracle .graal .python .builtins .modules .CodecsModuleBuiltins ;
71+ import com .oracle .graal .python .builtins .modules .OperatorModuleBuiltins ;
7872import com .oracle .graal .python .builtins .objects .PNone ;
7973import com .oracle .graal .python .builtins .objects .PNotImplemented ;
8074import com .oracle .graal .python .builtins .objects .bytes .BytesUtils ;
75+ import com .oracle .graal .python .builtins .objects .bytes .PByteArray ;
76+ import com .oracle .graal .python .builtins .objects .bytes .PBytes ;
8177import com .oracle .graal .python .builtins .objects .cext .PythonAbstractNativeObject ;
8278import com .oracle .graal .python .builtins .objects .common .FormatNodeBase ;
8379import com .oracle .graal .python .builtins .objects .common .HashingCollectionNodes ;
8480import com .oracle .graal .python .builtins .objects .common .HashingStorage ;
8581import com .oracle .graal .python .builtins .objects .common .HashingStorageLibrary ;
8682import com .oracle .graal .python .builtins .objects .common .SequenceNodes .GetObjectArrayNode ;
8783import com .oracle .graal .python .builtins .objects .common .SequenceNodesFactory .GetObjectArrayNodeGen ;
84+ import com .oracle .graal .python .builtins .objects .common .SequenceStorageNodes ;
8885import com .oracle .graal .python .builtins .objects .dict .PDict ;
8986import com .oracle .graal .python .builtins .objects .iterator .PStringIterator ;
9087import com .oracle .graal .python .builtins .objects .list .ListBuiltins .ListReverseNode ;
103100import com .oracle .graal .python .builtins .objects .tuple .PTuple ;
104101import com .oracle .graal .python .builtins .objects .tuple .TupleBuiltins ;
105102import com .oracle .graal .python .builtins .objects .type .TypeNodes .IsSameTypeNode ;
103+ import com .oracle .graal .python .builtins .objects .function .PKeyword ;
104+ import com .oracle .graal .python .builtins .objects .object .PythonObjectLibrary ;
106105import com .oracle .graal .python .lib .PyNumberAsSizeNode ;
107106import com .oracle .graal .python .lib .PyObjectHashNode ;
107+ import static com .oracle .graal .python .nodes .BuiltinNames .ENCODE ;
108+ import static com .oracle .graal .python .nodes .BuiltinNames .FORMAT ;
109+ import static com .oracle .graal .python .nodes .BuiltinNames .FORMAT_MAP ;
108110import com .oracle .graal .python .nodes .ErrorMessages ;
111+ import static com .oracle .graal .python .nodes .ErrorMessages .ENCODER_RETURNED_P_INSTEAD_OF_BYTES ;
112+ import static com .oracle .graal .python .nodes .ErrorMessages .OBJ_NOT_SUBSCRIPTABLE ;
113+ import static com .oracle .graal .python .nodes .ErrorMessages .TAKES_EXACTLY_S_ARGUMENTS_D_GIVEN ;
109114import com .oracle .graal .python .nodes .PGuards ;
110115import com .oracle .graal .python .nodes .PRaiseNode ;
111116import com .oracle .graal .python .nodes .SpecialMethodNames ;
@@ -227,6 +232,76 @@ private Spec getAndValidateSpec(String formatString) {
227232 }
228233 }
229234
235+ @ Builtin (name = FORMAT , minNumOfPositionalArgs = 1 , takesVarArgs = true , takesVarKeywordArgs = true , declaresExplicitSelf = true )
236+ @ GenerateNodeFactory
237+ abstract static class StrFormatNode extends PythonBuiltinNode {
238+ @ Specialization
239+ String format (VirtualFrame frame , PString self , Object [] args , PKeyword [] kwargs ,
240+ @ Cached BuiltinFunctions .FormatNode format ,
241+ @ Cached OperatorModuleBuiltins .GetItemNode getItem ) {
242+ return format (frame , self .getValue (), args , kwargs , format , getItem );
243+ }
244+
245+ @ Specialization
246+ String format (VirtualFrame frame , String self , Object [] args , PKeyword [] kwargs ,
247+ @ Cached BuiltinFunctions .FormatNode format ,
248+ @ Cached OperatorModuleBuiltins .GetItemNode getItem ) {
249+
250+ TemplateFormatter template = new TemplateFormatter (self );
251+
252+ PythonLanguage language = PythonLanguage .get (this );
253+ PythonContext context = PythonContext .get (this );
254+ Object state = IndirectCallContext .enter (frame , language , context , this );
255+ try {
256+ return template .build (this , args , kwargs , format , getItem );
257+ } finally {
258+ IndirectCallContext .exit (frame , language , context , state );
259+ }
260+ }
261+ }
262+
263+ @ Builtin (name = FORMAT_MAP , minNumOfPositionalArgs = 1 , declaresExplicitSelf = true , parameterNames = {"self" , "mapping" })
264+ @ ArgumentClinic (name = "self" , conversion = ArgumentClinic .ClinicConversion .String )
265+ @ GenerateNodeFactory
266+ @ ImportStatic (SpecialMethodNames .class )
267+ abstract static class FormatMapNode extends PythonBinaryClinicBuiltinNode {
268+ @ Override
269+ protected ArgumentClinicProvider getArgumentClinic () {
270+ return StringBuiltinsClinicProviders .FormatMapNodeClinicProviderGen .INSTANCE ;
271+ }
272+
273+ @ Specialization (guards = "lib.isMapping(mapping)" , limit = "1" )
274+ String format (VirtualFrame frame , String self , Object mapping ,
275+ @ Cached BuiltinFunctions .FormatNode format ,
276+ @ Cached OperatorModuleBuiltins .GetItemNode getItem ,
277+ @ SuppressWarnings ("unused" ) @ CachedLibrary ("mapping" ) PythonObjectLibrary lib ) {
278+
279+ TemplateFormatter template = new TemplateFormatter (self );
280+
281+ PythonLanguage language = PythonLanguage .get (this );
282+ PythonContext context = PythonContext .get (this );
283+ Object state = IndirectCallContext .enter (frame , language , context , this );
284+ try {
285+ return template .build (this , null , mapping , format , getItem );
286+ } finally {
287+ IndirectCallContext .exit (frame , language , context , state );
288+ }
289+ }
290+
291+ @ SuppressWarnings ("unused" )
292+ @ Specialization (guards = {"!lib.isMapping(obj)" , "!isNone(obj)" }, limit = "1" )
293+ String format (String self , Object obj ,
294+ @ SuppressWarnings ("unused" ) @ CachedLibrary ("obj" ) PythonObjectLibrary lib ) {
295+ throw raise (TypeError , OBJ_NOT_SUBSCRIPTABLE , obj );
296+ }
297+
298+ @ SuppressWarnings ("unused" )
299+ @ Specialization (guards = "isNone(obj)" )
300+ String format (String self , PNone obj ) {
301+ throw raise (TypeError , TAKES_EXACTLY_S_ARGUMENTS_D_GIVEN , "format_map" , "one" , 0 );
302+ }
303+ }
304+
230305 @ Builtin (name = __REPR__ , minNumOfPositionalArgs = 1 )
231306 @ GenerateNodeFactory
232307 abstract static class ReprNode extends PythonUnaryBuiltinNode {
@@ -1743,8 +1818,15 @@ public int rindex(Object self, Object sub, int start, int end,
17431818 }
17441819 }
17451820
1746- // This is only used during bootstrap and then replaced with Python code
1747- @ Builtin (name = "encode" , minNumOfPositionalArgs = 1 , parameterNames = {"self" , "encoding" , "errors" })
1821+ @ Builtin (name = ENCODE , minNumOfPositionalArgs = 1 , parameterNames = {"self" , "encoding" , "errors" }, doc = "Decode the bytes using the codec registered for encoding.\n \n " +
1822+ " encoding\n " +
1823+ " The encoding with which to decode the bytes.\n " +
1824+ " errors\n " +
1825+ " The error handling scheme to use for the handling of decoding errors.\n " +
1826+ " The default is 'strict' meaning that decoding errors raise a\n " +
1827+ " UnicodeDecodeError. Other possible values are 'ignore' and 'replace'\n " +
1828+ " as well as any other name registered with codecs.register_error that\n " +
1829+ " can handle UnicodeDecodeErrors." )
17481830 @ ArgumentClinic (name = "encoding" , conversion = ClinicConversion .String , defaultValue = "\" utf-8\" " , useDefaultForNone = true )
17491831 @ ArgumentClinic (name = "errors" , conversion = ClinicConversion .String , defaultValue = "\" strict\" " , useDefaultForNone = true )
17501832 @ GenerateNodeFactory
@@ -1757,48 +1839,26 @@ protected ArgumentClinicProvider getArgumentClinic() {
17571839 }
17581840
17591841 @ Specialization
1760- Object doStringEncodingErrors (String self , String encoding , String errors ) {
1761- return encodeString (self , encoding , errors );
1842+ Object doStringEncoding (VirtualFrame frame , String self , String encoding , String errors ,
1843+ @ Cached CodecsModuleBuiltins .EncodeNode encodeNode ,
1844+ @ Cached SequenceStorageNodes .CopyNode copyNode ) {
1845+ Object result = encodeNode .call (frame , self , encoding , errors );
1846+ if (!(result instanceof PBytes )) {
1847+ if (result instanceof PByteArray ) {
1848+ return factory ().createBytes (copyNode .execute (((PByteArray ) result ).getSequenceStorage ()));
1849+ }
1850+ throw raise (TypeError , ENCODER_RETURNED_P_INSTEAD_OF_BYTES , encoding , result );
1851+ }
1852+ return result ;
17621853 }
17631854
17641855 @ Specialization
1765- Object doGeneric (Object self , String encoding , String errors ,
1766- @ Cached CastToJavaStringCheckedNode castSelfNode ) {
1856+ Object doGeneric (VirtualFrame frame , Object self , String encoding , String errors ,
1857+ @ Cached CastToJavaStringCheckedNode castSelfNode ,
1858+ @ Cached CodecsModuleBuiltins .EncodeNode encodeNode ,
1859+ @ Cached SequenceStorageNodes .CopyNode copyNode ) {
17671860 String selfStr = castSelfNode .cast (self , ErrorMessages .REQUIRES_STR_OBJECT_BUT_RECEIVED_P , "index" , self );
1768- return encodeString (selfStr , encoding , errors );
1769- }
1770-
1771- @ TruffleBoundary
1772- private Object encodeString (String self , String encoding , String errors ) {
1773- // Note: to support custom actions, we can use CharsetEncoderICU from icu4j-charset
1774- CodingErrorAction errorAction ;
1775- switch (errors ) {
1776- case "ignore" :
1777- errorAction = CodingErrorAction .IGNORE ;
1778- break ;
1779- case "replace" :
1780- errorAction = CodingErrorAction .REPLACE ;
1781- break ;
1782- default :
1783- errorAction = CodingErrorAction .REPORT ;
1784- break ;
1785- }
1786-
1787- Charset cs ;
1788- try {
1789- cs = Charset .forName (encoding );
1790- } catch (UnsupportedCharsetException | IllegalCharsetNameException e ) {
1791- throw raise (LookupError , ErrorMessages .UNKNOWN_ENCODING , encoding );
1792- }
1793- try {
1794- ByteBuffer encoded = cs .newEncoder ().onMalformedInput (errorAction ).onUnmappableCharacter (errorAction ).encode (CharBuffer .wrap (self ));
1795- int n = encoded .remaining ();
1796- byte [] data = new byte [n ];
1797- encoded .get (data );
1798- return factory ().createBytes (data );
1799- } catch (CharacterCodingException e ) {
1800- throw raise (UnicodeEncodeError , e );
1801- }
1861+ return doStringEncoding (frame , selfStr , encoding , errors , encodeNode , copyNode );
18021862 }
18031863 }
18041864
0 commit comments