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,2 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../../lib', __FILE__)
2
+ require 'python'
@@ -0,0 +1,10 @@
1
+ require "python/version"
2
+ require "python/repl"
3
+ require "python/parser/expression"
4
+ require "python/syntax"
5
+ require "python/builtins"
6
+ require "python/file_interpreter"
7
+
8
+ module Python
9
+ # Your code goes here...
10
+ end
@@ -0,0 +1,72 @@
1
+ require 'python/pyobject'
2
+
3
+ module Python
4
+ module Builtins
5
+ # Primitive objects
6
+ Func = PyObject.new(:name => "Func")
7
+ Int = PyObject.new(:name => "Int")
8
+ Bool = PyObject.new(:name => "Bool", :bases => [Int])
9
+
10
+ None = PyObject.new(:name => "None")
11
+ True = PyObject.new(:class => Bool, :name => "True", :entity => 1)
12
+ False = PyObject.new(:class => Bool, :name => "False", :entity => 0)
13
+
14
+ Type = PyObject.new(:name => "Type")
15
+
16
+
17
+ # Primitiv functions
18
+ AddTwoInt = Func.make_instance{|a, b| Int.make_instance(a.entity + b.entity)}
19
+ SubTwoInt = Func.make_instance{|a, b| Int.make_instance(a.entity - b.entity)}
20
+ MulTwoInt = Func.make_instance{|a, b| Int.make_instance(a.entity * b.entity)}
21
+ FloordivTwoInt = Func.make_instance{|a, b| Int.make_instance(a.entity / b.entity)}
22
+ PosInt = Func.make_instance{|n| Int.make_instance(+ n.entity)}
23
+ NegInt = Func.make_instance{|n| Int.make_instance(- n.entity)}
24
+ EQInt = Func.make_instance{|a, b| a.entity == b.entity ? True : False}
25
+ LTInt = Func.make_instance{|a, b| a.entity < b.entity ? True : False}
26
+ GTInt = Func.make_instance{|a, b| a.entity > b.entity ? True : False}
27
+ IntToBool = Func.make_instance{|n| n.entity == 0 ? False : True}
28
+
29
+ Print = Func.make_instance{|o| puts(o.inspect)}
30
+ ClosureCall = Func.make_instance do |f, *args|
31
+ if f.entity[:rest_param_name]
32
+ unless f.entity[:fix_param_names].length <= args.length
33
+ raise Syntax::PyCallError.new
34
+ end
35
+ else
36
+ unless f.entity[:fix_param_names].length == args.length
37
+ raise Syntax::PyCallError.new
38
+ end
39
+ end
40
+ bind = f.entity[:fix_param_names].zip(args).to_h
41
+ env = Environment.new(bind.merge(:parent => f.entity[:env]))
42
+ catch(:return) { f.entity[:stat].eval(env) } || None
43
+ end
44
+
45
+ MakeInstance = Func.make_instance do |cls, *args|
46
+ if class_having_new = cls.base_traverse{|cls| cls["__new__"]}
47
+ madeobj = class_having_new["__new__"].call(*args)
48
+ else
49
+ madeobj = PyObject.new(:class => cls)
50
+ end
51
+ if madeobj[:class] == cls && madeobj.has_special_attr?("__init__")
52
+ madeobj.call_special_method("__init__", *args)
53
+ end
54
+ madeobj
55
+ end
56
+
57
+ # Method binds of primitive functions
58
+ Func["__get__"] = Func.make_instance{|_self, obj, objtype| Func.make_instance{|*args| _self.call(obj, *args)}}
59
+ Func["__call__"] = Func.make_instance{|_self, *args| ClosureCall.call(_self, *args)}
60
+ Int["__add__"] = Func.make_instance{|_self, other| AddTwoInt.call(_self, other)}
61
+ Int["__sub__"] = Func.make_instance{|_self, other| SubTwoInt.call(_self, other)}
62
+ Int["__mul__"] = Func.make_instance{|_self, other| MulTwoInt.call(_self, other)}
63
+ Int["__floordiv__"] = Func.make_instance{|_self, other| FloordivTwoInt.call(_self, other)}
64
+ Int["__pos__"] = Func.make_instance{|_self| PosInt.call(_self)}
65
+ Int["__neg__"] = Func.make_instance{|_self| NegInt.call(_self)}
66
+ Int["__bool__"] = Func.make_instance{|_self| IntToBool.call(_self)}
67
+ Int["__eq__"] = Func.make_instance{|_self, other| EQInt.call(_self, other)}
68
+ Int["__lt__"] = Func.make_instance{|_self, other| LTInt.call(_self, other)}
69
+ Int["__gt__"] = Func.make_instance{|_self, other| GTInt.call(_self, other)}
70
+ Type["__call__"] = Func.make_instance{|_self, *args| MakeInstance.call(_self, *args)}
71
+ end
72
+ end
@@ -0,0 +1,42 @@
1
+ require 'python/builtins'
2
+
3
+ module Python
4
+ class Environment < Hash
5
+ def initialize(initial_attr={})
6
+ self.merge!(initial_attr)
7
+ end
8
+
9
+ def resolve(name)
10
+ if self[name]
11
+ self[name]
12
+ elsif self[:parent]
13
+ self[:parent].resolve(name)
14
+ else
15
+ case name
16
+ when "True"
17
+ Builtins::True
18
+ when "False"
19
+ Builtins::False
20
+ when "None"
21
+ Builtins::None
22
+ when "print"
23
+ Builtins::Print
24
+ end
25
+ end
26
+ end
27
+
28
+ def set(name, pyobj)
29
+ self[name] = pyobj
30
+ end
31
+
32
+ def getlink
33
+ self
34
+ end
35
+ end
36
+
37
+ class ClassEnvironment < Environment
38
+ def getlink
39
+ self[:parent].getlink
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,29 @@
1
+ require 'python/parser/statement'
2
+ require 'python/parser/indent_converter'
3
+ require 'python/environment'
4
+
5
+ module Python
6
+ class FileInterpreter
7
+ ParsingError = Class.new(RuntimeError)
8
+
9
+ def initialize(code, bind={})
10
+ @code = code
11
+ @bind = bind
12
+ end
13
+
14
+ def parse
15
+ parser = Parser::StatementParser.file_input
16
+ result = parser.parse(Parser::IndentConverter.new.convert(@code))
17
+
18
+ if result.is_a?(Parser::Succeeded) && result.rest == ""
19
+ result.parsed
20
+ else
21
+ raise ParsingError.new
22
+ end
23
+ end
24
+
25
+ def execute
26
+ parse().eval(Environment.new(@bind))
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,206 @@
1
+ module Python
2
+ module Parser
3
+ Result = Class.new
4
+ Failed = Class.new(Result)
5
+ Succeeded = Class.new(Result)
6
+
7
+ class Succeeded
8
+ attr_reader :parsed, :rest
9
+ def initialize(parsed, rest)
10
+ @parsed, @rest = parsed, rest
11
+ end
12
+ end
13
+
14
+ class Combinator
15
+ ParserDefinitionError = Class.new(RuntimeError)
16
+
17
+ attr_accessor :f
18
+ def initialize(&proc)
19
+ @f = proc
20
+ end
21
+
22
+ def parse(inp)
23
+ @f.call(inp)
24
+ end
25
+
26
+ def >>(proc)
27
+ self.class.so(self, &proc)
28
+ end
29
+
30
+ def |(other)
31
+ self.class.either(self, other)
32
+ end
33
+
34
+ def +(other)
35
+ self.class.discardl(self, other)
36
+ end
37
+
38
+ def -(other)
39
+ self.class.discardr(self, other)
40
+ end
41
+
42
+ def self.ret(something)
43
+ new{|inp| Succeeded.new(something, inp)}
44
+ end
45
+
46
+ def self.failure
47
+ new{|inp| Failed.new}
48
+ end
49
+
50
+ def self.item
51
+ new{|inp| inp.size == 0 ? Failed.new : Succeeded.new(inp[0], inp[1, inp.size - 1])}
52
+ end
53
+
54
+ def self.so(parser, &proc)
55
+ new{|inp|
56
+ case result = parser.parse(inp)
57
+ when Failed
58
+ result
59
+ when Succeeded
60
+ proc.call(result.parsed).parse(result.rest)
61
+ else
62
+ raise "error."
63
+ end
64
+ }
65
+ end
66
+
67
+ def self.either(parser1, parser2)
68
+ new{|inp|
69
+ case result = parser1.parse(inp)
70
+ when Failed
71
+ parser2.parse(inp)
72
+ when Succeeded
73
+ result
74
+ else
75
+ raise "error."
76
+ end
77
+ }
78
+ end
79
+
80
+ def self.discardl(parser1, parser2)
81
+ parser1 >> proc{parser2}
82
+ end
83
+
84
+ def self.discardr(parser1, parser2)
85
+ parser1 >> proc{|x|
86
+ parser2 >> proc{
87
+ ret(x)
88
+ }}
89
+ end
90
+
91
+ def self.separator(element_parser, separating_token_str)
92
+ element_parser >> proc{|x|
93
+ many(token_str(separating_token_str) + element_parser) >> proc{|xs|
94
+ ret([x] + xs)
95
+ }}
96
+ end
97
+
98
+ def self.separator_allow_empty(element_parser, separating_token_str)
99
+ separator(element_parser, separating_token_str) | ret([])
100
+ end
101
+
102
+ def self.optional(parser)
103
+ (parser >> proc{|x| ret([x])}) | ret([])
104
+ end
105
+
106
+ def self.many(parser)
107
+ many1(parser) | ret([])
108
+ end
109
+
110
+ def self.many1(parser)
111
+ parser >> proc{|x|
112
+ many(parser) >> proc{|xs|
113
+ ret([x] + xs)
114
+ }}
115
+ end
116
+
117
+ def self.sat(&proc)
118
+ item >> proc{|c|
119
+ proc.call(c) ? ret(c) : failure
120
+ }
121
+ end
122
+
123
+ def self.char(char)
124
+ sat{|c| c == char}
125
+ end
126
+
127
+ def self.any_char(x)
128
+ case x
129
+ when String
130
+ chars = x.cahrs.map{|c| char(c)}
131
+ if chars.length < 0
132
+ raise ParserDefinitionError.new
133
+ else
134
+ chars.inject(&:|)
135
+ end
136
+ when Range
137
+ chars = x.map{|c| char(c)}
138
+ if chars.length < 0
139
+ raise ParserDefinitionError.new
140
+ else
141
+ chars.inject(&:|)
142
+ end
143
+ else
144
+ raise ParserDefinitionError.new
145
+ end
146
+ end
147
+
148
+ def self.string(str)
149
+ if str.size == 0
150
+ ret(str)
151
+ else
152
+ char(str[0]) >> proc{|c|
153
+ string(str[1, str.size - 1]) >> proc{
154
+ ret(str)
155
+ }
156
+ }
157
+ end
158
+ end
159
+
160
+ def self.whitespace
161
+ many(char("\s") | char("\t")) >> proc{|ws|
162
+ ret(:whitespace)
163
+ }
164
+ end
165
+
166
+ def self.token(parser)
167
+ whitespace >> proc{
168
+ parser >> proc{|x|
169
+ whitespace >> proc{
170
+ ret(x)
171
+ }}}
172
+ end
173
+
174
+ def self.token_str(str)
175
+ token(string(str))
176
+ end
177
+
178
+ def self.binopl(parser, op_proc_parser)
179
+ rest = proc{|a|
180
+ op_proc_parser >> proc{|f|
181
+ parser >> proc{|b|
182
+ rest.call(f.call(a, b))
183
+ }} | ret(a)
184
+ }
185
+ parser >> proc{|a|
186
+ rest.call(a)
187
+ }
188
+ end
189
+
190
+ def self.parser(name, &proc)
191
+ @cache ||= {}
192
+ spcls = class << self; self end
193
+ spcls.send(:define_method, name) do |*args|
194
+ key = [name, args]
195
+ if @cache[key]
196
+ return @cache[key]
197
+ else
198
+ @cache[key] = self.new{}
199
+ @cache[key].f = proc.call(*args).f
200
+ return @cache[key]
201
+ end
202
+ end
203
+ end
204
+ end
205
+ end
206
+ end
@@ -0,0 +1,125 @@
1
+ require 'python/parser/combinator'
2
+ require 'python/parser/integer'
3
+ require 'python/parser/identifier'
4
+ require 'python/syntax'
5
+ require 'python/builtins'
6
+
7
+ module Python
8
+ module Parser
9
+ class ExpressionParser < Combinator
10
+
11
+ parser :expression do
12
+ conditional_expression
13
+ end
14
+
15
+ parser :conditional_expression do
16
+ or_test >> proc{|true_exp|
17
+ token_str("if") + or_test - token_str("else") >> proc{|cond|
18
+ expression >> proc{|false_exp|
19
+ ret(Syntax::Conditional.new(cond, true_exp, false_exp))
20
+ }} | ret(true_exp)
21
+ }
22
+ end
23
+
24
+ parser :or_test do # -> Expression
25
+ orop = token_str("or") + ret(proc{|l, r| Syntax::Or.new(l, r)})
26
+ binopl(and_test, orop)
27
+ end
28
+
29
+ parser :and_test do # -> Expression
30
+ andop = token_str("and") + ret(proc{|l, r| Syntax::And.new(l, r)})
31
+ binopl(not_test, andop)
32
+ end
33
+
34
+ parser :not_test do # -> Expression
35
+ token_str("not") + not_test >> proc{|exp|
36
+ ret(Syntax::Not.new(exp))
37
+ } | comparison
38
+ end
39
+
40
+ parser :comparison do # -> Expression
41
+ a_expr >> proc{|head|
42
+ many(comp_operator >> proc{|op| a_expr >> proc{|exp| ret([op, exp])}}) >> proc{|tail|
43
+ if tail.length == 0
44
+ ret(head)
45
+ else
46
+ exps = [head] + tail.map{|op, exp| exp}
47
+ ops = tail.map{|op, exp| op}
48
+ comps = exps.each_cons(2).zip(ops).map{|p, op| Syntax::BinaryOp.new(op, p[0], p[1])}
49
+ ret(comps.inject{|l, r| Syntax::And.new(l, r)})
50
+ end
51
+ }
52
+ }
53
+ end
54
+
55
+ parser :comp_operator do # -> Symbol
56
+ token_str("==") + ret("__eq__") |
57
+ token_str(">=") + ret("__ge__") |
58
+ token_str("<=") + ret("__le__") |
59
+ token_str("<") + ret("__lt__") |
60
+ token_str(">") + ret("__gt__") |
61
+ token_str("!=") + ret("__ne__")
62
+ end
63
+
64
+ parser :a_expr do # -> Expression
65
+ addop = token_str("+") + ret(lambda{|l, r| Syntax::BinaryOp.new("__add__", l, r)})
66
+ subop = token_str("-") + ret(lambda{|l, r| Syntax::BinaryOp.new("__sub__", l, r)})
67
+ binopl(m_expr, addop | subop)
68
+ end
69
+
70
+ parser :m_expr do # -> Expression
71
+ mulop = token_str("*") + ret(proc{|l, r| Syntax::BinaryOp.new("__mul__", l, r)})
72
+ fdivop = token_str("//") + ret(proc{|l, r| Syntax::BinaryOp.new("__floordiv__", l, r)})
73
+ binopl(u_expr, mulop | fdivop)
74
+ end
75
+
76
+ parser :u_expr do # -> Expression
77
+ posop = token_str("+") + ret("__pos__")
78
+ negop = token_str("-") + ret("__neg__")
79
+ (posop | negop) >> proc{|op_name|
80
+ u_expr >> proc{|exp|
81
+ ret(Syntax::UnaryOp.new(op_name, exp))
82
+ }} | primary
83
+ end
84
+
85
+ parser :primary do
86
+ atom >> proc{|at|
87
+ many(attributeref | call) >> proc{|ps|
88
+ ret(ps.inject(at){|a, p| p.call(a)})
89
+ }}
90
+ end
91
+
92
+ parser :attributeref do
93
+ token_str(".") + IdentifierParser.identifier >> proc{|ident|
94
+ ret(proc{|receiver| Syntax::AttrRef.new(receiver, ident)})
95
+ }
96
+ end
97
+
98
+ parser :call do # -> Apply
99
+ token_str("(") + positional_arguments - token_str(")") >> proc{|args|
100
+ ret(proc{|callee| Syntax::Apply.new(callee, args)})
101
+ }
102
+ end
103
+
104
+ parser :positional_arguments do # -> [Expression]
105
+ separator_allow_empty(expression, ",")
106
+ end
107
+
108
+ parser :atom do
109
+ identifier | integerliteral | parenth_form
110
+ end
111
+
112
+ parser :identifier do
113
+ IdentifierParser.identifier >> proc{|ident| ret(Syntax::RefIdentifier.new(ident))}
114
+ end
115
+
116
+ parser :integerliteral do
117
+ IntegerParser.integer >> proc{|n| ret(Syntax::LiteralObject.new(Builtins::Int.make_instance(n)))}
118
+ end
119
+
120
+ parser :parenth_form do
121
+ token_str("(") + expression - token_str(")")
122
+ end
123
+ end
124
+ end
125
+ end