python 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|