python 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +60 -0
  6. data/Rakefile +2 -0
  7. data/bin/python.rb +16 -0
  8. data/examples/demo.py +10 -0
  9. data/examples/fibonacci.py +5 -0
  10. data/examples/twoclass.py +9 -0
  11. data/features/programmer_caclulate_numerical_expression.feature +50 -0
  12. data/features/programmer_execute_from_source_file.feature +10 -0
  13. data/features/programmer_starts_repl_console.feature +10 -0
  14. data/features/programmer_use_advanced_calculator.feature +35 -0
  15. data/features/programmer_use_class.feature +42 -0
  16. data/features/programmer_use_closure.feature +66 -0
  17. data/features/programmer_use_variables.feature +12 -0
  18. data/features/step_definitions/calculate_numerical_steps.rb +67 -0
  19. data/features/support/env.rb +2 -0
  20. data/lib/python.rb +10 -0
  21. data/lib/python/builtins.rb +72 -0
  22. data/lib/python/environment.rb +42 -0
  23. data/lib/python/file_interpreter.rb +29 -0
  24. data/lib/python/parser/combinator.rb +206 -0
  25. data/lib/python/parser/expression.rb +125 -0
  26. data/lib/python/parser/identifier.rb +22 -0
  27. data/lib/python/parser/indent_converter.rb +52 -0
  28. data/lib/python/parser/integer.rb +28 -0
  29. data/lib/python/parser/statement.rb +86 -0
  30. data/lib/python/pyobject.rb +129 -0
  31. data/lib/python/repl.rb +47 -0
  32. data/lib/python/syntax.rb +201 -0
  33. data/lib/python/version.rb +3 -0
  34. data/python.gemspec +24 -0
  35. data/spec/python/parser/expression_spec.rb +28 -0
  36. data/spec/python/parser/indent_converter_spec.rb +36 -0
  37. data/spec/python/pyobject_spec.rb +20 -0
  38. data/spec/python/repl_spec.rb +14 -0
  39. data/spec/spec_helper.rb +1 -0
  40. metadata +125 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c712a1eeb1a31ce723c1fa4c0f6f499a3b04de9f
4
+ data.tar.gz: 0e3a1c2d0123e206072ee79a27d28fbe87d687bb
5
+ SHA512:
6
+ metadata.gz: 75ab974d6430f574011536b451895263d6c62b82adf89eb73832b2393880aa9e550e8b3642e64d160e0787b4fffe230fec67db348d2cb0978c6194cb00e15d7e
7
+ data.tar.gz: 77723e0b9e1e3f01d22032442e0881bc3659d4955706b401a53962e839f9201ceddcfdb93508a35c60355f21013767bcb19c9cdca0395ffa85e0a37248c12540
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ /documents/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in python.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 TODO: Write your name
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,60 @@
1
+ # Python
2
+
3
+ Python implemented in pure Ruby without any libraries.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'python'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install python
20
+
21
+ ## Usage
22
+
23
+ Executable script "python.rb" will be installed in your bin path.
24
+ You can execute python program by two way.
25
+ One way is through command-line interpreter (REPL), and another is from source-file.
26
+
27
+ ### Command-line interpreter (REPL)
28
+
29
+ $ python.rb
30
+ python.rb> 1 + 2
31
+ 3
32
+ python.rb>
33
+
34
+ ### Executing program from source file
35
+
36
+ ```python
37
+ # demo.py
38
+ class A:
39
+ def __init__(self, x):
40
+ self.x = x
41
+
42
+ def add(self, d):
43
+ self.x = self.x + d
44
+ return self
45
+
46
+ a = A(1).add(2).add(3)
47
+ print(a.x)
48
+ ```
49
+
50
+ $ python.rb demo.py
51
+ 6
52
+ $
53
+
54
+ ## Contributing
55
+
56
+ 1. Fork it ( https://github.com/sawaken/python.rb/fork )
57
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
58
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
59
+ 4. Push to the branch (`git push origin my-new-feature`)
60
+ 5. Create a new Pull Request
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
3
+ require 'python'
4
+
5
+ if ARGV[0]
6
+ File.open(ARGV[0], "r") do |file|
7
+ Python::FileInterpreter.new(file.read).execute
8
+ end
9
+ else
10
+ repl = Python::REPL.new(STDOUT)
11
+ repl.start
12
+ while input = STDIN.gets
13
+ repl.read_eval_print(input)
14
+ repl.prompt
15
+ end
16
+ end
@@ -0,0 +1,10 @@
1
+ class A:
2
+ def __init__(self, x):
3
+ self.x = x
4
+
5
+ def add(self, d):
6
+ self.x = self.x + d
7
+ return self
8
+
9
+ a = A(1).add(2).add(3)
10
+ print(a.x)
@@ -0,0 +1,5 @@
1
+ def fib(n):
2
+ cond = n == 0 or n == 1
3
+ return n if cond else fib(n - 1) + fib(n - 2)
4
+
5
+ print(fib(10))
@@ -0,0 +1,9 @@
1
+ class Y:
2
+ def __init__(self, val):
3
+ self.val = val
4
+
5
+ class X:
6
+ def __init__(self, val):
7
+ self.y = Y(val)
8
+
9
+ print(X(1).y.val)
@@ -0,0 +1,50 @@
1
+ Feature: programmer calculate numerical expression
2
+
3
+ The programmer calculates numerical expressions through REPL console.
4
+ REPL console print caluculated number in one line.
5
+
6
+ Scenario Outline: calculate numerical expression
7
+ Given I started repl but didn't input anything
8
+ When I input "<expression>"
9
+ Then the output expect be "<evaluated>"
10
+
11
+ Scenarios: without operator
12
+ | expression | evaluated |
13
+ | 1 | 1 |
14
+ | 0 | 0 |
15
+ | -1 | -1 |
16
+ | +1 | 1 |
17
+
18
+ Scenarios: single operator
19
+ | expression | evaluated |
20
+ | 1 + 2 | 3 |
21
+ | 1 - 2 | -1 |
22
+ | 1 * 2 | 2 |
23
+ | 1 // 2 | 0 |
24
+
25
+ Scenarios: without space between tokens
26
+ | expression | evaluated |
27
+ | 1+2 | 3 |
28
+ | 100+100 | 200 |
29
+
30
+ Scenarios: double operator
31
+ | expression | evaluated |
32
+ | 1 + 2 + 3 | 6 |
33
+ | 1 - 2 - 3 | -4 |
34
+ | 1 * 2 * 3 | 6 |
35
+ | 9 // 3 // 2 | 1 |
36
+
37
+ Scenarios: priority
38
+ | expression | evaluated |
39
+ | 1 + 2 * 3 | 7 |
40
+ | 1 - 2 * 3 | -5 |
41
+ | 1 + 6 // 3 | 3 |
42
+ | 1 - 6 // 3 | -1 |
43
+
44
+ Scenarios: parentheses
45
+ | expression | evaluated |
46
+ | (1) | 1 |
47
+ | (-1) | -1 |
48
+ | (1 + 2) * (3 + 4) | 21 |
49
+ | (1 - (2 - 3)) | 2 |
50
+ | ((1 + 2) * 3) | 9 |
@@ -0,0 +1,10 @@
1
+ Feature: programmer execute python program in source file
2
+
3
+ Scenario: execute script file
4
+ Given in silence, I am on shell
5
+ When I start interpreter with argument "number_of_the_beast.py":
6
+ """
7
+ six = 6
8
+ print(six * 100 + six * 10 + six)
9
+ """
10
+ Then the output expect be "666"
@@ -0,0 +1,10 @@
1
+ Feature: programmer starts REPL console
2
+
3
+ As a programmer
4
+ I want to start REPL console
5
+ So that I can input and run python code
6
+
7
+ Scenario: start REPL
8
+ Given I am not yet inputting anything
9
+ When I start a new REPL console
10
+ Then I expect see "python.rb> "
@@ -0,0 +1,35 @@
1
+ Feature: programmer use advanced calculator
2
+
3
+ The programmer calculates numerical expressions with conditions through REPL console.
4
+ REPL console print caluculated number in one line.
5
+
6
+ Scenario Outline: calculate numerical expression with conditions
7
+ Given I started repl but didn't input anything
8
+ When I input "<statement>"
9
+ Then the output expect be "<evaluated>"
10
+
11
+ Scenarios: with conditional operator
12
+ | statement | evaluated |
13
+ | 1 < 2 | True |
14
+ | 1 < 2 < 3 | True |
15
+ | 2 < 1 | False |
16
+ | 1 == 1 | True |
17
+ | 1 == 2 | False |
18
+ | 2 > 1 | True |
19
+
20
+ Scenarios: with not, and, or
21
+ | statement | evaluated |
22
+ | not 1 | False |
23
+ | not 0 | True |
24
+ | not True | False |
25
+ | not False | True |
26
+ | 1 and 2 | 2 |
27
+ | 1 and 0 | 0 |
28
+ | 1 or 0 | 1 |
29
+ | 0 or 1 | 1 |
30
+ | 1 or 2 | 1 |
31
+
32
+ Scenarios: with conditional expression
33
+ | statement | evaluated |
34
+ | 1 + 1 if 1 == 2 else 2 + 2 | 4 |
35
+ | 1 + 1 if 1 == 1 else 2 + 2 | 2 |
@@ -0,0 +1,42 @@
1
+ Feature: programmer use class
2
+
3
+ Scenario: define simple class and make instance
4
+ Given in silence, I am on shell
5
+ When I start interpreter with argument "defineclass.py":
6
+ """
7
+ class A:
8
+ def mymethod(self, x):
9
+ return x
10
+
11
+ a = A()
12
+ print(a.mymethod(2))
13
+ """
14
+ Then the output expect be "2"
15
+
16
+ Scenario: define class having static variable and use it
17
+ Given in silence, I am on shell
18
+ When I start interpreter with argument "staticclassvariable.py":
19
+ """
20
+ class B:
21
+ staticvar = 123
22
+
23
+ b = B()
24
+ print(b.staticvar)
25
+ """
26
+ Then the output expect be "123"
27
+
28
+ Scenario: define two class
29
+ Given in silence, I am on shell
30
+ When I start interpreter with argument "class2.py":
31
+ """
32
+ class Y:
33
+ def __init__(self, val):
34
+ self.val = val
35
+
36
+ class X:
37
+ def __init__(self, val):
38
+ self.y = Y(val)
39
+
40
+ print(X(1).y.val)
41
+ """
42
+ Then the output expect be "1"
@@ -0,0 +1,66 @@
1
+ Feature: programmer use closure
2
+
3
+ Scenario: calc fibonacci-number by using closure in script file
4
+ Given in silence, I am on shell
5
+ When I start interpreter with argument "fibonacci.py":
6
+ """
7
+ def fib(n):
8
+ cond = n == 0 or n == 1
9
+ return n if cond else fib(n - 1) + fib(n - 2)
10
+
11
+ print(fib(10))
12
+ """
13
+ Then the output expect be "55"
14
+
15
+ Scenario: play with a high-order function (a function returns a function) in script file
16
+ Given in silence, I am on shell
17
+ When I start interpreter with argument "highorder1.py":
18
+ """
19
+ def curried_add(a):
20
+ def add(b):
21
+ return a + b
22
+ return add
23
+
24
+ print(curried_add(1)(2))
25
+ """
26
+ Then the output expect be "3"
27
+
28
+ Scenario: play with a high-order function (a function takes a function) in script file
29
+ Given in silence, I am on shell
30
+ When I start interpreter with argument "highorder2.py":
31
+ """
32
+ def twice(f, arg):
33
+ return f(f(arg))
34
+
35
+ def double(a):
36
+ return a * 2
37
+
38
+ print(twice(double, 5))
39
+ """
40
+ Then the output expect be "20"
41
+
42
+ Scenario: argument-less function
43
+ Given in silence, I am on shell
44
+ When I start interpreter with argument "noargs.py":
45
+ """
46
+ def hello():
47
+ print(12)
48
+
49
+ hello()
50
+ """
51
+ Then the output expect be "12"
52
+
53
+ Scenario: double DEDENT
54
+ Given in silence, I am on shell
55
+ When I start interpreter with argument "doublededent.py":
56
+ """
57
+ def foo():
58
+ def bar():
59
+ return 1
60
+ def baz():
61
+ return 2
62
+
63
+ a = foo()
64
+ print(0)
65
+ """
66
+ Then the output expect be "0"
@@ -0,0 +1,12 @@
1
+ Feature: programmer use variables on REPL console
2
+
3
+ Scenario: use variables
4
+ Given I started repl but didn't input anything
5
+ When I input "x = 1"
6
+ Then the output expect be ""
7
+ When I input "x"
8
+ Then the output expect be "1"
9
+ When I input "x = x + 1"
10
+ Then the output expect be ""
11
+ When I input "x"
12
+ Then the output expect be "2"
@@ -0,0 +1,67 @@
1
+ class Out
2
+ def messages
3
+ @messages ||= []
4
+ end
5
+
6
+ def write(messge)
7
+ print(message)
8
+ end
9
+
10
+ def puts(message)
11
+ print(message + "\n")
12
+ end
13
+
14
+ def print(message)
15
+ messages << message
16
+ end
17
+ end
18
+
19
+ # Feature: programmer starts REPL console
20
+ #-----
21
+
22
+ Given(/^I am not yet inputting anything$/) do
23
+ @out = Out.new
24
+ @repl = Python::REPL.new(@out)
25
+ end
26
+
27
+ When(/^I start a new REPL console$/) do
28
+ @repl.start
29
+ end
30
+
31
+ Then(/^I expect see "([^"]*)"$/) do |message|
32
+ expect(@out.messages).to eq([message])
33
+ end
34
+
35
+ # Feature: programmer calculate numerical expression
36
+ #-----
37
+
38
+ Given(/^I started repl but didn't input anything$/) do
39
+ @out = Out.new
40
+ @repl = Python::REPL.new(@out)
41
+ @repl.start
42
+ end
43
+
44
+ When(/^I input "([^"]*)"$/) do |input|
45
+ @repl.read_eval_print(input)
46
+ end
47
+
48
+ Then(/^the output expect be "([^"]*)"$/) do |expected|
49
+ if expected != ""
50
+ expect(@out.messages.last).to eq(expected + "\n")
51
+ else
52
+ expect(@out.messages.last).to eq("")
53
+ end
54
+ end
55
+
56
+ # Feature: programmer execute python program in source file
57
+ #-----
58
+
59
+ Given(/^in silence, I am on shell$/) do
60
+
61
+ end
62
+
63
+ When(/^I start interpreter with argument "([^"]*)":$/) do |filename, code|
64
+ @out = Out.new
65
+ printfunc = Python::Builtins::Func.make_instance{|obj| @out.puts(obj.inspect)}
66
+ Python::FileInterpreter.new(code, "print" => printfunc).execute
67
+ end