python 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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