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.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +60 -0
- data/Rakefile +2 -0
- data/bin/python.rb +16 -0
- data/examples/demo.py +10 -0
- data/examples/fibonacci.py +5 -0
- data/examples/twoclass.py +9 -0
- data/features/programmer_caclulate_numerical_expression.feature +50 -0
- data/features/programmer_execute_from_source_file.feature +10 -0
- data/features/programmer_starts_repl_console.feature +10 -0
- data/features/programmer_use_advanced_calculator.feature +35 -0
- data/features/programmer_use_class.feature +42 -0
- data/features/programmer_use_closure.feature +66 -0
- data/features/programmer_use_variables.feature +12 -0
- data/features/step_definitions/calculate_numerical_steps.rb +67 -0
- data/features/support/env.rb +2 -0
- data/lib/python.rb +10 -0
- data/lib/python/builtins.rb +72 -0
- data/lib/python/environment.rb +42 -0
- data/lib/python/file_interpreter.rb +29 -0
- data/lib/python/parser/combinator.rb +206 -0
- data/lib/python/parser/expression.rb +125 -0
- data/lib/python/parser/identifier.rb +22 -0
- data/lib/python/parser/indent_converter.rb +52 -0
- data/lib/python/parser/integer.rb +28 -0
- data/lib/python/parser/statement.rb +86 -0
- data/lib/python/pyobject.rb +129 -0
- data/lib/python/repl.rb +47 -0
- data/lib/python/syntax.rb +201 -0
- data/lib/python/version.rb +3 -0
- data/python.gemspec +24 -0
- data/spec/python/parser/expression_spec.rb +28 -0
- data/spec/python/parser/indent_converter_spec.rb +36 -0
- data/spec/python/pyobject_spec.rb +20 -0
- data/spec/python/repl_spec.rb +14 -0
- data/spec/spec_helper.rb +1 -0
- metadata +125 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'python/parser/combinator'
|
2
|
+
|
3
|
+
module Python
|
4
|
+
module Parser
|
5
|
+
class IdentifierParser < Combinator
|
6
|
+
parser :identifier do # -> String
|
7
|
+
token(xid_start >> proc{|head|
|
8
|
+
many(xid_continue) >> proc{|rests|
|
9
|
+
ret(head + rests.inject("", &:+))
|
10
|
+
}})
|
11
|
+
end
|
12
|
+
|
13
|
+
parser :xid_start do # -> Char (1-lenght String)
|
14
|
+
any_char("A".."Z") | any_char("a".."z") | char("_")
|
15
|
+
end
|
16
|
+
|
17
|
+
parser :xid_continue do # -> Char (1-lenght String)
|
18
|
+
xid_start | any_char("0".."9")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Python
|
2
|
+
module Parser
|
3
|
+
class IndentConverter
|
4
|
+
IndentConversionError = Class.new(RuntimeError)
|
5
|
+
|
6
|
+
INDENT = "$I"
|
7
|
+
DEDENT = "$D"
|
8
|
+
NEWLINE = "\n"
|
9
|
+
|
10
|
+
def convert(str)
|
11
|
+
stack = [0]
|
12
|
+
converted_lines = []
|
13
|
+
lines = str.gsub("\r\n", "\n").gsub("\r", "\n").split("\n") + [""]
|
14
|
+
lines.each do |line|
|
15
|
+
ilevel = indent_level(line)
|
16
|
+
if ilevel > stack.last
|
17
|
+
stack << ilevel
|
18
|
+
converted_lines << convert_line(line, INDENT)
|
19
|
+
elsif ilevel < stack.last
|
20
|
+
dedent_livel = 0
|
21
|
+
while ilevel < stack.last
|
22
|
+
dedent_livel += 1
|
23
|
+
stack.pop
|
24
|
+
end
|
25
|
+
unless ilevel == stack.last
|
26
|
+
raise IndentConversionError.new
|
27
|
+
end
|
28
|
+
converted_lines << convert_line(line, DEDENT * dedent_livel)
|
29
|
+
else
|
30
|
+
converted_lines << convert_line(line, "")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
converted_lines.join(NEWLINE) + NEWLINE
|
34
|
+
end
|
35
|
+
|
36
|
+
def indent_level(line)
|
37
|
+
line.chars.take_while{|c| c == "\s" || c == "\t"}.inject(0) do |acc, c|
|
38
|
+
case c
|
39
|
+
when "\s"
|
40
|
+
acc + 1
|
41
|
+
when "\t"
|
42
|
+
acc - (acc % 8) + 8
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def convert_line(line, token)
|
48
|
+
token + line.chars.drop_while{|c| c == "\s" || c == "\t"}.inject("", &:+)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'python/parser/combinator'
|
2
|
+
|
3
|
+
module Python
|
4
|
+
module Parser
|
5
|
+
class IntegerParser < Combinator
|
6
|
+
parser :integer do # -> Integer
|
7
|
+
token(decimalinteger)
|
8
|
+
end
|
9
|
+
|
10
|
+
parser :decimalinteger do # -> Integer
|
11
|
+
nonzero = nonzerodigit >> proc{|head|
|
12
|
+
many(digit) >> proc{|tail|
|
13
|
+
ret((head + tail.inject("", &:+)).to_i)
|
14
|
+
}}
|
15
|
+
zero = many1(char("0")) >> proc{|zs| ret(0)}
|
16
|
+
nonzero | zero
|
17
|
+
end
|
18
|
+
|
19
|
+
parser :nonzerodigit do # -> Char (1-length String)
|
20
|
+
any_char("1".."9")
|
21
|
+
end
|
22
|
+
|
23
|
+
parser :digit do # -> Char (1-length String)
|
24
|
+
any_char("0".."9")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'python/parser/combinator'
|
2
|
+
require 'python/syntax'
|
3
|
+
require 'python/parser/identifier'
|
4
|
+
|
5
|
+
module Python
|
6
|
+
module Parser
|
7
|
+
class StatementParser < Combinator
|
8
|
+
|
9
|
+
NEWLINE = token_str("\n")
|
10
|
+
INDENT = token_str("$I")
|
11
|
+
DEDENT = token_str("$D")
|
12
|
+
|
13
|
+
parser :file_input do # -> StatementList
|
14
|
+
many(NEWLINE | statement) >> proc{|stmts|
|
15
|
+
ret(Syntax::StatementList.new(stmts.select{|stmt| stmt.is_a?(Syntax::Statement)}))
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
parser :suite do # -> StatementList
|
20
|
+
stmt_list - NEWLINE | NEWLINE + INDENT + many1(statement) - many(NEWLINE) - DEDENT >> proc{|stmts|
|
21
|
+
ret(Syntax::StatementList.new(stmts))
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
parser :statement do # -> Statement
|
26
|
+
compound_stmt | stmt_list - NEWLINE
|
27
|
+
end
|
28
|
+
|
29
|
+
parser :compound_stmt do # -> Statement
|
30
|
+
classdef | funcdef
|
31
|
+
end
|
32
|
+
|
33
|
+
parser :funcdef do # -> Statement
|
34
|
+
token_str("def") + IdentifierParser.identifier - token_str("(") >> proc{|funcname|
|
35
|
+
separator_allow_empty(IdentifierParser.identifier, ",") - token_str(")") - token_str(":") >> proc{|params|
|
36
|
+
suite >> proc{|stmt|
|
37
|
+
ret(Syntax::Def.new(funcname, stmt, params))
|
38
|
+
}}}
|
39
|
+
end
|
40
|
+
|
41
|
+
parser :classdef do # -> Statement
|
42
|
+
token_str("class") + IdentifierParser.identifier >> proc{|classname|
|
43
|
+
((token_str("(") + separator(ExpressionParser.expression, ",") - token_str(")")) | ret([])) - token_str(":") >> proc{|base_exps|
|
44
|
+
suite >> proc{|stmt|
|
45
|
+
ret(Syntax::ClassDef.new(classname, stmt, base_exps))
|
46
|
+
}}}
|
47
|
+
end
|
48
|
+
|
49
|
+
parser :stmt_list do # -> StatementList
|
50
|
+
separator(simple_stmt, ";") - (token_str(";") | ret(nil)) >> proc{|stmts|
|
51
|
+
ret(Syntax::StatementList.new(stmts))
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
parser :simple_stmt do # -> Statement
|
56
|
+
assignment_stmt | return_stmt | expression_stmt
|
57
|
+
end
|
58
|
+
|
59
|
+
parser :assignment_stmt do # -> Statement
|
60
|
+
((IdentifierParser.identifier - token_str("=")) | (ExpressionParser::primary - token_str("="))) >> proc{|target|
|
61
|
+
ExpressionParser.expression >> proc{|exp|
|
62
|
+
case target
|
63
|
+
when String
|
64
|
+
ret(Syntax::AssignIdentifier.new(target, exp))
|
65
|
+
when Syntax::AttrRef
|
66
|
+
ret(Syntax::AssignAttr.new(target.receiver, target.attrname, exp))
|
67
|
+
else
|
68
|
+
p target
|
69
|
+
failure
|
70
|
+
end
|
71
|
+
}}
|
72
|
+
end
|
73
|
+
|
74
|
+
parser :return_stmt do # -> Statement
|
75
|
+
token_str("return") + (ExpressionParser.expression | ret(nil)) >> proc{|exp|
|
76
|
+
ret(Syntax::Return.new(exp))
|
77
|
+
}
|
78
|
+
end
|
79
|
+
|
80
|
+
parser :expression_stmt do
|
81
|
+
ExpressionParser.expression
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
module Python
|
2
|
+
class PyObject < Hash
|
3
|
+
def initialize(attr={})
|
4
|
+
self.merge!(attr)
|
5
|
+
end
|
6
|
+
|
7
|
+
def make_instance(entity=nil, &entity_proc)
|
8
|
+
PyObject.new(:class => self, :entity => entity || entity_proc)
|
9
|
+
end
|
10
|
+
|
11
|
+
def entity
|
12
|
+
self[:entity]
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(*args)
|
16
|
+
if self[:entity] && self[:entity].is_a?(Proc)
|
17
|
+
self[:entity].call(*args)
|
18
|
+
else
|
19
|
+
call_special_method("__call__", *args)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def call_special_method(method_name, *args)
|
24
|
+
get_special_attr(method_name).call(*args)
|
25
|
+
end
|
26
|
+
|
27
|
+
def get_special_attr(name)
|
28
|
+
if !self[:class]
|
29
|
+
raise "failed to get special attr #{name} from #{self}: #{self} doesn't have class"
|
30
|
+
elsif cls = self[:class].base_traverse{|cls| cls[name] && cls[name].datadescriptor?}
|
31
|
+
cls[name].get_get_method.call(cls[name], self, self[:class])
|
32
|
+
elsif cls = self[:class].base_traverse{|cls| cls[name]}
|
33
|
+
if cls[name].descriptor?
|
34
|
+
cls[name].get_get_method.call(cls[name], self, self[:class])
|
35
|
+
else
|
36
|
+
cls[name]
|
37
|
+
end
|
38
|
+
else
|
39
|
+
raise "failed to get special attr #{name} from #{self}: #{name} is not found"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def has_special_attr?(name)
|
44
|
+
get_special_attr(name)
|
45
|
+
rescue
|
46
|
+
nil
|
47
|
+
end
|
48
|
+
|
49
|
+
def get_attr(name)
|
50
|
+
if !self[:class]
|
51
|
+
raise "failed to get attr #{name} from #{self}: #{self} doesn't have class"
|
52
|
+
elsif cls = self[:class].base_traverse{|cls| cls[name] && cls[name].datadescriptor?}
|
53
|
+
cls[name].get_get_method.call(cls[name], self, self[:class])
|
54
|
+
elsif owner = self.base_traverse{|owner| owner[name]}
|
55
|
+
owner[name]
|
56
|
+
elsif cls = self[:class].base_traverse{|cls| cls[name]}
|
57
|
+
if cls[name].descriptor?
|
58
|
+
cls[name].get_get_method.call(cls[name], self, self[:class])
|
59
|
+
else
|
60
|
+
cls[name]
|
61
|
+
end
|
62
|
+
else
|
63
|
+
raise "failed to get attr #{name} from #{self}: #{name} is not found"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def has_attr?(name)
|
68
|
+
get_attr(name)
|
69
|
+
rescue
|
70
|
+
nil
|
71
|
+
end
|
72
|
+
|
73
|
+
def set_attr(name, pyobj)
|
74
|
+
if !self[:class]
|
75
|
+
raise "failed to set attr #{name} on #{self}: #{self} doesn't have class"
|
76
|
+
elsif cls = self[:class].base_traverse{|cls| cls[name] && cls[name].datadescriptor?}
|
77
|
+
cls[name].get_set_method.call(cls[name], self, pyobj)
|
78
|
+
else
|
79
|
+
self[name] = pyobj
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def get_get_method
|
84
|
+
cls = self[:class].base_traverse{|cls| cls["__get__"]}
|
85
|
+
cls["__get__"]
|
86
|
+
end
|
87
|
+
|
88
|
+
def descriptor?
|
89
|
+
self[:class] && self[:class].base_traverse{|cls| cls["__get__"]}
|
90
|
+
end
|
91
|
+
|
92
|
+
def get_set_method
|
93
|
+
cls = self[:class].base_traverse{|cls| cls["__set__"] || cls["__delete__"]}
|
94
|
+
unless cls["__set__"]
|
95
|
+
raise "cannot set data on datadescriptor '#{cls}'"
|
96
|
+
else
|
97
|
+
cls["__set__"]
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def datadescriptor?
|
102
|
+
descriptor? && self[:class].base_traverse{|cls| cls["__set__"] || cls["__delete__"]}
|
103
|
+
end
|
104
|
+
|
105
|
+
def base_traverse(&proc)
|
106
|
+
queue = [self]
|
107
|
+
until queue.empty?
|
108
|
+
cls = queue.pop
|
109
|
+
if judge = proc.call(cls)
|
110
|
+
return cls
|
111
|
+
end
|
112
|
+
queue += (cls[:bases] || [])
|
113
|
+
end
|
114
|
+
return nil
|
115
|
+
end
|
116
|
+
|
117
|
+
def inspect
|
118
|
+
if self[:name]
|
119
|
+
self[:name]
|
120
|
+
elsif self[:entity]
|
121
|
+
self[:entity].to_s
|
122
|
+
elsif self[:class] && self[:class][:name]
|
123
|
+
"<instance of:#{self[:class][:name]}"
|
124
|
+
else
|
125
|
+
super
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
data/lib/python/repl.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'python/parser/statement'
|
2
|
+
require 'python/environment'
|
3
|
+
|
4
|
+
module Python
|
5
|
+
class REPL
|
6
|
+
ParsingError = Class.new(RuntimeError)
|
7
|
+
|
8
|
+
def initialize(output)
|
9
|
+
@output = output
|
10
|
+
@env = Environment.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def start
|
14
|
+
prompt
|
15
|
+
end
|
16
|
+
|
17
|
+
def read_eval_print(code)
|
18
|
+
print(eval(read(code)))
|
19
|
+
end
|
20
|
+
|
21
|
+
def read(code)
|
22
|
+
parser = Parser::StatementParser.stmt_list
|
23
|
+
result = parser.parse(code)
|
24
|
+
if result.is_a?(Parser::Succeeded) && result.rest.chomp == ""
|
25
|
+
result.parsed
|
26
|
+
else
|
27
|
+
raise ParsingError.new
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def eval(exp)
|
32
|
+
exp.eval(@env)
|
33
|
+
end
|
34
|
+
|
35
|
+
def print(obj)
|
36
|
+
if obj == nil
|
37
|
+
@output.print ""
|
38
|
+
else
|
39
|
+
@output.puts obj.inspect
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def prompt
|
44
|
+
@output.print "python.rb> "
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,201 @@
|
|
1
|
+
require 'python/pyobject'
|
2
|
+
require 'python/builtins'
|
3
|
+
|
4
|
+
module Python
|
5
|
+
module Syntax
|
6
|
+
class Statement
|
7
|
+
def attrs
|
8
|
+
[]
|
9
|
+
end
|
10
|
+
|
11
|
+
def eval_proc
|
12
|
+
proc{}
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(*args)
|
16
|
+
min_argc = attrs.take_while{|attr| attr.is_a?(Symbol)}.count
|
17
|
+
max_argc = attrs.flatten.count
|
18
|
+
unless min_argc <= args.length && args.length <= max_argc
|
19
|
+
raise "Argument error: failed to make instance of #{self.class.name}." +
|
20
|
+
"expected: #{attrs}, actual: #{args}"
|
21
|
+
end
|
22
|
+
attrs.flatten.zip(args).each do |name, val|
|
23
|
+
instance_variable_set("@#{name}".to_sym, val)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def eval(env)
|
28
|
+
instance_exec(env, &eval_proc)
|
29
|
+
end
|
30
|
+
|
31
|
+
def ==(other)
|
32
|
+
self.class == other.class && attrs.flatten.all? do |vname|
|
33
|
+
ivname = "@#{vname}".to_sym
|
34
|
+
self.instance_variable_get(ivname) == other.instance_variable_get(ivname)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
Expression = Class.new(Statement)
|
39
|
+
|
40
|
+
def self.stmt(*attrs, &eval)
|
41
|
+
define_element_type(Statement, *attrs, &eval)
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.exp(*attrs, &eval)
|
45
|
+
define_element_type(Expression, *attrs, &eval)
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.define_element_type(base, *attrs, &eval_proc)
|
49
|
+
cls = Class.new(base)
|
50
|
+
cls.send(:define_method, :attrs) { attrs }
|
51
|
+
cls.send(:define_method, :eval_proc) { eval_proc }
|
52
|
+
cls.send(:attr_reader, *attrs.flatten)
|
53
|
+
return cls
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.draw_syntax_tree(val, depth=0)
|
57
|
+
case val
|
58
|
+
when Statement
|
59
|
+
puts (" " * depth) + "Node<#{val.class.name}>:"
|
60
|
+
val.attrs.flatten.each do |attrname|
|
61
|
+
puts (" " * (depth + 1)) + "#{attrname}:"
|
62
|
+
draw_syntax_tree(val.instance_variable_get("@#{attrname}".to_sym), depth + 2)
|
63
|
+
end
|
64
|
+
when Array
|
65
|
+
val.each_with_index do |v, i|
|
66
|
+
puts (" " * (depth + 1)) + "[#{i}]"
|
67
|
+
draw_syntax_tree(v, depth + 2)
|
68
|
+
end
|
69
|
+
else
|
70
|
+
puts (" " * (depth + 1)) + val.to_s
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Exceptions possibly occurring when evaluating
|
75
|
+
PyBoolizeError = Class.new(RuntimeError)
|
76
|
+
PyNameError = Class.new(RuntimeError)
|
77
|
+
PyCallError = Class.new(RuntimeError)
|
78
|
+
|
79
|
+
def self.pytrue?(object)
|
80
|
+
boolized = object.call_special_method("__bool__")
|
81
|
+
if boolized == Builtins::True
|
82
|
+
return true
|
83
|
+
elsif boolized == Builtins::False
|
84
|
+
return false
|
85
|
+
else
|
86
|
+
raise PyBoolizeError.new
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
#--------------------
|
91
|
+
# AST-elements of Statements
|
92
|
+
#--------------------
|
93
|
+
|
94
|
+
StatementList = stmt(:stmts) do |env|
|
95
|
+
@stmts.inject(nil) do |acc, stmt|
|
96
|
+
stmt.eval(env)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
AssignIdentifier = stmt(:name, :exp) do |env|
|
101
|
+
env.set(@name, @exp.eval(env))
|
102
|
+
nil
|
103
|
+
end
|
104
|
+
|
105
|
+
AssignAttr = stmt(:receiver, :attrname, :exp) do |env|
|
106
|
+
@receiver.eval(env).set_attr(@attrname, @exp.eval(env))
|
107
|
+
nil
|
108
|
+
end
|
109
|
+
|
110
|
+
Def = stmt(:name, :stat, :fix_param_names, [:rest_param_name]) do |env|
|
111
|
+
entity = {:fix_param_names => @fix_param_names,
|
112
|
+
:rest_param_name => @rest_param_name,
|
113
|
+
:stat => @stat,
|
114
|
+
:env => env.getlink}
|
115
|
+
env.set(@name, Builtins::Func.make_instance(entity))
|
116
|
+
nil
|
117
|
+
end
|
118
|
+
|
119
|
+
ClassDef = stmt(:name, :stat, :base_exps) do |env|
|
120
|
+
bases = @base_exps.map{|e| e.eval(env)}
|
121
|
+
klassenv = ClassEnvironment.new(:parent => env)
|
122
|
+
stat.eval(klassenv)
|
123
|
+
klass = PyObject.new(klassenv.merge(:class => Builtins::Type, :bases => bases))
|
124
|
+
env.set(@name, klass)
|
125
|
+
nil
|
126
|
+
end
|
127
|
+
|
128
|
+
Return = stmt([:exp]) do |env|
|
129
|
+
res = if @exp then @exp.eval(env) else Builtins::None end
|
130
|
+
throw :return, res
|
131
|
+
end
|
132
|
+
|
133
|
+
#--------------------
|
134
|
+
# AST-elements of Expressions
|
135
|
+
#--------------------
|
136
|
+
|
137
|
+
Apply = exp(:callee_exp, :arg_exps) do |env|
|
138
|
+
@callee_exp.eval(env).call(*@arg_exps.map{|e| e.eval(env)})
|
139
|
+
end
|
140
|
+
|
141
|
+
AttrRef = exp(:receiver, :attrname) do |env|
|
142
|
+
@receiver.eval(env).get_attr(@attrname)
|
143
|
+
end
|
144
|
+
|
145
|
+
RefIdentifier = exp(:name) do |env|
|
146
|
+
if res = env.resolve(@name)
|
147
|
+
res
|
148
|
+
else
|
149
|
+
raise PyNameError.new("Unbound variable: #{@name}")
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
Conditional = exp(:cond_exp, :true_exp, :false_exp) do |env|
|
154
|
+
if Syntax.pytrue?(@cond_exp.eval(env))
|
155
|
+
@true_exp.eval(env)
|
156
|
+
else
|
157
|
+
@false_exp.eval(env)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
UnaryOp = exp(:op_name, :exp) do |env|
|
162
|
+
@exp.eval(env).call_special_method(@op_name)
|
163
|
+
end
|
164
|
+
|
165
|
+
BinaryOp = exp(:op_name, :left_exp, :right_exp) do |env|
|
166
|
+
left = @left_exp.eval(env)
|
167
|
+
right = @right_exp.eval(env)
|
168
|
+
left.call_special_method(@op_name, right)
|
169
|
+
end
|
170
|
+
|
171
|
+
And = exp(:left_exp, :right_exp) do |env|
|
172
|
+
left = @left_exp.eval(env)
|
173
|
+
if !Syntax.pytrue?(left)
|
174
|
+
left
|
175
|
+
else
|
176
|
+
@right_exp.eval(env)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
Or = exp(:left_exp, :right_exp) do |env|
|
181
|
+
left = @left_exp.eval(env)
|
182
|
+
if Syntax.pytrue?(left)
|
183
|
+
left
|
184
|
+
else
|
185
|
+
@right_exp.eval(env)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
Not = exp(:cond_exp) do |env|
|
190
|
+
if Syntax.pytrue?(@cond_exp.eval(env))
|
191
|
+
Builtins::False
|
192
|
+
else
|
193
|
+
Builtins::True
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
LiteralObject = exp(:object) do |env|
|
198
|
+
@object
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|