Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
P
Pyston
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Boxiang Sun
Pyston
Commits
ec1b3848
Commit
ec1b3848
authored
Aug 25, 2014
by
Kevin Modzelewski
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Implement execfile() (1-arg version)
Also required adding some string functions so that we could use os.path.
parent
59e195aa
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
135 additions
and
32 deletions
+135
-32
src/core/types.h
src/core/types.h
+2
-1
src/core/util.cpp
src/core/util.cpp
+8
-2
src/core/util.h
src/core/util.h
+1
-0
src/jit.cpp
src/jit.cpp
+3
-17
src/runtime/builtin_modules/builtins.cpp
src/runtime/builtin_modules/builtins.cpp
+27
-0
src/runtime/objmodel.cpp
src/runtime/objmodel.cpp
+9
-3
src/runtime/str.cpp
src/runtime/str.cpp
+65
-2
src/runtime/types.cpp
src/runtime/types.cpp
+7
-5
test/tests/execfile_test.py
test/tests/execfile_test.py
+9
-2
test/tests/str_functions.py
test/tests/str_functions.py
+4
-0
No files found.
src/core/types.h
View file @
ec1b3848
...
@@ -452,7 +452,8 @@ static_assert(sizeof(pyston::BoxedClass) == sizeof(struct _typeobject), "");
...
@@ -452,7 +452,8 @@ static_assert(sizeof(pyston::BoxedClass) == sizeof(struct _typeobject), "");
// TODO these shouldn't be here
// TODO these shouldn't be here
void
setupRuntime
();
void
setupRuntime
();
void
teardownRuntime
();
void
teardownRuntime
();
BoxedModule
*
createModule
(
const
std
::
string
&
name
,
const
std
::
string
&
fn
);
BoxedModule
*
compileAndRunModule
(
const
std
::
string
&
name
,
const
std
::
string
&
fn
,
bool
add_to_sys_modules
);
BoxedModule
*
createModule
(
const
std
::
string
&
name
,
const
std
::
string
&
fn
,
bool
add_to_sys_modules
=
true
);
std
::
string
getPythonFuncAt
(
void
*
ip
,
void
*
sp
);
std
::
string
getPythonFuncAt
(
void
*
ip
,
void
*
sp
);
...
...
src/core/util.cpp
View file @
ec1b3848
...
@@ -83,11 +83,17 @@ Timer::~Timer() {
...
@@ -83,11 +83,17 @@ Timer::~Timer() {
}
}
bool
startswith
(
const
std
::
string
&
s
,
const
std
::
string
&
pattern
)
{
bool
startswith
(
const
std
::
string
&
s
,
const
std
::
string
&
pattern
)
{
if
(
s
.
size
()
==
0
)
if
(
pattern
.
size
()
>
s
.
size
()
)
return
pattern
.
size
()
==
0
;
return
false
;
return
s
.
compare
(
0
,
pattern
.
size
(),
pattern
)
==
0
;
return
s
.
compare
(
0
,
pattern
.
size
(),
pattern
)
==
0
;
}
}
bool
endswith
(
const
std
::
string
&
s
,
const
std
::
string
&
pattern
)
{
if
(
pattern
.
size
()
>
s
.
size
())
return
false
;
return
s
.
compare
(
s
.
size
()
-
pattern
.
size
(),
pattern
.
size
(),
pattern
)
==
0
;
}
void
removeDirectoryIfExists
(
const
std
::
string
&
path
)
{
void
removeDirectoryIfExists
(
const
std
::
string
&
path
)
{
llvm
::
error_code
code
;
llvm
::
error_code
code
;
...
...
src/core/util.h
View file @
ec1b3848
...
@@ -48,6 +48,7 @@ public:
...
@@ -48,6 +48,7 @@ public:
};
};
bool
startswith
(
const
std
::
string
&
s
,
const
std
::
string
&
pattern
);
bool
startswith
(
const
std
::
string
&
s
,
const
std
::
string
&
pattern
);
bool
endswith
(
const
std
::
string
&
s
,
const
std
::
string
&
pattern
);
void
removeDirectoryIfExists
(
const
std
::
string
&
path
);
void
removeDirectoryIfExists
(
const
std
::
string
&
path
);
...
...
src/jit.cpp
View file @
ec1b3848
...
@@ -127,8 +127,6 @@ int main(int argc, char** argv) {
...
@@ -127,8 +127,6 @@ int main(int argc, char** argv) {
_t
.
split
(
"to run"
);
_t
.
split
(
"to run"
);
BoxedModule
*
main_module
=
NULL
;
BoxedModule
*
main_module
=
NULL
;
if
(
fn
!=
NULL
)
{
if
(
fn
!=
NULL
)
{
main_module
=
createModule
(
"__main__"
,
fn
);
llvm
::
SmallString
<
128
>
path
;
llvm
::
SmallString
<
128
>
path
;
if
(
!
llvm
::
sys
::
path
::
is_absolute
(
fn
))
{
if
(
!
llvm
::
sys
::
path
::
is_absolute
(
fn
))
{
...
@@ -147,20 +145,8 @@ int main(int argc, char** argv) {
...
@@ -147,20 +145,8 @@ int main(int argc, char** argv) {
num_iterations
=
1000
;
num_iterations
=
1000
;
for
(
int
i
=
0
;
i
<
num_iterations
;
i
++
)
{
for
(
int
i
=
0
;
i
<
num_iterations
;
i
++
)
{
AST_Module
*
m
;
if
(
caching
)
m
=
caching_parse
(
fn
);
else
m
=
parse
(
fn
);
if
(
VERBOSITY
()
>=
1
)
{
printf
(
"Parsed code; ast:
\n
"
);
print_ast
(
m
);
printf
(
"==============
\n
"
);
}
try
{
try
{
compileAndRunModule
(
m
,
main_modul
e
);
main_module
=
compileAndRunModule
(
"__main__"
,
fn
,
tru
e
);
}
catch
(
Box
*
b
)
{
}
catch
(
Box
*
b
)
{
std
::
string
msg
=
formatException
(
b
);
std
::
string
msg
=
formatException
(
b
);
printLastTraceback
();
printLastTraceback
();
...
@@ -173,7 +159,7 @@ int main(int argc, char** argv) {
...
@@ -173,7 +159,7 @@ int main(int argc, char** argv) {
if
(
repl
&&
BENCH
)
{
if
(
repl
&&
BENCH
)
{
if
(
!
main_module
)
{
if
(
!
main_module
)
{
main_module
=
createModule
(
"__main__"
,
"<bench>"
);
main_module
=
createModule
(
"__main__"
,
"<bench>"
,
true
);
}
else
{
}
else
{
main_module
->
fn
=
"<bench>"
;
main_module
->
fn
=
"<bench>"
;
}
}
...
@@ -211,7 +197,7 @@ int main(int argc, char** argv) {
...
@@ -211,7 +197,7 @@ int main(int argc, char** argv) {
printf
(
", targeting Python %d.%d.%d
\n
"
,
PYTHON_VERSION_MAJOR
,
PYTHON_VERSION_MINOR
,
PYTHON_VERSION_MICRO
);
printf
(
", targeting Python %d.%d.%d
\n
"
,
PYTHON_VERSION_MAJOR
,
PYTHON_VERSION_MINOR
,
PYTHON_VERSION_MICRO
);
if
(
!
main_module
)
{
if
(
!
main_module
)
{
main_module
=
createModule
(
"__main__"
,
"<stdin>"
);
main_module
=
createModule
(
"__main__"
,
"<stdin>"
,
true
);
}
else
{
}
else
{
main_module
->
fn
=
"<stdin>"
;
main_module
->
fn
=
"<stdin>"
;
}
}
...
...
src/runtime/builtin_modules/builtins.cpp
View file @
ec1b3848
...
@@ -16,6 +16,8 @@
...
@@ -16,6 +16,8 @@
#include <cstddef>
#include <cstddef>
#include <err.h>
#include <err.h>
#include "llvm/Support/FileSystem.h"
#include "codegen/compvars.h"
#include "codegen/compvars.h"
#include "core/ast.h"
#include "core/ast.h"
#include "core/types.h"
#include "core/types.h"
...
@@ -524,6 +526,29 @@ Box* divmod(Box* lhs, Box* rhs) {
...
@@ -524,6 +526,29 @@ Box* divmod(Box* lhs, Box* rhs) {
return
binopInternal
(
lhs
,
rhs
,
AST_TYPE
::
DivMod
,
false
,
NULL
);
return
binopInternal
(
lhs
,
rhs
,
AST_TYPE
::
DivMod
,
false
,
NULL
);
}
}
Box
*
execfile
(
Box
*
_fn
)
{
// The "globals" and "locals" arguments aren't implemented for now
if
(
!
isSubclass
(
_fn
->
cls
,
str_cls
))
{
raiseExcHelper
(
TypeError
,
"must be string, not %s"
,
getTypeName
(
_fn
)
->
c_str
());
}
BoxedString
*
fn
=
static_cast
<
BoxedString
*>
(
_fn
);
bool
exists
;
llvm
::
error_code
code
=
llvm
::
sys
::
fs
::
exists
(
fn
->
s
,
exists
);
#if LLVMREV < 210072
ASSERT
(
code
==
0
,
"%s: %s"
,
code
.
message
().
c_str
(),
fn
->
s
.
c_str
());
#else
assert
(
!
code
);
#endif
if
(
!
exists
)
raiseExcHelper
(
IOError
,
"No such file or directory: '%s'"
,
fn
->
s
.
c_str
());
compileAndRunModule
(
"aoeu"
,
fn
->
s
,
false
);
return
None
;
}
void
setupBuiltins
()
{
void
setupBuiltins
()
{
builtins_module
=
createModule
(
"__builtin__"
,
"__builtin__"
);
builtins_module
=
createModule
(
"__builtin__"
,
"__builtin__"
);
...
@@ -649,6 +674,8 @@ void setupBuiltins() {
...
@@ -649,6 +674,8 @@ void setupBuiltins() {
builtins_module
->
giveAttr
(
"divmod"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
divmod
,
UNKNOWN
,
2
)));
builtins_module
->
giveAttr
(
"divmod"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
divmod
,
UNKNOWN
,
2
)));
builtins_module
->
giveAttr
(
"execfile"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
execfile
,
UNKNOWN
,
1
)));
builtins_module
->
giveAttr
(
"map"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
map2
,
LIST
,
2
)));
builtins_module
->
giveAttr
(
"map"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
map2
,
LIST
,
2
)));
builtins_module
->
giveAttr
(
"filter"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
filter2
,
LIST
,
2
)));
builtins_module
->
giveAttr
(
"filter"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
filter2
,
LIST
,
2
)));
builtins_module
->
giveAttr
(
"zip"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
zip2
,
LIST
,
2
)));
builtins_module
->
giveAttr
(
"zip"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
zip2
,
LIST
,
2
)));
...
...
src/runtime/objmodel.cpp
View file @
ec1b3848
...
@@ -3487,6 +3487,14 @@ extern "C" Box* getGlobal(BoxedModule* m, std::string* name) {
...
@@ -3487,6 +3487,14 @@ extern "C" Box* getGlobal(BoxedModule* m, std::string* name) {
raiseExcHelper
(
NameError
,
"global name '%s' is not defined"
,
name
->
c_str
());
raiseExcHelper
(
NameError
,
"global name '%s' is not defined"
,
name
->
c_str
());
}
}
BoxedModule
*
compileAndRunModule
(
const
std
::
string
&
name
,
const
std
::
string
&
fn
,
bool
add_to_sys_modules
)
{
BoxedModule
*
module
=
createModule
(
name
,
fn
,
add_to_sys_modules
);
AST_Module
*
ast
=
caching_parse
(
fn
.
c_str
());
compileAndRunModule
(
ast
,
module
);
return
module
;
}
// TODO I feel like importing should go somewhere else; it's more closely tied to codegen
// TODO I feel like importing should go somewhere else; it's more closely tied to codegen
// than to the object model.
// than to the object model.
extern
"C"
Box
*
import
(
const
std
::
string
*
name
)
{
extern
"C"
Box
*
import
(
const
std
::
string
*
name
)
{
...
@@ -3533,9 +3541,7 @@ extern "C" Box* import(const std::string* name) {
...
@@ -3533,9 +3541,7 @@ extern "C" Box* import(const std::string* name) {
printf
(
"Importing %s from %s
\n
"
,
name
->
c_str
(),
fn
.
c_str
());
printf
(
"Importing %s from %s
\n
"
,
name
->
c_str
(),
fn
.
c_str
());
// TODO duplication with jit.cpp:
// TODO duplication with jit.cpp:
BoxedModule
*
module
=
createModule
(
*
name
,
fn
);
BoxedModule
*
module
=
compileAndRunModule
(
*
name
,
fn
,
true
);
AST_Module
*
ast
=
caching_parse
(
fn
.
c_str
());
compileAndRunModule
(
ast
,
module
);
return
module
;
return
module
;
}
}
...
...
src/runtime/str.cpp
View file @
ec1b3848
...
@@ -23,6 +23,7 @@
...
@@ -23,6 +23,7 @@
#include "codegen/compvars.h"
#include "codegen/compvars.h"
#include "core/common.h"
#include "core/common.h"
#include "core/types.h"
#include "core/types.h"
#include "core/util.h"
#include "gc/collector.h"
#include "gc/collector.h"
#include "runtime/objmodel.h"
#include "runtime/objmodel.h"
#include "runtime/types.h"
#include "runtime/types.h"
...
@@ -694,6 +695,64 @@ Box* strContains(BoxedString* self, Box* elt) {
...
@@ -694,6 +695,64 @@ Box* strContains(BoxedString* self, Box* elt) {
return
True
;
return
True
;
}
}
Box
*
strStartswith
(
BoxedString
*
self
,
Box
*
elt
)
{
if
(
self
->
cls
!=
str_cls
)
raiseExcHelper
(
TypeError
,
"descriptor 'startswith' requires a 'str' object but received a '%s'"
,
getTypeName
(
elt
)
->
c_str
());
if
(
elt
->
cls
!=
str_cls
)
raiseExcHelper
(
TypeError
,
"expected a character buffer object"
);
BoxedString
*
sub
=
static_cast
<
BoxedString
*>
(
elt
);
return
boxBool
(
startswith
(
self
->
s
,
sub
->
s
));
}
Box
*
strEndswith
(
BoxedString
*
self
,
Box
*
elt
)
{
if
(
self
->
cls
!=
str_cls
)
raiseExcHelper
(
TypeError
,
"descriptor 'endswith' requires a 'str' object but received a '%s'"
,
getTypeName
(
elt
)
->
c_str
());
if
(
elt
->
cls
!=
str_cls
)
raiseExcHelper
(
TypeError
,
"expected a character buffer object"
);
BoxedString
*
sub
=
static_cast
<
BoxedString
*>
(
elt
);
return
boxBool
(
endswith
(
self
->
s
,
sub
->
s
));
}
Box
*
strFind
(
BoxedString
*
self
,
Box
*
elt
)
{
if
(
self
->
cls
!=
str_cls
)
raiseExcHelper
(
TypeError
,
"descriptor 'find' requires a 'str' object but received a '%s'"
,
getTypeName
(
elt
)
->
c_str
());
if
(
elt
->
cls
!=
str_cls
)
raiseExcHelper
(
TypeError
,
"expected a character buffer object"
);
BoxedString
*
sub
=
static_cast
<
BoxedString
*>
(
elt
);
size_t
r
=
self
->
s
.
find
(
sub
->
s
);
if
(
r
==
std
::
string
::
npos
)
return
boxInt
(
-
1
);
return
boxInt
(
r
);
}
Box
*
strRfind
(
BoxedString
*
self
,
Box
*
elt
)
{
if
(
self
->
cls
!=
str_cls
)
raiseExcHelper
(
TypeError
,
"descriptor 'rfind' requires a 'str' object but received a '%s'"
,
getTypeName
(
elt
)
->
c_str
());
if
(
elt
->
cls
!=
str_cls
)
raiseExcHelper
(
TypeError
,
"expected a character buffer object"
);
BoxedString
*
sub
=
static_cast
<
BoxedString
*>
(
elt
);
size_t
r
=
self
->
s
.
rfind
(
sub
->
s
);
if
(
r
==
std
::
string
::
npos
)
return
boxInt
(
-
1
);
return
boxInt
(
r
);
}
extern
"C"
Box
*
strGetitem
(
BoxedString
*
self
,
Box
*
slice
)
{
extern
"C"
Box
*
strGetitem
(
BoxedString
*
self
,
Box
*
slice
)
{
assert
(
self
->
cls
==
str_cls
);
assert
(
self
->
cls
==
str_cls
);
...
@@ -851,9 +910,7 @@ void setupStr() {
...
@@ -851,9 +910,7 @@ void setupStr() {
str_cls
->
giveAttr
(
"upper"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
strUpper
,
STR
,
1
)));
str_cls
->
giveAttr
(
"upper"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
strUpper
,
STR
,
1
)));
str_cls
->
giveAttr
(
"strip"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
strStrip
,
STR
,
2
,
1
,
false
,
false
),
{
None
}));
str_cls
->
giveAttr
(
"strip"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
strStrip
,
STR
,
2
,
1
,
false
,
false
),
{
None
}));
str_cls
->
giveAttr
(
"lstrip"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
strLStrip
,
STR
,
2
,
1
,
false
,
false
),
{
None
}));
str_cls
->
giveAttr
(
"lstrip"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
strLStrip
,
STR
,
2
,
1
,
false
,
false
),
{
None
}));
str_cls
->
giveAttr
(
"rstrip"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
strRStrip
,
STR
,
2
,
1
,
false
,
false
),
{
None
}));
str_cls
->
giveAttr
(
"rstrip"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
strRStrip
,
STR
,
2
,
1
,
false
,
false
),
{
None
}));
str_cls
->
giveAttr
(
"capitalize"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
strCapitalize
,
STR
,
1
)));
str_cls
->
giveAttr
(
"capitalize"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
strCapitalize
,
STR
,
1
)));
...
@@ -861,6 +918,12 @@ void setupStr() {
...
@@ -861,6 +918,12 @@ void setupStr() {
str_cls
->
giveAttr
(
"__contains__"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
strContains
,
BOXED_BOOL
,
2
)));
str_cls
->
giveAttr
(
"__contains__"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
strContains
,
BOXED_BOOL
,
2
)));
str_cls
->
giveAttr
(
"startswith"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
strStartswith
,
BOXED_BOOL
,
2
)));
str_cls
->
giveAttr
(
"endswith"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
strEndswith
,
BOXED_BOOL
,
2
)));
str_cls
->
giveAttr
(
"find"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
strFind
,
BOXED_INT
,
2
)));
str_cls
->
giveAttr
(
"rfind"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
strRfind
,
BOXED_INT
,
2
)));
str_cls
->
giveAttr
(
"__add__"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
strAdd
,
UNKNOWN
,
2
)));
str_cls
->
giveAttr
(
"__add__"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
strAdd
,
UNKNOWN
,
2
)));
str_cls
->
giveAttr
(
"__mod__"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
strMod
,
STR
,
2
)));
str_cls
->
giveAttr
(
"__mod__"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
strMod
,
STR
,
2
)));
str_cls
->
giveAttr
(
"__mul__"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
strMul
,
UNKNOWN
,
2
)));
str_cls
->
giveAttr
(
"__mul__"
,
new
BoxedFunction
(
boxRTFunction
((
void
*
)
strMul
,
UNKNOWN
,
2
)));
...
...
src/runtime/types.cpp
View file @
ec1b3848
...
@@ -805,14 +805,16 @@ void setupRuntime() {
...
@@ -805,14 +805,16 @@ void setupRuntime() {
TRACK_ALLOCATIONS
=
true
;
TRACK_ALLOCATIONS
=
true
;
}
}
BoxedModule
*
createModule
(
const
std
::
string
&
name
,
const
std
::
string
&
fn
)
{
BoxedModule
*
createModule
(
const
std
::
string
&
name
,
const
std
::
string
&
fn
,
bool
add_to_sys_modules
)
{
assert
(
fn
.
size
()
&&
"probably wanted to set the fn to <stdin>?"
);
assert
(
fn
.
size
()
&&
"probably wanted to set the fn to <stdin>?"
);
BoxedModule
*
module
=
new
BoxedModule
(
name
,
fn
);
BoxedModule
*
module
=
new
BoxedModule
(
name
,
fn
);
BoxedDict
*
d
=
getSysModulesDict
();
if
(
add_to_sys_modules
)
{
Box
*
b_name
=
boxStringPtr
(
&
name
);
BoxedDict
*
d
=
getSysModulesDict
();
assert
(
d
->
d
.
count
(
b_name
)
==
0
);
Box
*
b_name
=
boxStringPtr
(
&
name
);
d
->
d
[
b_name
]
=
module
;
assert
(
d
->
d
.
count
(
b_name
)
==
0
);
d
->
d
[
b_name
]
=
module
;
}
module
->
giveAttr
(
"__doc__"
,
None
);
module
->
giveAttr
(
"__doc__"
,
None
);
return
module
;
return
module
;
...
...
test/tests/execfile_test.py
View file @
ec1b3848
# expected: fail
# expected: fail
# execfile() not implemented yet
# execfile() not implemented yet
execfile
(
"execfile_target.py"
)
try
:
execfile
(
"doesnt_exist.py"
)
except
IOError
,
e
:
print
e
import
os
fn
=
os
.
path
.
join
(
os
.
path
.
dirname
(
__file__
),
'execfile_target.py'
)
execfile
(
fn
)
print
"done with first execfile"
print
"done with first execfile"
execfile
(
"execfile_target.py"
)
execfile
(
fn
)
test/tests/str_functions.py
View file @
ec1b3848
...
@@ -56,3 +56,7 @@ print sorted([str(i) for i in xrange(25)])
...
@@ -56,3 +56,7 @@ print sorted([str(i) for i in xrange(25)])
for
i
in
xrange
(
-
3
,
5
):
for
i
in
xrange
(
-
3
,
5
):
print
i
,
"bananananananananana"
.
split
(
"an"
,
i
)
print
i
,
"bananananananananana"
.
split
(
"an"
,
i
)
for
i
in
[
""
,
"a"
,
"ab"
,
"aa"
]:
for
j
in
[
""
,
"b"
,
"a"
,
"ab"
,
"aa"
]:
print
i
,
j
,
i
.
startswith
(
j
),
j
.
startswith
(
i
),
i
.
endswith
(
j
),
j
.
endswith
(
i
),
i
.
find
(
j
),
j
.
find
(
i
),
i
.
rfind
(
j
),
j
.
rfind
(
i
)
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment