sbyc 0.1.3 → 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/sbyc.rb +1 -5
- data/lib/sbyc/codetree.rb +79 -77
- data/lib/sbyc/codetree/ast_node.rb +117 -115
- data/lib/sbyc/codetree/eval/ast_node_ext.rb +33 -31
- data/lib/sbyc/codetree/eval/functional_eval.rb +33 -31
- data/lib/sbyc/codetree/eval/object_eval.rb +33 -31
- data/lib/sbyc/codetree/matching/ast_node_ext.rb +13 -11
- data/lib/sbyc/codetree/matching/match_data.rb +25 -23
- data/lib/sbyc/codetree/matching/matcher.rb +73 -71
- data/lib/sbyc/codetree/name2x/delegate.rb +56 -54
- data/lib/sbyc/codetree/name2x/module_delegate.rb +23 -22
- data/lib/sbyc/codetree/proc_parser.rb +101 -99
- data/lib/sbyc/codetree/producing/producer.rb +69 -67
- data/lib/sbyc/codetree/producing/tracing_methods.rb +66 -64
- data/lib/sbyc/codetree/rewriting/class_methods.rb +15 -13
- data/lib/sbyc/codetree/rewriting/compiler.rb +27 -25
- data/lib/sbyc/codetree/rewriting/instance_methods.rb +80 -78
- data/lib/sbyc/codetree/rewriting/match.rb +51 -49
- data/lib/sbyc/shortspaces.rb +3 -0
- data/lib/sbyc/type_system.rb +4 -2
- data/lib/sbyc/type_system/contract.rb +38 -36
- data/lib/sbyc/type_system/errors.rb +8 -6
- data/lib/sbyc/type_system/ruby.rb +137 -121
- data/test/spec/spec_helper.rb +1 -1
- data/test/spec/unit/sbyc/type_system/ruby/boolean.spec +14 -0
- data/test/spec/unit/sbyc/type_system/ruby/coerce.spec +10 -1
- metadata +6 -4
@@ -1,6 +1,8 @@
|
|
1
|
-
module
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
1
|
+
module SByC
|
2
|
+
module TypeSystem
|
3
|
+
class Error < StandardError; end
|
4
|
+
class InvalidValueLiteralError < Error; end
|
5
|
+
class NoSuchLiteralError < Error; end
|
6
|
+
class CoercionError < Error; end
|
7
|
+
end # module TypeSystem
|
8
|
+
end # module SByC
|
@@ -1,135 +1,151 @@
|
|
1
1
|
require 'date'
|
2
2
|
require 'time'
|
3
|
-
module
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
module SByC
|
4
|
+
module TypeSystem
|
5
|
+
#
|
6
|
+
# Implements a basic TypeSystem that mimics Ruby's type system.
|
7
|
+
#
|
8
|
+
module Ruby
|
8
9
|
|
9
|
-
|
10
|
-
|
10
|
+
# Marker module for ruby Boolean values
|
11
|
+
module Boolean
|
12
|
+
|
13
|
+
# Returns true if value is a boolean
|
14
|
+
def self.===(value)
|
15
|
+
(value == true) or (value == false)
|
16
|
+
end
|
11
17
|
|
12
|
-
# Ruby classes for which value.inspect will work for returning
|
13
|
-
# a valid literal
|
14
|
-
SAFE_LITERAL_CLASSES = {}
|
15
|
-
[NilClass, TrueClass, FalseClass,
|
16
|
-
Fixnum, Bignum,
|
17
|
-
Float,
|
18
|
-
String,
|
19
|
-
Symbol,
|
20
|
-
Class,
|
21
|
-
Module,
|
22
|
-
Regexp].each{|c| SAFE_LITERAL_CLASSES[c] = true}
|
23
|
-
|
24
|
-
#
|
25
|
-
# Returns value.class
|
26
|
-
#
|
27
|
-
# @see TypeSystem::Contract#type_of
|
28
|
-
#
|
29
|
-
def type_of(value)
|
30
|
-
value.class
|
31
18
|
end
|
19
|
+
|
20
|
+
# Methods
|
21
|
+
module Methods
|
22
|
+
|
23
|
+
# Ruby classes for which value.inspect will work for returning
|
24
|
+
# a valid literal
|
25
|
+
SAFE_LITERAL_CLASSES = {}
|
26
|
+
[NilClass, TrueClass, FalseClass,
|
27
|
+
Fixnum, Bignum,
|
28
|
+
Float,
|
29
|
+
String,
|
30
|
+
Symbol,
|
31
|
+
Class,
|
32
|
+
Module,
|
33
|
+
Regexp].each{|c| SAFE_LITERAL_CLASSES[c] = true}
|
34
|
+
|
35
|
+
#
|
36
|
+
# Returns value.class
|
37
|
+
#
|
38
|
+
# @see TypeSystem::Contract#type_of
|
39
|
+
#
|
40
|
+
def type_of(value)
|
41
|
+
value.class
|
42
|
+
end
|
32
43
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
44
|
+
#
|
45
|
+
# Converts _value_ to a ruby literal and returns it.
|
46
|
+
#
|
47
|
+
# Behavior of the algorithm when th value cannot be recognized depends
|
48
|
+
# on the :fallback option:
|
49
|
+
# * when set to :fail, it raises a NoSuchLiteralError
|
50
|
+
# * when set to :inspect, it returns <code>value.inspect</code>
|
51
|
+
# * when set to :marshal it uses <code>Marshal::dump(value)</code>
|
52
|
+
# * when set to :json it uses <code>JSON::generate(value)</code>
|
53
|
+
#
|
54
|
+
# @see TypeSystem::Contract#to_literal(value)
|
55
|
+
#
|
56
|
+
def to_literal(value, options = {:fallback => :fail})
|
57
|
+
if value.respond_to?(:to_ruby_literal)
|
58
|
+
value.to_ruby_literal
|
59
|
+
elsif value == (1.0/0)
|
60
|
+
return '(1.0/0)'
|
61
|
+
elsif value == -(1.0/0)
|
62
|
+
return '(-1.0/0)'
|
63
|
+
elsif SAFE_LITERAL_CLASSES.key?(type_of(value))
|
64
|
+
value.inspect
|
65
|
+
elsif value.kind_of?(Array)
|
66
|
+
"[" + value.collect{|v| to_literal(v, options)}.join(', ') + "]"
|
67
|
+
elsif value.kind_of?(Hash)
|
68
|
+
"{" + value.collect{|pair| "#{to_literal(pair[0], options)} => #{to_literal(pair[1], options)}"}.join(', ') + "}"
|
69
|
+
elsif value.kind_of?(Date)
|
70
|
+
"Date::parse(#{value.to_s.inspect})"
|
71
|
+
elsif value.kind_of?(Time)
|
72
|
+
"Time::parse(#{value.inspect.inspect})"
|
73
|
+
else
|
74
|
+
case options[:fallback]
|
75
|
+
when :inspect
|
76
|
+
value.inspect
|
77
|
+
when :marshal
|
78
|
+
"Marshal::load(#{Marshal::dump(value).inspect})"
|
79
|
+
when :json
|
80
|
+
require 'json'
|
81
|
+
JSON::generate(value)
|
82
|
+
when :fail, nil
|
83
|
+
raise NoSuchLiteralError, "Unable to convert #{value.inspect} to a ruby literal"
|
84
|
+
else
|
85
|
+
raise ArgumentError, "Invalid fallback option #{options[:fallback]}"
|
86
|
+
end
|
75
87
|
end
|
76
88
|
end
|
77
|
-
end
|
78
89
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
90
|
+
#
|
91
|
+
# Returns result of Kernel.eval(str)
|
92
|
+
#
|
93
|
+
# @see TypeSystem::Contract#parse_literal(str)
|
94
|
+
#
|
95
|
+
def parse_literal(str)
|
96
|
+
Kernel.eval(str)
|
97
|
+
rescue Exception => ex
|
98
|
+
raise TypeSystem::InvalidValueLiteralError, "Invalid ruby value literal #{str.inspect}", ex.backtrace
|
99
|
+
end
|
89
100
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
return
|
101
|
+
#
|
102
|
+
# Coerces a string to a given class.
|
103
|
+
#
|
104
|
+
# @see TypeSystem::Contract#coerce(str)
|
105
|
+
#
|
106
|
+
def coerce(str, clazz)
|
107
|
+
return str if str.kind_of?(clazz)
|
108
|
+
if clazz == NilClass
|
109
|
+
return nil if str.empty? or str == "nil"
|
110
|
+
elsif clazz == Ruby::Boolean
|
111
|
+
return true if str.to_s == "true"
|
112
|
+
return false if str.to_s == "false"
|
113
|
+
elsif clazz == TrueClass
|
114
|
+
return true if str == "true"
|
115
|
+
elsif clazz == FalseClass
|
116
|
+
return false if str == "false"
|
117
|
+
elsif [Fixnum, Bignum, Integer].include?(clazz)
|
118
|
+
if str =~ /^[-+]?[0-9]+$/
|
119
|
+
i = str.to_i
|
120
|
+
return i if i.kind_of?(clazz)
|
121
|
+
end
|
122
|
+
elsif clazz == Float
|
123
|
+
if str =~ /^[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?$/
|
124
|
+
return str.to_f
|
125
|
+
end
|
126
|
+
elsif clazz == String
|
127
|
+
return str
|
128
|
+
elsif clazz == Symbol
|
129
|
+
return str.to_sym
|
130
|
+
elsif clazz == Class or clazz == Module
|
131
|
+
parts, current = str.split("::"), Kernel
|
132
|
+
parts.each{|part| current = current.const_get(part.to_sym)}
|
133
|
+
return current if current.kind_of?(clazz)
|
134
|
+
elsif clazz == Regexp
|
135
|
+
return Regexp::compile(str)
|
136
|
+
elsif clazz.respond_to?(:parse)
|
137
|
+
return clazz.parse(str)
|
106
138
|
end
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
return str
|
113
|
-
elsif clazz == Symbol
|
114
|
-
return str.to_sym
|
115
|
-
elsif clazz == Class or clazz == Module
|
116
|
-
parts, current = str.split("::"), Kernel
|
117
|
-
parts.each{|part| current = current.const_get(part.to_sym)}
|
118
|
-
return current if current.kind_of?(clazz)
|
119
|
-
elsif clazz == Regexp
|
120
|
-
return Regexp::compile(str)
|
121
|
-
elsif clazz.respond_to?(:parse)
|
122
|
-
return clazz.parse(str)
|
139
|
+
raise TypeSystem::CoercionError, "Unable to coerce #{str} to a #{clazz}"
|
140
|
+
rescue TypeSystem::CoercionError
|
141
|
+
raise
|
142
|
+
rescue StandardError => ex
|
143
|
+
raise TypeSystem::CoercionError, "Unable to coerce #{str} to a #{clazz}: #{ex.message}"
|
123
144
|
end
|
124
|
-
raise TypeSystem::CoercionError, "Unable to coerce #{str} to a #{clazz}"
|
125
|
-
rescue TypeSystem::CoercionError
|
126
|
-
raise
|
127
|
-
rescue StandardError => ex
|
128
|
-
raise TypeSystem::CoercionError, "Unable to coerce #{str} to a #{clazz}: #{ex.message}"
|
129
|
-
end
|
130
145
|
|
131
|
-
|
132
|
-
|
146
|
+
end # module Methods
|
147
|
+
extend(Methods)
|
133
148
|
|
134
|
-
|
135
|
-
end # module TypeSystem
|
149
|
+
end # class Ruby
|
150
|
+
end # module TypeSystem
|
151
|
+
end # module SByC
|
data/test/spec/spec_helper.rb
CHANGED
@@ -0,0 +1,14 @@
|
|
1
|
+
require File.expand_path('../../../../../spec_helper', __FILE__)
|
2
|
+
require 'sbyc/type_system/ruby'
|
3
|
+
|
4
|
+
describe "TypeSystem::Ruby::Boolean" do
|
5
|
+
|
6
|
+
subject{ TypeSystem::Ruby::Boolean }
|
7
|
+
|
8
|
+
it { should === true }
|
9
|
+
|
10
|
+
it { should === false }
|
11
|
+
|
12
|
+
it { should_not === nil }
|
13
|
+
|
14
|
+
end
|
@@ -9,6 +9,7 @@ describe "TypeSystem::Ruby#coerce" do
|
|
9
9
|
|
10
10
|
safe_representors = {
|
11
11
|
NilClass => [ nil ],
|
12
|
+
::SByC::TypeSystem::Ruby::Boolean => [ true, false ],
|
12
13
|
TrueClass => [ true ],
|
13
14
|
FalseClass => [ false ],
|
14
15
|
Fixnum => [ -(2**(0.size * 8 - 2)), -1, 0, 1, 10, (2**(0.size * 8 - 2) - 1)],
|
@@ -23,12 +24,20 @@ describe "TypeSystem::Ruby#coerce" do
|
|
23
24
|
|
24
25
|
safe_representors.each_pair do |clazz, values|
|
25
26
|
values.each do |value|
|
26
|
-
|
27
|
+
|
28
|
+
describe "When coercing '#{value} to a #{clazz}" do
|
29
|
+
|
27
30
|
it "should return #{value}" do
|
28
31
|
str = value.kind_of?(Regexp) ? value.inspect[1..-2] : value.to_s
|
29
32
|
TypeSystem::Ruby::coerce(str, clazz).should == value
|
30
33
|
end
|
34
|
+
|
35
|
+
it "should be friendly" do
|
36
|
+
TypeSystem::Ruby::coerce(value, clazz).should == value
|
37
|
+
end
|
38
|
+
|
31
39
|
end
|
40
|
+
|
32
41
|
end
|
33
42
|
end
|
34
43
|
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sbyc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 19
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 1
|
9
|
-
-
|
10
|
-
version: 0.1.
|
9
|
+
- 4
|
10
|
+
version: 0.1.4
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Bernard Lambeau
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-
|
18
|
+
date: 2010-09-08 00:00:00 +02:00
|
19
19
|
default_executable:
|
20
20
|
dependencies: []
|
21
21
|
|
@@ -51,6 +51,7 @@ files:
|
|
51
51
|
- lib/sbyc/codetree/rewriting/match.rb
|
52
52
|
- lib/sbyc/codetree/rewriting.rb
|
53
53
|
- lib/sbyc/codetree.rb
|
54
|
+
- lib/sbyc/shortspaces.rb
|
54
55
|
- lib/sbyc/type_system/contract.rb
|
55
56
|
- lib/sbyc/type_system/errors.rb
|
56
57
|
- lib/sbyc/type_system/ruby.rb
|
@@ -113,6 +114,7 @@ files:
|
|
113
114
|
- test/spec/unit/sbyc/codetree/rewriting/match/apply.spec
|
114
115
|
- test/spec/unit/sbyc/codetree/rewriting/match/coerce.spec
|
115
116
|
- test/spec/unit/sbyc/codetree/rewriting/match/matches.spec
|
117
|
+
- test/spec/unit/sbyc/type_system/ruby/boolean.spec
|
116
118
|
- test/spec/unit/sbyc/type_system/ruby/coerce.spec
|
117
119
|
- test/spec/unit/sbyc/type_system/ruby/parse_literal.spec
|
118
120
|
- test/spec/unit/sbyc/type_system/ruby/to_literal.spec
|