├── lib ├── types │ ├── rails │ │ ├── time.rb │ │ ├── rack │ │ │ └── request.rb │ │ ├── active_record │ │ │ ├── core.rb │ │ │ ├── base.rb │ │ │ ├── validations.rb │ │ │ ├── finder_methods.rb │ │ │ ├── relation.rb │ │ │ └── model_schema.rb │ │ ├── active_support │ │ │ ├── base.rb │ │ │ ├── tagged_logging.rb │ │ │ ├── time_zone.rb │ │ │ ├── logger.rb │ │ │ └── time_with_zone.rb │ │ ├── active_model │ │ │ ├── validations.rb │ │ │ └── errors.rb │ │ ├── integer.rb │ │ ├── action_mailer │ │ │ ├── message_delivery.rb │ │ │ └── base.rb │ │ ├── string.rb │ │ ├── abstract_controller │ │ │ └── translation.rb │ │ ├── action_view │ │ │ ├── helpers_sanitizehelper.rb │ │ │ └── helpers_urlhelper.rb │ │ ├── fixnum.rb │ │ ├── action_controller │ │ │ ├── base.rb │ │ │ ├── metal.rb │ │ │ ├── parameters.rb │ │ │ ├── mime_responds.rb │ │ │ ├── instrumentation.rb │ │ │ └── strong_parameters.rb │ │ ├── action_dispatch │ │ │ ├── routing.rb │ │ │ └── flashhash.rb │ │ └── _helpers.rb │ ├── devise.rb │ ├── pundit.rb │ ├── core │ │ ├── marshal.rb │ │ ├── yaml.rb │ │ ├── abbrev.rb │ │ ├── date.rb │ │ ├── csv.rb │ │ ├── coverage.rb │ │ ├── strscan.rb │ │ ├── fileutils.rb │ │ ├── base64.rb │ │ ├── nil.rb │ │ ├── proc.rb │ │ ├── bigmath.rb │ │ ├── basic_object.rb │ │ ├── random.rb │ │ ├── _aliases.rb │ │ ├── class.rb │ │ ├── benchmark.rb │ │ ├── exception.rb │ │ ├── uri.rb │ │ ├── gem.rb │ │ ├── encoding.rb │ │ ├── matchdata.rb │ │ ├── symbol.rb │ │ ├── enumerator.rb │ │ ├── regexp.rb │ │ ├── range.rb │ │ ├── dir.rb │ │ ├── math.rb │ │ ├── set.rb │ │ ├── numeric.rb │ │ ├── time.rb │ │ ├── hash.rb │ │ ├── object.rb │ │ ├── module.rb │ │ ├── enumerable.rb │ │ ├── kernel.rb │ │ ├── pathname.rb │ │ ├── io.rb │ │ └── process.rb │ ├── core.rb │ └── devise │ │ ├── parameter_sanitizer.rb │ │ └── controller_helpers.rb ├── rdl │ ├── types │ │ ├── type_query.rb │ │ ├── dots_query.rb │ │ ├── wild_query.rb │ │ ├── computed.rb │ │ ├── bot.rb │ │ ├── top.rb │ │ ├── non_null.rb │ │ ├── annotated_arg.rb │ │ ├── var.rb │ │ ├── optional.rb │ │ ├── singleton.rb │ │ ├── dependent_arg.rb │ │ ├── ast_node.rb │ │ ├── lexer.rex │ │ ├── vararg.rb │ │ ├── nominal.rb │ │ ├── intersection.rb │ │ ├── generic.rb │ │ ├── structural.rb │ │ ├── type_inferencer.rb │ │ ├── tuple.rb │ │ ├── union.rb │ │ ├── lexer.rex.rb │ │ └── finite_hash.rb │ ├── contracts │ │ ├── contract.rb │ │ ├── or.rb │ │ ├── proc.rb │ │ ├── and.rb │ │ └── flat.rb │ ├── switch.rb │ ├── boot_rails.rb │ ├── util.rb │ ├── info.rb │ ├── query.rb │ └── boot.rb ├── rdl.rb └── rdl_disable.rb ├── gemfiles └── Gemfile.travis ├── .travis.yml ├── bin └── rdl_query ├── Rakefile ├── test ├── test_wrap.rb ├── test_intersection.rb ├── test_dsl.rb ├── test_alias.rb ├── test_contract.rb ├── test_rdl_type.rb ├── disabled_test_rdoc.rb ├── disabled_test_coverage.rb ├── test_query.rb ├── test_member.rb └── test_lib_types.rb ├── .gitignore ├── rdl.gemspec ├── LICENSE └── CHANGES.md /lib/types/rails/time.rb: -------------------------------------------------------------------------------- 1 | RDL.type :Time, 'self.zone', '() -> ActiveSupport::TimeZone' 2 | -------------------------------------------------------------------------------- /lib/types/devise.rb: -------------------------------------------------------------------------------- 1 | Dir[File.dirname(__FILE__) + "/devise/**/*.rb"].each { |f| require f } 2 | -------------------------------------------------------------------------------- /lib/rdl/types/type_query.rb: -------------------------------------------------------------------------------- 1 | module RDL::Type 2 | class TypeQuery < Type 3 | 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /lib/types/pundit.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :Pundit 2 | RDL.type :Pundit, :authorize, '(%any, ?%any) -> %any' 3 | -------------------------------------------------------------------------------- /gemfiles/Gemfile.travis: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'rake' 4 | gem 'minitest' 5 | gem 'parser' 6 | -------------------------------------------------------------------------------- /lib/types/core/marshal.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :Marshal 2 | 3 | RDL.type :Marshal, 'self.load', '(String, ?Proc) -> Object' 4 | -------------------------------------------------------------------------------- /lib/types/core/yaml.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :YAML 2 | 3 | RDL.type :YAML, 'self.load_file', '(String) -> Array' 4 | -------------------------------------------------------------------------------- /lib/types/rails/rack/request.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :'Rack::Request' 2 | RDL.type :'Rack::Request', :env, '() -> Hash' 3 | -------------------------------------------------------------------------------- /lib/types/core/abbrev.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :Abbrev 2 | 3 | RDL.type :Abbrev, 'self.abbrev', '(Array) -> Hash' 4 | -------------------------------------------------------------------------------- /lib/types/rails/active_record/core.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :'ActiveRecord::Core' 2 | RDL.type :'ActiveRecord::Core', :==, '(%any) -> %bool' 3 | -------------------------------------------------------------------------------- /lib/rdl/contracts/contract.rb: -------------------------------------------------------------------------------- 1 | module RDL::Contract 2 | class ContractError < StandardError 3 | end 4 | 5 | class Contract 6 | end 7 | end -------------------------------------------------------------------------------- /lib/types/core/date.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :Date 2 | 3 | RDL.type :Date, 'self.now', '() -> DateTime' 4 | RDL.type :Date, :strftime, '(String) -> String' 5 | -------------------------------------------------------------------------------- /lib/types/rails/active_record/base.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :'ActiveRecord::Base' 2 | RDL.type :'ActiveRecord::Base', :logger, '() -> ActiveSupport::Logger' 3 | -------------------------------------------------------------------------------- /lib/types/rails/active_support/base.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :'ActiveRecord::Base' 2 | RDL.type :'ActiveRecord::Base', :logger, '() -> ActiveSupport::Logger' 3 | -------------------------------------------------------------------------------- /lib/types/core.rb: -------------------------------------------------------------------------------- 1 | require_relative "core/_aliases.rb" # load type aliases first 2 | Dir[File.dirname(__FILE__) + "/core/**/*.rb"].each { |f| require f } 3 | -------------------------------------------------------------------------------- /lib/types/core/csv.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :CSV 2 | 3 | RDL.type :CSV, 'self.foreach', '(String or File, ?Hash) {(Array) -> %any} -> NilClass' 4 | -------------------------------------------------------------------------------- /lib/types/rails/active_model/validations.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :'ActiveModel::Validations' 2 | RDL.type :'ActiveModel::Validations', :errors, '() -> ActiveModel::Errors' 3 | -------------------------------------------------------------------------------- /lib/types/rails/active_support/tagged_logging.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :'ActiveSupport::TaggedLogging' 2 | RDL.type :'ActiveSupport::TaggedLogging', :info, '(String) -> %bool' 3 | -------------------------------------------------------------------------------- /lib/types/rails/active_support/time_zone.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :'ActiveSupport::TimeZone' 2 | RDL.type :'ActiveSupport::TimeZone', :now, '() -> ActiveSupport::TimeWithZone' 3 | -------------------------------------------------------------------------------- /lib/types/rails/integer.rb: -------------------------------------------------------------------------------- 1 | RDL.type :Integer, :*, '(ActiveSupport::Duration) -> ActiveSupport::Duration' 2 | RDL.type :Integer, :day, '() -> ActiveSupport::Duration' 3 | -------------------------------------------------------------------------------- /lib/types/rails/action_mailer/message_delivery.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :'ActionMailer::MessageDelivery' 2 | RDL.type :'ActionMailer::MessageDelivery', :deliver_now, '() -> Mail::Message' 3 | -------------------------------------------------------------------------------- /lib/types/rails/string.rb: -------------------------------------------------------------------------------- 1 | RDL.type :String, :truncate, '(Integer) -> String' 2 | RDL.type :String, :strftime, '(String) -> String' 3 | RDL.type :String, :sanitize, '() -> String' 4 | -------------------------------------------------------------------------------- /lib/rdl.rb: -------------------------------------------------------------------------------- 1 | # This wrapper file allows us to completely disable RDL in certain modes. 2 | if defined?(Rails) 3 | require 'rdl/boot_rails' 4 | else 5 | require 'rdl/boot' 6 | end 7 | -------------------------------------------------------------------------------- /lib/types/core/coverage.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :Coverage 2 | 3 | RDL.type :Coverage, 'self.start', '() -> nil' 4 | RDL.type :Coverage, 'self.result', '() -> Hash>' 5 | -------------------------------------------------------------------------------- /lib/types/rails/abstract_controller/translation.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :'AbstractController::Translation' 2 | RDL.type :'AbstractController::Translation', :t, '(Symbol or String) -> String' 3 | -------------------------------------------------------------------------------- /lib/types/devise/parameter_sanitizer.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :'Devise::ParameterSanitizer' 2 | RDL.type :'Devise::ParameterSanitizer', :permit, '(Symbol, Hash>) -> NilClass' 3 | -------------------------------------------------------------------------------- /lib/types/rails/active_record/validations.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :'ActiveRecord::Validations' 2 | RDL.type :'ActiveRecord::Validations', :valid?, '(?:create or :update or :on or NilClass) -> %bool' 3 | -------------------------------------------------------------------------------- /lib/types/rails/action_view/helpers_sanitizehelper.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :'ActionView::Helpers::SanitizeHelper' 2 | RDL.type :'ActionView::Helpers::SanitizeHelper', :strip_tags, '(String) -> String' 3 | -------------------------------------------------------------------------------- /lib/types/rails/active_support/logger.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :'ActiveSupport::Logger' 2 | RDL.type :'ActiveSupport::Logger', :error, '(String) -> %bool' 3 | RDL.type :'ActiveSupport::Logger', :debug, '(String) -> %bool' 4 | -------------------------------------------------------------------------------- /lib/types/rails/active_record/finder_methods.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :'ActiveRecord::FinderMethods' 2 | #RDL.type :'ActiveRecord::FinderMethods', :exists?, '(?String or Integer or Array or Hash) -> %bool' 3 | -------------------------------------------------------------------------------- /lib/types/rails/fixnum.rb: -------------------------------------------------------------------------------- 1 | RDL.type :Fixnum, :*, '(ActiveSupport::Duration) -> ActiveSupport::Duration', version: RDL::Globals::FIXBIG_VERSIONS 2 | RDL.type :Fixnum, :day, '() -> ActiveSupport::Duration', version: RDL::Globals::FIXBIG_VERSIONS 3 | -------------------------------------------------------------------------------- /lib/types/rails/action_controller/base.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :'ActionController::Base' 2 | RDL.type :'ActionController::Base', 'self.helpers', '() -> ActionView::Base' 3 | RDL.type :'ActionController::Base', :logger, '() -> ActiveSupport::TaggedLogging' 4 | -------------------------------------------------------------------------------- /lib/types/devise/controller_helpers.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :'Devise::Controllers::Helpers' 2 | RDL.type :'Devise::Controllers::Helpers', :devise_parameter_sanitizer, '() -> Devise::ParameterSanitizer' 3 | RDL.type :'Devise::Controllers::Helpers', :current_user, '() -> User' 4 | -------------------------------------------------------------------------------- /lib/types/rails/action_mailer/base.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :'ActionMailer::Base' 2 | RDL.type :'ActionMailer::Base', :mail, '({subject: ?String, to: ?String, from: ?String, cc: ?String or Array, bcc: ?String or Array, reply_to: ?String, date: ?String}) -> Mail::Message' 3 | -------------------------------------------------------------------------------- /lib/types/rails/action_controller/metal.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :'ActionController::Metal' 2 | RDL.type :'ActionController::Metal', :params, '() -> ActiveSupport::HashWithIndifferentAccess' 3 | RDL.type :'ActionController::Metal', :request, '() -> ActionDispatch::Request' 4 | -------------------------------------------------------------------------------- /lib/types/rails/action_controller/parameters.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :'ActionController::Parameters' 2 | RDL.type :'ActionController::Parameters', :require, '(*Symbol) -> ActionController::Parameters' 3 | RDL.type :'ActionController::Parameters', :permit, '(*Symbol) -> ActionController::Parameters' 4 | -------------------------------------------------------------------------------- /lib/types/core/strscan.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :StringScanner 2 | 3 | RDL.type :StringScanner, 'self.new', '(String, ?%bool) -> StringScanner' 4 | RDL.type :StringScanner, :eos?, '() -> %bool' 5 | RDL.type :StringScanner, :scan, '(Regexp) -> String' 6 | RDL.type :StringScanner, :getch, '() -> String' 7 | -------------------------------------------------------------------------------- /lib/types/rails/action_dispatch/routing.rb: -------------------------------------------------------------------------------- 1 | # module ActionDispatch 2 | # module Routing 3 | # class RouteSet 4 | # post(:draw) { |ret| 5 | # # puts "Routes are: #{Rails.application.routes.named_routes.helper_names}" 6 | # true 7 | # } 8 | # end 9 | # end 10 | # end 11 | -------------------------------------------------------------------------------- /lib/types/core/fileutils.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :FileUtils 2 | 3 | RDL.type :FileUtils, 'self.cp_r', '(String or Pathname, String or Pathname, ?Hash<:preserve or :noop or :verbose or :dereference_root or :remove_destination, %bool>) -> Array' 4 | RDL.type :FileUtils, 'self.mkdir_p', '(String or Pathname, ?Hash<:mode or :noop or :verbose, %bool>) -> Array' 5 | -------------------------------------------------------------------------------- /lib/rdl/switch.rb: -------------------------------------------------------------------------------- 1 | class RDL::Switch 2 | def initialize 3 | @switch = true 4 | end 5 | def off?() 6 | return not(@switch) 7 | end 8 | def off() 9 | return unless @switch 10 | tmp = @switch 11 | @switch = false 12 | begin 13 | ret = yield 14 | ensure 15 | @switch = tmp 16 | end 17 | return ret 18 | end 19 | end 20 | 21 | -------------------------------------------------------------------------------- /lib/types/core/base64.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :Base64 2 | 3 | RDL.type :Base64, 'self.decode64', '(String) -> String' 4 | RDL.type :Base64, 'self.encode64', '(String) -> String' 5 | RDL.type :Base64, 'self.strict_decode64', '(String) -> String' 6 | RDL.type :Base64, 'self.strict_encode64', '(String) -> String' 7 | RDL.type :Base64, 'self.urlsafe_decode64', '(String) -> String' 8 | RDL.type :Base64, 'self.urlsafe_encode64', '(String) -> String' 9 | -------------------------------------------------------------------------------- /lib/types/core/nil.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :NilClass 2 | 3 | RDL.type :NilClass, :&, '(%any obj) -> false' 4 | RDL.type :NilClass, :'^', '(%any obj) -> %bool' 5 | RDL.type :NilClass, :|, '(%any obj) -> %bool' 6 | RDL.type :NilClass, :rationalize, '() -> Rational' 7 | RDL.type :NilClass, :to_a, '() -> []' 8 | RDL.type :NilClass, :to_c, '() -> Complex' 9 | RDL.type :NilClass, :to_f, '() -> 0.0' 10 | RDL.type :NilClass, :to_h, '() -> {}' 11 | RDL.type :NilClass, :to_r, '() -> Rational' 12 | -------------------------------------------------------------------------------- /lib/types/core/proc.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :Proc 2 | 3 | RDL.type :Proc, :arity, '() -> Integer' 4 | RDL.type :Proc, :binding, '() -> Binding' 5 | RDL.type :Proc, :curry, '(?Integer arity) -> Proc' 6 | RDL.type :Proc, :hash, '() -> Integer' 7 | RDL.rdl_alias :Proc, :inspect, :to_s 8 | RDL.type :Proc, :lambda, '() -> %bool' 9 | RDL.type :Proc, :parameters, '() -> Array<[Symbol, Symbol]>' 10 | RDL.type :Proc, :source_location, '() -> [String, Integer]' 11 | RDL.type :Proc, :to_proc, '() -> self' 12 | RDL.type :Proc, :to_s, '() -> String' 13 | -------------------------------------------------------------------------------- /lib/rdl/boot_rails.rb: -------------------------------------------------------------------------------- 1 | if Rails.env.development? || Rails.env.test? 2 | require 'rdl/boot' 3 | require 'types/core' 4 | 5 | require_relative "../types/rails/_helpers.rb" # load type aliases first 6 | Dir[File.dirname(__FILE__) + "/../types/rails/**/*.rb"].each { |f| require f } 7 | elsif Rails.env.production? 8 | require 'rdl_disable' 9 | class ActionController::Base 10 | def self.params_type(typs); end 11 | end 12 | else 13 | raise RuntimeError, "Don't know what to do in Rails environment #{Rails.env}" 14 | end 15 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | gemfile: 3 | - gemfiles/Gemfile.travis 4 | rvm: 5 | - 2.1.1 6 | - 2.1.6 7 | - 2.1.7 8 | - 2.1.8 9 | - 2.2.0 10 | - 2.2.1 11 | - 2.2.2 12 | - 2.2.3 13 | - 2.2.4 14 | - 2.2.5 15 | - 2.2.6 16 | - 2.3.0 17 | - 2.3.1 18 | - 2.3.2 19 | - 2.3.3 20 | - 2.3.4 21 | - 2.4.0 22 | - 2.4.1 23 | sudo: false 24 | notifications: 25 | email: 26 | recipients: 27 | - rdl-devel@googlegroups.com 28 | on_success: never # default: change 29 | on_failure: always # default: always 30 | -------------------------------------------------------------------------------- /lib/types/rails/action_dispatch/flashhash.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :'ActionDispatch::Flash::FlashHash' 2 | RDL.type :'ActionDispatch::Flash::FlashHash', :[], '(Symbol) -> String' 3 | RDL.type :'ActionDispatch::Flash::FlashHash', :[]=, '(Symbol, String) -> String' 4 | RDL.type :'ActionDispatch::Flash::FlashHash', :now, '() -> ActionDispatch::Flash::FlashNow' 5 | 6 | RDL.nowrap :'ActionDispatch::Flash::FlashNow' 7 | RDL.type :'ActionDispatch::Flash::FlashNow', :[], '(Symbol) -> String' 8 | RDL.type :'ActionDispatch::Flash::FlashNow', :[]=, '(Symbol, String) -> String' 9 | -------------------------------------------------------------------------------- /lib/types/core/bigmath.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :BigMath 2 | 3 | RDL.type :BigMath, 'self.exp', '(Integer, Integer) -> BigDecimal' 4 | RDL.type :BigMath, 'self.log', '(Integer, Integer) -> BigDecimal' 5 | RDL.type :BigMath, :E, '(Integer) -> BigDecimal' 6 | RDL.type :BigMath, :PI, '(Integer) -> BigDecimal' 7 | RDL.type :BigMath, :atan, '(Integer, Integer) -> BigDecimal' 8 | RDL.type :BigMath, :cos, '(Integer, Integer) -> BigDecimal' 9 | RDL.type :BigMath, :sin, '(Integer, Integer) -> BigDecimal' 10 | RDL.type :BigMath, :sqrt, '(Integer, Integer) -> BigDecimal' 11 | -------------------------------------------------------------------------------- /lib/types/rails/action_controller/mime_responds.rb: -------------------------------------------------------------------------------- 1 | RDL.type :'ActionController::MimeResponds', :respond_to, 2 | '(*(String or Symbol)) { (ActionController::MimeResponds::Collector) -> %any } -> Array or String' 3 | 4 | module ActionController 5 | module MimeResponds 6 | class Collector 7 | Mime::EXTENSION_LOOKUP.each { |mime| 8 | RDL.type :'ActionController::MimeResponds::Collector', :method_missing, 9 | "(#{mime[1].symbol.inspect}) { (ActionController::MimeResponds::Collector::VariantCollector) -> %any } -> %any" 10 | } 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /lib/rdl/contracts/or.rb: -------------------------------------------------------------------------------- 1 | module RDL::Contract 2 | class OrContract < Contract 3 | attr_reader :contracts 4 | 5 | def initialize(*contracts) 6 | @contracts = contracts 7 | end 8 | 9 | def check(slf, *v, &blk) 10 | # All contracts must be satisfied 11 | @contracts.each { |c| 12 | begin 13 | c.check(slf, *v, &blk) 14 | return true 15 | rescue ContractError 16 | end 17 | } 18 | raise ContractError, "#{v.inspect} does not satisfy #{self}" 19 | end 20 | 21 | def to_s 22 | @contracts.join(' && ') 23 | end 24 | end 25 | end -------------------------------------------------------------------------------- /lib/types/rails/action_view/helpers_urlhelper.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :'ActionView::Helpers::UrlHelper' 2 | RDL.type :'ActionView::Helpers::UrlHelper', :link_to, '(String, String or ActiveRecord::Base, ?Hash) -> ActiveSupport::SafeBuffer' 3 | RDL.type :'ActionView::Helpers::UrlHelper', :link_to, '(String, ?Hash, ?Hash) -> ActiveSupport::SafeBuffer' 4 | RDL.type :'ActionView::Helpers::UrlHelper', :link_to, '(?Hash, ?Hash) {() -> String} -> ActiveSupport::SafeBuffer' 5 | RDL.type :'ActionView::Helpers::UrlHelper', :link_to, '(?String, ?Hash) {() -> String} -> ActiveSupport::SafeBuffer' 6 | -------------------------------------------------------------------------------- /lib/types/rails/active_record/relation.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :'ActiveRecord::Relation' 2 | 3 | RDL.type_params :'ActiveRecord::Relation', [:t], :all? 4 | 5 | =begin 6 | RDL.type :'ActiveRecord::Relation', :[], '(Integer) -> t' 7 | RDL.type :'ActiveRecord::Relation', :empty?, '() -> %bool' 8 | RDL.type :'ActiveRecord::Relation', :first, '() -> t' 9 | RDL.type :'ActiveRecord::Relation', :length, '() -> Integer' 10 | RDL.type :'ActiveRecord::Relation', :sort, '() {(t, t) -> Integer} -> Array' 11 | RDL.type :'ActiveRecord::Relation', :each, '() -> Enumerator' 12 | RDL.type :'ActiveRecord::Relation', :each, '() { (t) -> %any } -> Array' 13 | =end 14 | -------------------------------------------------------------------------------- /lib/rdl/types/dots_query.rb: -------------------------------------------------------------------------------- 1 | require_relative 'type_query' 2 | 3 | module RDL::Type 4 | class DotsQuery < TypeQuery 5 | @@cache = nil 6 | 7 | class << self 8 | alias :__new__ :new 9 | end 10 | 11 | def self.new 12 | @@cache = DotsQuery.__new__ unless @@cache 13 | return @@cache 14 | end 15 | 16 | def to_s 17 | "..." 18 | end 19 | 20 | def ==(other) 21 | return false if other.nil? 22 | other = other.canonical 23 | return (other.instance_of? DotsQuery) 24 | end 25 | 26 | # doesn't have match method---taken care of at a higher level, in MethodType#match 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /bin/rdl_query: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require_relative '../lib/rdl.rb' 4 | require_relative '../lib/types/core.rb' 5 | 6 | if ARGV.length != 1 then 7 | print < 9 | 10 | Valid queries: 11 | 12 | Class#method - Display type of instance method 13 | Class.method - Display type of class (singleton) method 14 | (method type) - Display methods that have given type 15 | 16 | Method type queries follow the usual syntax for RDL types, 17 | but can also include `.' to match any type, and `...' to 18 | match any sequence of types. See the README.md file for more 19 | detail. 20 | EOF 21 | exit 0 22 | end 23 | 24 | RDL.query(ARGV[0]) 25 | -------------------------------------------------------------------------------- /lib/types/core/basic_object.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :BasicObject 2 | 3 | RDL.type :BasicObject, :==, '(%any other) -> %bool' 4 | RDL.type :BasicObject, :equal?, '(%any other) -> %bool' 5 | RDL.type :BasicObject, :!, '() -> %bool' 6 | RDL.type :BasicObject, :!=, '(%any other) -> %bool' 7 | RDL.type :BasicObject, :instance_eval, '(String, ?String filename, ?Integer lineno) -> %any' 8 | RDL.type :BasicObject, :instance_eval, '() { () -> %any } -> %any' 9 | RDL.type :BasicObject, :instance_exec, '(*%any args) { (*%any) -> %any } -> %any' 10 | RDL.type :BasicObject, :__send__, '(Symbol, *%any) -> %any obj' 11 | RDL.rdl_alias :BasicObject, :__id__, :object_id 12 | RDL.type :BasicObject, :object_id, '() -> Integer' 13 | -------------------------------------------------------------------------------- /lib/types/core/random.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :Random 2 | 3 | RDL.type :Random, :initialize, '(?Integer seed) -> self' # Floats can be passed also, but just truncated to int? 4 | RDL.type :Random, 'self.new_seed', '() -> Integer' 5 | RDL.type :Random, 'self.rand', '(?Integer max) -> Numeric' 6 | RDL.type :Random, 'self.srand', '(?Integer number) -> Numeric old_seed' 7 | 8 | RDL.type :Random, :==, '(%any) -> %bool' 9 | RDL.type :Random, :bytes, '(Integer size) -> String' 10 | RDL.type :Random, :rand, '(?(Integer or Range) max) -> Integer' 11 | RDL.type :Random, :rand, '(?(Float or Range) max) -> Float' 12 | RDL.pre(:Random, :rand) { |max| max > 0 } 13 | RDL.type :Random, :seed, '() -> Integer' 14 | -------------------------------------------------------------------------------- /lib/types/core/_aliases.rb: -------------------------------------------------------------------------------- 1 | if defined? BigDecimal 2 | RDL.type_alias '%real', 'Integer or Float or Rational or BigDecimal' 3 | RDL.type_alias '%numeric', 'Integer or Float or Rational or BigDecimal or Complex' 4 | else 5 | RDL.type_alias '%real', 'Integer or Float or Rational' 6 | RDL.type_alias '%numeric', 'Integer or Float or Rational' 7 | end 8 | RDL.type_alias '%string', '[to_str: () -> String]' 9 | if defined? Pathname 10 | RDL.type_alias '%path', '%string or Pathname' 11 | else 12 | RDL.type_alias '%path', '%string' 13 | end 14 | RDL.type_alias '%open_args', '{external_encoding: ?String, internal_encoding: ?String, encoding: ?String, textmode: ?%any, binmode: ?%any, autoclose: ?%any, mode: ?String}' 15 | -------------------------------------------------------------------------------- /lib/types/core/class.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :Class 2 | 3 | RDL.type :Class, :allocate, '() -> %any' # Instance of class self 4 | RDL.type :Class, :inherited, '(Class) -> %any' 5 | #RDL.type :Class, 'initialize', '() -> ' 6 | #RDL.type :Class, 'new', '(*%any) -> %any' #Causes two other test cases to fail 7 | RDL.type :Class, :superclass, '() -> Class or nil' 8 | 9 | #RDL.type :Class, :class_eval, '() {() -> %any} -> %any' 10 | #RDL.type :Class, :method_defined?, '(String or Symbol) -> %bool' 11 | #RDL.type :Class, :define_method, '(String or Symbol) {(*%any) -> %any} -> Proc' 12 | RDL.type :Class, :instance_methods, '(?%bool) -> Array' 13 | RDL.type :Class, :class, '() -> Class' 14 | RDL.type :Class, :superclass, '() -> Class' 15 | RDL.type :Class, :name, '() -> String' 16 | -------------------------------------------------------------------------------- /lib/rdl/contracts/proc.rb: -------------------------------------------------------------------------------- 1 | module RDL::Contract 2 | class ProcContract < Contract 3 | attr_accessor :pre_cond, :post_cond 4 | 5 | def initialize(pre_cond:nil, post_cond:nil) 6 | @pre_cond = pre_cond 7 | @post_cond = post_cond 8 | end 9 | 10 | 11 | def wrap(slf, &blk) 12 | Proc.new {|*v, &other_blk| 13 | @pre_cond.check(slf, *v, &other_blk) 14 | tmp = other_blk ? slf.instance_exec(*v, other_blk, &blk) : slf.instance_exec(*v, &blk) # TODO fix blk 15 | # tmp = blk.call(*v, &other_blk) # TODO: Instance eval with self 16 | @post_cond.check(slf, tmp, *v, &other_blk) 17 | tmp 18 | } 19 | end 20 | 21 | def to_s 22 | "(#{@pre_cond}) -> (#{@post_cond})" 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /lib/rdl/types/wild_query.rb: -------------------------------------------------------------------------------- 1 | module RDL::Type 2 | class WildQuery < TypeQuery 3 | @@cache = nil 4 | 5 | class << self 6 | alias :__new__ :new 7 | end 8 | 9 | def self.new 10 | @@cache = WildQuery.__new__ unless @@cache 11 | return @@cache 12 | end 13 | 14 | def to_s 15 | "*" 16 | end 17 | 18 | def ==(other) 19 | return false if other.nil? 20 | other = other.canonical 21 | return (other.instance_of? WildQuery) 22 | end 23 | 24 | alias eql? == 25 | 26 | def <=(other) 27 | other = other.type if other.is_a? DependentArgType 28 | other = other.canonical 29 | return self == other 30 | end 31 | 32 | def match(other) 33 | return true 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'rake/testtask' 2 | 3 | Rake::TestTask.new do |t| 4 | t.libs << 'test' 5 | end 6 | 7 | desc "Run tests" 8 | task :default => :test 9 | 10 | task :skel, [:cname,:prettyname] do |skel, varhash| 11 | kls = eval "#{varhash[:cname]}.new" 12 | mthds = kls.public_methods(false) + kls.private_methods(false) + kls.protected_methods(false) 13 | mname = "types/ruby-2.2.3/#{varhash[:prettyname]}.rb" 14 | touch mname 15 | mthds.sort.each{ |m| 16 | sh "echo \" type '#{m}', '() -> '\" >> #{mname}" 17 | } 18 | sh "echo \"end\" >> #{mname}" 19 | end 20 | 21 | task :stat, [:fname,:outpath] do |stat,varhash| 22 | ruby "extras/rdlstat.rb #{varhash[:fname]} #{varhash[:outpath]}" 23 | end 24 | 25 | task :statrun, [:fname] do |statrun,varhash| 26 | ruby "#{varhash[:fname]}" 27 | end -------------------------------------------------------------------------------- /lib/types/core/benchmark.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :Benchmark 2 | 3 | RDL.type :Benchmark, 'self.benchmark', '(String, ?Integer, ?String, *String) -> Array' 4 | RDL.type :Benchmark, 'self.bm', '(?Integer, *String) { (Benchmark::Process) -> nil} -> Array' 5 | # RDL.type :Benchmark, 'self.benchmark', '(Caption: String, Label_Width: ?Integer, Format: ?String, Labels: *String) -> Benchmark::Tms' 6 | # RDL.type :Benchmark, 'self.bm', '(Label_Width: ?Integer, Labels: *String) { (Benchmark::Process) -> nil} -> Array' 7 | RDL.type :Benchmark, 'self.bmbm', '(?Integer label_width) { (Benchmark::Process) -> nil} -> Array' 8 | RDL.type :Benchmark, 'self.measure', '(?String label) -> Benchmark::Tms' 9 | RDL.type :Benchmark, 'self.realtime', '() {(*%any) -> %any} -> Integer' 10 | -------------------------------------------------------------------------------- /lib/rdl/contracts/and.rb: -------------------------------------------------------------------------------- 1 | module RDL::Contract 2 | class AndContract < Contract 3 | attr_reader :contracts 4 | 5 | def initialize(*contracts) 6 | @contracts = contracts 7 | end 8 | 9 | # [:slf:] is bound to self when the contracts are checked 10 | def check(slf, *v, &blk) 11 | AndContract.check_array(@contracts, slf, *v, &blk) 12 | end 13 | 14 | # Check an array of contracts a 15 | # [:slf:] is bound to self when the contracts are checked 16 | def self.check_array(a, slf, *v, &blk) 17 | # All contracts must be satisfied 18 | a.all? { |c| c.check(slf, *v, &blk) } 19 | end 20 | 21 | def to_s 22 | AndContract.array_to_s(@contracts) 23 | end 24 | 25 | def self.array_to_s(a) 26 | a.join(' && ') 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /lib/types/core/exception.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :Exception 2 | 3 | RDL.type :Exception, :==, '(%any) -> %bool' 4 | RDL.type :Exception, :backtrace, '() -> Array' 5 | RDL.type :Exception, :backtrace_locations, '() -> Array' 6 | RDL.type :Exception, :cause, '() -> nil' # TODO exception is proper postcondition 7 | RDL.type :Exception, :exception, '(?String) -> Exception' # or error 8 | # RDL.type :Exception, :initialize, '() -> ' 9 | RDL.type :Exception, :inspect, '() -> String' 10 | RDL.type :Exception, :message, '() -> String' 11 | # RDL.type :Exception, :method_missing, '() -> ' 12 | # RDL.type :Exception, :respond_to?, '() -> ' 13 | # RDL.type :Exception, :respond_to_missing?, '() -> ' 14 | RDL.type :Exception, :set_backtrace, '(String or Array) -> Array' 15 | RDL.type :Exception, :to_s, '() -> String' 16 | -------------------------------------------------------------------------------- /lib/rdl/contracts/flat.rb: -------------------------------------------------------------------------------- 1 | module RDL::Contract 2 | class FlatContract < Contract 3 | attr_accessor :desc 4 | 5 | def initialize(desc="No Description", &blk) 6 | @pred = blk 7 | @desc = desc 8 | end 9 | 10 | def check(slf, *v, &blk) 11 | RDL::Globals.contract_switch.off { 12 | if @pred && v.length >= @pred.arity 13 | unless blk ? slf.instance_exec(*v, blk, &@pred) : slf.instance_exec(*v, &@pred) # TODO: Fix blk 14 | # unless blk ? pred.call(*v, &blk) : pred.call(*v) 15 | raise ContractError, 16 | "#{v.inspect} does not satisfy #{self.to_s}" 17 | end 18 | else 19 | raise ContractError, 20 | "Invalid number of arguments: Expecting #{@pred.arity}, got #{v.size}" 21 | end 22 | } 23 | return true 24 | end 25 | 26 | def to_s 27 | @desc 28 | end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /test/test_wrap.rb: -------------------------------------------------------------------------------- 1 | require 'minitest/autorun' 2 | $LOAD_PATH << File.dirname(__FILE__) + "/../lib" 3 | require 'rdl' 4 | 5 | class TestWrap < Minitest::Test 6 | extend RDL::Annotate 7 | class C 8 | def foo_public(x) 9 | foo(x) 10 | end 11 | 12 | private 13 | 14 | def foo(x) 15 | x + 1 16 | end 17 | end 18 | 19 | def test_private_wrap 20 | RDL.type C, :foo, '(Integer) -> Integer' 21 | c = C.new 22 | 23 | assert_raises RDL::Type::TypeError do 24 | c.foo_public("1") 25 | end 26 | end 27 | 28 | class D 29 | def foo_public(x) 30 | foo(x) 31 | end 32 | 33 | protected 34 | 35 | def foo(x) 36 | x + 1 37 | end 38 | end 39 | 40 | def test_protected_wrap 41 | RDL.type D, :foo, '(Integer) -> Integer' 42 | d = D.new 43 | 44 | assert_raises RDL::Type::TypeError do 45 | d.foo_public("1") 46 | end 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | {\rtf1\ansi\ansicpg1252\cocoartf1265\cocoasubrtf210 2 | {\fonttbl\f0\fnil\fcharset0 Consolas;} 3 | {\colortbl;\red255\green255\blue255;\red38\green38\blue38;} 4 | \margl1440\margr1440\vieww10800\viewh8400\viewkind0 5 | \deftab720 6 | \pard\pardeftab720 7 | 8 | \f0\fs24 \cf2 # Compiled source #\ 9 | ###################\ 10 | *.com\ 11 | *.class\ 12 | *.dll\ 13 | *.exe\ 14 | *.o\ 15 | *.so\ 16 | \'a0\ 17 | # Packages #\ 18 | ############\ 19 | # it's better to unpack these files and commit the raw source\ 20 | # git has its own built in compression methods\ 21 | *.7z\ 22 | *.dmg\ 23 | *.gz\ 24 | *.iso\ 25 | *.jar\ 26 | *.rar\ 27 | *.tar\ 28 | *.zip\ 29 | \'a0\ 30 | # Logs and databases #\ 31 | ######################\ 32 | *.log\ 33 | *.sql\ 34 | *.sqlite\ 35 | \'a0\ 36 | # OS generated files #\ 37 | ######################\ 38 | .DS_Store\ 39 | .DS_Store?\ 40 | ._*\ 41 | .Spotlight-V100\ 42 | .Trashes\ 43 | ehthumbs.db\ 44 | Thumbs.db} -------------------------------------------------------------------------------- /rdl.gemspec: -------------------------------------------------------------------------------- 1 | # In the top directory 2 | # gem build rdl.gemspec 3 | # gem install rdl-1.0.0.beta.1.gem 4 | 5 | Gem::Specification.new do |s| 6 | s.name = 'rdl' 7 | s.version = '2.1.0' 8 | s.date = '2017-06-14' 9 | s.summary = 'Ruby type and contract system' 10 | s.description = <<-EOF 11 | RDL is a gem that adds types and contracts to Ruby. RDL includes extensive 12 | support for specifying method types, which can either be enforced as 13 | contracts or statically checked. 14 | EOF 15 | s.authors = ['Jeffrey S. Foster', 'Brianna M. Ren', 'T. Stephen Strickland', 'Alexander T. Yu', 'Milod Kazerounian'] 16 | s.email = ['rdl-users@googlegroups.com'] 17 | s.files = `git ls-files`.split($/) 18 | s.executables << 'rdl_query' 19 | s.homepage = 'https://github.com/plum-umd/rdl' 20 | s.license = 'BSD-3-Clause' 21 | s.add_runtime_dependency 'parser', '~>2.3', '>= 2.3.1.4' 22 | end 23 | -------------------------------------------------------------------------------- /lib/types/rails/action_controller/instrumentation.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :'ActionController::Instrumentation' 2 | RDL.type :'ActionController::Instrumentation', :render, '(String or Symbol) -> Array' 3 | RDL.type :'ActionController::Instrumentation', :render, '(?String or Symbol, {content_type: ?String, layout: ?%bool or String, action: ?String or Symbol, location: ?String, nothing: ?%bool, text: ?[to_s: () -> String], status: ?Symbol, content_type: ?String, formats: ?Symbol or Array, locals: ?Hash}) -> Array' 4 | RDL.type :'ActionController::Instrumentation', :redirect_to, '(:back) -> String' 5 | RDL.type :'ActionController::Instrumentation', :redirect_to, '({controller: ?String, action: ?String, notice: ?String, alert: ?String}) -> String' 6 | RDL.type :'ActionController::Instrumentation', :redirect_to, '(String or Symbol or ActiveRecord::Base, ?{controller: ?String, action: ?String, notice: ?String, alert: ?String}) -> String' 7 | -------------------------------------------------------------------------------- /lib/rdl/types/computed.rb: -------------------------------------------------------------------------------- 1 | require_relative 'type' 2 | 3 | module RDL::Type 4 | class ComputedType < Type 5 | attr_reader :code 6 | 7 | def initialize(code) 8 | @code = code 9 | super() 10 | end 11 | 12 | def compute(bind) 13 | res = bind.eval(@code) 14 | raise RuntimeError, "Expected ComputedType to evaluate to type, instead got #{res}." unless res.is_a?(Type) 15 | res 16 | end 17 | 18 | def to_s 19 | "``#{@code}``" 20 | end 21 | 22 | ### TODO:: Figure out how to fill in the below methods. 23 | ### I believe a ComputedType will always be evaluated to 24 | ### another RDL type before any of these methods would be called. 25 | ### Need to think about this though. 26 | 27 | def instantiate(inst) 28 | @inst = inst 29 | self 30 | end 31 | 32 | def <=(other) 33 | ## TODO 34 | end 35 | 36 | def ==(other) 37 | ## TODO 38 | end 39 | 40 | alias eql? == 41 | 42 | 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /lib/types/rails/active_model/errors.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :'ActiveModel::Errors' 2 | RDL.type :'ActiveModel::Errors', :clear, '() -> %any' 3 | RDL.type :'ActiveModel::Errors', :delete, '(%symstr) -> %any' 4 | RDL.type :'ActiveModel::Errors', :[], '(%symstr) -> Array' 5 | RDL.type :'ActiveModel::Errors', :each, '() { (%symstr, String) -> %any } -> %any' 6 | RDL.type :'ActiveModel::Errors', :size, '() -> Integer' 7 | RDL.rdl_alias :'ActiveModel::Errors', :count, :size 8 | RDL.type :'ActiveModel::Errors', :values, '() -> Array' 9 | RDL.type :'ActiveModel::Errors', :keys, '() -> Array' 10 | RDL.type :'ActiveModel::Errors', :empty?, '() -> %bool' 11 | RDL.rdl_alias :'ActiveModel::Errors', :blank?, :empty? 12 | RDL.type :'ActiveModel::Errors', :hash, '(?%bool full_messages) -> Hash' 13 | RDL.type :'ActiveModel::Errors', :add, '(%symstr, %symstr, Hash) -> %any' 14 | RDL.type :'ActiveModel::Errors', :add, '(%symstr, { () -> String }, Hash) -> %any' # TODO: combine with prev with union once supported 15 | -------------------------------------------------------------------------------- /lib/types/core/uri.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :URI 2 | 3 | RDL.type :URI, :decode_www_form, '(String, ?Encoding, ?String separator, %bool use_charset, %bool isindex) -> Array<[String,String]>' 4 | RDL.type :URI, :decode_www_form_component, '(String, ?Encoding) -> Array<[String,String]>' 5 | # RDL.type :URI, :encode_www_form, '(Array>, ?) -> String' #Doublesplat 6 | # RDL.type :URI, :encode_www_form_component, '(String, ?) -> String' 7 | RDL.type :URI, :extract, '(String, ?Array) { (*%any) -> %any} -> Array' 8 | RDL.type :URI, :join, '(*String) -> URI::HTTP' 9 | RDL.type :URI, :parse, '(String) -> URI::HTTP' 10 | RDL.type :URI, :regexp, '(?Array schemes) -> Array' #Assume schemes are strings 11 | RDL.type :URI, :scheme_list, '() -> Hash' 12 | RDL.type :URI, :split, '(String) -> Array' 13 | 14 | RDL.type :URI, :escape, '(String, *Regexp) -> String' 15 | RDL.type :URI, :escape, '(String, *String) -> String' 16 | RDL.type :URI, :unescape, '(*String) -> String' 17 | RDL.rdl_alias :URI, :encode, :escape 18 | RDL.rdl_alias :URI, :decode, :unescape 19 | -------------------------------------------------------------------------------- /lib/rdl/types/bot.rb: -------------------------------------------------------------------------------- 1 | module RDL::Type 2 | class BotType < Type 3 | @@cache = nil 4 | 5 | class << self 6 | alias :__new__ :new 7 | end 8 | 9 | def self.new 10 | @@cache = BotType.__new__ unless @@cache 11 | return @@cache 12 | end 13 | 14 | def initialize 15 | super 16 | end 17 | 18 | def to_s 19 | "%bot" 20 | end 21 | 22 | def ==(other) 23 | other.instance_of? BotType 24 | end 25 | 26 | alias eql? == 27 | 28 | def match(other) 29 | other = other.canonical 30 | other = other.type if other.instance_of? AnnotatedArgType 31 | return true if other.instance_of? WildQuery 32 | return self == other 33 | end 34 | 35 | def <=(other) 36 | return Type.leq(self, other) 37 | end 38 | 39 | def member?(obj, *args) 40 | # There are no values of this type (note nil does *not* have type %bot) 41 | false 42 | end 43 | 44 | def instantiate(inst) 45 | return self 46 | end 47 | 48 | def hash 49 | 13 50 | end 51 | end 52 | end 53 | -------------------------------------------------------------------------------- /lib/rdl/types/top.rb: -------------------------------------------------------------------------------- 1 | module RDL::Type 2 | class TopType < Type 3 | @@cache = nil 4 | 5 | class << self 6 | alias :__new__ :new 7 | end 8 | 9 | def self.new 10 | @@cache = TopType.__new__ unless @@cache 11 | return @@cache 12 | end 13 | 14 | def initialize 15 | super 16 | end 17 | 18 | def to_s 19 | "%any" 20 | end 21 | 22 | def ==(other) 23 | return false if other.nil? 24 | other = other.canonical 25 | other.instance_of? TopType 26 | end 27 | 28 | alias eql? == 29 | 30 | def match(other) 31 | other = other.canonical 32 | other = other.type if other.instance_of? AnnotatedArgType 33 | return true if other.instance_of? WildQuery 34 | return self == other 35 | end 36 | 37 | def <=(other) 38 | return Type.leq(self, other) 39 | end 40 | 41 | def member?(obj, *args) 42 | t = RDL::Util.rdl_type obj 43 | return t <= self if t 44 | true 45 | end 46 | 47 | def instantiate(inst) 48 | return self 49 | end 50 | 51 | def hash 52 | 17 53 | end 54 | end 55 | end 56 | -------------------------------------------------------------------------------- /lib/types/core/gem.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :Gem 2 | 3 | RDL.type :Gem, 'self.bin_path', '(String name, ?String exec_name, *Gem::Requirement requirements) -> String' 4 | RDL.type :Gem, 'self.binary_mode', '() -> String' 5 | RDL.type :Gem, 'self.bindir', '(?String install_dir) -> String' 6 | RDL.type :Gem, 'self.clear_default_specs', '() -> Hash' 7 | RDL.type :Gem, 'self.clear_paths', '() -> nil' 8 | RDL.type :Gem, 'self.config_file', '() -> String' 9 | RDL.type :Gem, 'self.configuration', '() -> Gem::ConfigFile' 10 | RDL.type :Gem, 'self.configuration=', '(%any) -> %any' #returns param 11 | RDL.type :Gem, 'self.datadir', '(String gem_name) -> String or nil' 12 | RDL.type :Gem, 'self.default_bindir', '() -> String or nil' 13 | RDL.type :Gem, 'self.default_cert_path', '() -> String or nil' 14 | RDL.type :Gem, 'self.default_dir', '() -> String or nil' 15 | RDL.type :Gem, 'self.default_exec_format', '() -> String or nil' 16 | RDL.type :Gem, 'self.default_key_path', '() -> String or nil' 17 | RDL.type :Gem, 'self.default_path', '() -> String or nil' 18 | RDL.type :Gem, 'self.default_rubygems_dirs', '() -> Array or nil' 19 | RDL.type :Gem, 'self.default_sources', '() -> Array or nil' 20 | -------------------------------------------------------------------------------- /lib/types/core/encoding.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :Encoding 2 | 3 | RDL.type :Encoding, 'self.aliases', '() -> Hash' 4 | RDL.type :Encoding, 'self.compatible?', '(%any obj1, %any obj2) -> Encoding or nil' 5 | RDL.type :Encoding, 'self.default_external', '() -> Encoding' 6 | RDL.type :Encoding, 'self.default_external=', '(String) -> String' 7 | RDL.type :Encoding, 'self.default_external=', '(Encoding) -> Encoding' 8 | RDL.type :Encoding, 'self.default_internal', '() -> Encoding' 9 | RDL.type :Encoding, 'self.default_internal=', '(String) -> String or nil' 10 | RDL.type :Encoding, 'self.default_internal=', '(Encoding) -> Encoding or nil' 11 | RDL.type :Encoding, 'self.find', '(String or Encoding) -> Encoding' 12 | RDL.type :Encoding, 'self.list', '() -> Array' 13 | RDL.type :Encoding, 'self.name_list', '() -> Array' 14 | 15 | RDL.type :Encoding, :ascii_compatible?, '() -> %bool' 16 | RDL.type :Encoding, :dummy?, '() -> %bool' 17 | RDL.type :Encoding, :inspect, '() -> String' 18 | RDL.type :Encoding, :name, '() -> String' 19 | RDL.type :Encoding, :names, '() -> Array' 20 | RDL.type :Encoding, :replicate, '(String name) -> Encoding' 21 | RDL.rdl_alias :Encoding, :to_s, :name 22 | -------------------------------------------------------------------------------- /lib/types/rails/active_support/time_with_zone.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :'ActiveSupport::TimeWithZone' 2 | RDL.type :'ActiveSupport::TimeWithZone', :beginning_of_day, '() -> ActiveSupport::TimeWithZone' 3 | RDL.type :'ActiveSupport::TimeWithZone', :end_of_day, '() -> ActiveSupport::TimeWithZone' 4 | RDL.type :'ActiveSupport::TimeWithZone', :beginning_of_week, '() -> ActiveSupport::TimeWithZone' 5 | RDL.type :'ActiveSupport::TimeWithZone', :end_of_week, '() -> ActiveSupport::TimeWithZone' 6 | RDL.type :'ActiveSupport::TimeWithZone', :to_date, '() -> Date' 7 | RDL.type :'ActiveSupport::TimeWithZone', :strftime, '(String) -> String' 8 | RDL.type :'ActiveSupport::TimeWithZone', :+, '(ActiveSupport::Duration) -> ActiveSupport::TimeWithZone' 9 | RDL.type :'ActiveSupport::TimeWithZone', :-, '(ActiveSupport::Duration) -> ActiveSupport::TimeWithZone' 10 | RDL.type :'ActiveSupport::TimeWithZone', :<, '(ActiveSupport::TimeWithZone or Time) -> %bool' 11 | RDL.type :'ActiveSupport::TimeWithZone', :>, '(ActiveSupport::TimeWithZone or Time) -> %bool' 12 | RDL.type :'ActiveSupport::TimeWithZone', :<=, '(ActiveSupport::TimeWithZone or Time) -> %bool' 13 | RDL.type :'ActiveSupport::TimeWithZone', :>=, '(ActiveSupport::TimeWithZone or Time) -> %bool' 14 | -------------------------------------------------------------------------------- /lib/types/rails/action_controller/strong_parameters.rb: -------------------------------------------------------------------------------- 1 | # TODO: This is all a bit of a hack. Right now, ActionControll::Parameters has its [] method set appropriately during the context 2 | # of the next method by params_types. But that doesn't quite match what actually happens in Rails. 3 | 4 | class ActionController::Base 5 | 6 | # [+ typ_hash +] is a Hash, where the keys are the parameter names and the Strings are the corresponding types 7 | # adds these parameters to the `params` hash in the immediately following controller method 8 | def self.params_type(typs) 9 | # TODO: Ick, this is ugly. Once it's obvious how to generalize this kind of reasoning to other cases, clean this up! 10 | typs.each_pair { |param, param_type| 11 | param_type = RDL::Globals.parser.scan_str "#T #{param_type}" 12 | meth_type = RDL::Globals.parser.scan_str "(#{param.inspect}) -> #{param_type}" # given singleton symbol arg, get param's return type 13 | RDL::Globals.deferred << [self, :context_types, [ActionController::Parameters, :[], meth_type], class_check: self] 14 | } 15 | end 16 | end 17 | 18 | RDL.type :'ActionController::StrongParameters', :params, '() -> ActionController::Parameters' 19 | -------------------------------------------------------------------------------- /lib/types/core/matchdata.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :MatchData 2 | 3 | RDL.type :MatchData, :==, '(%any) -> %bool' 4 | RDL.type :MatchData, :[], '(Integer i) -> String or nil' 5 | RDL.type :MatchData, :[], '(Integer start, Integer length) -> Array' 6 | RDL.type :MatchData, :[], '(Range range) -> Array' 7 | RDL.type :MatchData, :[], '(String or Symbol name) -> String or nil' 8 | RDL.type :MatchData, :begin, '(Integer n) -> Integer' 9 | RDL.type :MatchData, :captures, '() -> Array' 10 | RDL.type :MatchData, :end, '(Integer n) -> Integer' 11 | RDL.type :MatchData, :eql?, '(%any other) -> %bool' 12 | RDL.type :MatchData, :hash, '() -> Integer' 13 | RDL.type :MatchData, :inspect, '() -> String' 14 | RDL.type :MatchData, :length, '() -> Integer' 15 | RDL.type :MatchData, :names, '() -> Array' 16 | RDL.type :MatchData, :offset, '(Integer n) -> Array' 17 | RDL.type :MatchData, :post_match, '() -> String' 18 | RDL.type :MatchData, :pre_match, '() -> String' 19 | RDL.type :MatchData, :regexp, '() -> Regexp' 20 | RDL.type :MatchData, :size, '() -> Integer' 21 | RDL.type :MatchData, :string, '() -> String' 22 | RDL.type :MatchData, :to_a, '() -> Array' 23 | RDL.type :MatchData, :to_s, '() -> String' 24 | RDL.type :MatchData, :values_at, '(*Integer indexes) -> Array' 25 | -------------------------------------------------------------------------------- /lib/types/core/symbol.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :Symbol 2 | 3 | RDL.type :Symbol, 'self.all_symbols', '() -> Array' 4 | RDL.type :Symbol, :<=>, '(Symbol other) -> Integer or nil' 5 | RDL.type :Symbol, :==, '(%any obj) -> %bool' 6 | RDL.type :Symbol, :=~, '(%any obj) -> Integer or nil' 7 | RDL.type :Symbol, :[], '(Integer idx) -> String' 8 | RDL.type :Symbol, :[], '(Integer b, Integer n) -> String' 9 | RDL.type :Symbol, :[], '(Range) -> String' 10 | RDL.type :Symbol, :capitalize, '() -> Symbol' 11 | RDL.type :Symbol, :casecmp, '(Symbol other) -> Integer or nil' 12 | RDL.type :Symbol, :downcase, '() -> Symbol' 13 | RDL.type :Symbol, :empty?, '() -> %bool' 14 | RDL.type :Symbol, :encoding, '() -> Encoding' 15 | RDL.type :Symbol, :id2name, '() -> String' 16 | RDL.type :Symbol, :inspect, '() -> String' 17 | RDL.type :Symbol, :intern, '() -> self' 18 | RDL.type :Symbol, :length, '() -> Integer' 19 | RDL.type :Symbol, :match, '(%any obj) -> Integer or nil' 20 | RDL.type :Symbol, :succ, '() -> Symbol' 21 | RDL.rdl_alias :Symbol, :size, :length 22 | RDL.rdl_alias :Symbol, :slice, :[] 23 | RDL.type :Symbol, :swapcase, '() -> Symbol' 24 | RDL.type :Symbol, :to_proc, '() -> Proc' # TODO proc 25 | RDL.rdl_alias :Symbol, :to_s, :id2name 26 | RDL.rdl_alias :Symbol, :to_sym, :intern 27 | RDL.type :Symbol, :upcase, '() -> Symbol' 28 | -------------------------------------------------------------------------------- /lib/types/core/enumerator.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :Enumerator 2 | 3 | RDL.type_params :Enumerator, [:t], :all? 4 | 5 | RDL.type :Enumerator, :initialize, '(?Integer) { (Array) -> %any } -> self' 6 | RDL.type :Enumerator, :initialize, '(?Proc) { (Array) -> %any } -> self' # TODO Proc 7 | # TODO: deprecated form of new 8 | RDL.type :Enumerator, :each, '() { (t) -> %any } -> %any' # is there a better RDL.type? 9 | RDL.type :Enumerator, :each, '() -> self' 10 | # TODO: args 11 | RDL.type :Enumerator, :each_with_index, '() { (t, Integer) -> %any } -> %any' # TODO args 12 | RDL.type :Enumerator, :each_with_index, '() -> Enumerator<[t, Integer]>' # TODO args 13 | RDL.type :Enumerator, :each_with_object, '(u) { (t, u) -> %any } -> %any' # TODO args 14 | RDL.type :Enumerator, :each_with_object, '(u) -> Enumerator<[t, u]>' # TODO args 15 | RDL.type :Enumerator, :feed, '(t) -> nil' 16 | RDL.type :Enumerator, :inspect, '() -> String' 17 | RDL.type :Enumerator, :next, '() -> t' 18 | RDL.type :Enumerator, :next_values, '() -> Array' 19 | RDL.type :Enumerator, :peek, '() -> t' 20 | RDL.type :Enumerator, :peek_values, '() -> Array' 21 | RDL.type :Enumerator, :rewrind, '() -> self' 22 | RDL.type :Enumerator, :size, '() -> Integer or Float or nil' 23 | RDL.rdl_alias :Enumerator, :with_index, :each_with_index 24 | RDL.rdl_alias :Enumerator, :with_object, :each_with_object 25 | -------------------------------------------------------------------------------- /lib/rdl/types/non_null.rb: -------------------------------------------------------------------------------- 1 | require_relative 'type' 2 | 3 | module RDL::Type 4 | class NonNullType < Type 5 | attr_reader :type 6 | 7 | def initialize(type) 8 | @type = type 9 | raise RuntimeError, "Singleton types are always non-null" if type.is_a? SingletonType 10 | raise RuntimeError, "Attempt to create doubly non-null type" if type.is_a? NonNullType 11 | super() 12 | end 13 | 14 | def to_s 15 | return "!#{@type.to_s}" 16 | end 17 | 18 | def ==(other) # :nodoc: 19 | return false if other.nil? 20 | other = other.canonical 21 | return (other.instance_of? NonNullType) && (other.type == @type) 22 | end 23 | 24 | alias eql? == 25 | 26 | def match(other) 27 | other = other.canonical 28 | other = other.type if other.instance_of? AnnotatedArgType 29 | return true if other.instance_of? WildQuery 30 | return (other.instance_of? NonNullType) && (@type.match(other.type)) 31 | end 32 | 33 | def hash # :nodoc: 34 | return 157 + @type.hash 35 | end 36 | 37 | def <=(other) 38 | return Type.leq(self, other) 39 | end 40 | 41 | def member?(obj, *args) 42 | return false if obj.nil? 43 | @type.member?(obj, *args) 44 | end 45 | 46 | def instantiate(inst) 47 | return NonNullType.new(@type.instantiate(inst)) 48 | end 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /lib/rdl/types/annotated_arg.rb: -------------------------------------------------------------------------------- 1 | require_relative 'type' 2 | 3 | module RDL::Type 4 | class AnnotatedArgType < Type 5 | attr_reader :name 6 | attr_reader :type 7 | 8 | # Note: Named argument types aren't hashconsed. 9 | 10 | def initialize(name, type) 11 | @name = name 12 | @type = type 13 | raise RuntimeError, "Attempt to create annotated type with non-type" unless type.is_a? Type 14 | raise RuntimeError, "Attempt to create doubly annotated type" if type.is_a? AnnotatedArgType 15 | super() 16 | end 17 | 18 | def to_s 19 | return "#{@type.to_s} #{@name}" 20 | end 21 | 22 | def ==(other) # :nodoc: 23 | return false if other.nil? 24 | other = other.canonical 25 | return (other.instance_of? AnnotatedArgType) && (other.name == @name) && (other.type == @type) 26 | end 27 | 28 | alias eql? == 29 | 30 | # doesn't have a match method - queries shouldn't have annotations in them 31 | 32 | def hash # :nodoc: 33 | return (57 + @name.hash) * @type.hash 34 | end 35 | 36 | def member?(obj, *args) 37 | @type.member?(obj, *args) 38 | end 39 | 40 | def instantiate(inst) 41 | return AnnotatedArgType.new(@name, @type.instantiate(inst)) 42 | end 43 | 44 | def optional? 45 | return type.optional? 46 | end 47 | 48 | def vararg? 49 | return type.vararg? 50 | end 51 | end 52 | end 53 | -------------------------------------------------------------------------------- /test/test_intersection.rb: -------------------------------------------------------------------------------- 1 | require 'minitest/autorun' 2 | $LOAD_PATH << File.dirname(__FILE__) + "/../lib" 3 | require 'rdl' 4 | 5 | class TestIntersection < Minitest::Test 6 | include RDL::Type 7 | 8 | def setup 9 | @parser = RDL::Type::Parser.new 10 | 11 | @integer = NominalType.new(Integer) 12 | @string = NominalType.new(String) 13 | @array = NominalType.new(Array) 14 | @hash = NominalType.new(Hash) 15 | @true_n = NominalType.new(TrueClass) 16 | 17 | @tparam_t = VarType.new(:t) 18 | 19 | @f_or_s = UnionType.new(@integer, @string) 20 | @string_or_true = UnionType.new(@string, @true_n) 21 | 22 | @array_of_integer = GenericType.new(@array, @integer) 23 | @array_of_true = GenericType.new(@array, @true_n) 24 | @array_of_integer_string = GenericType.new(@array, @f_or_s) 25 | @array_of_true_string = GenericType.new(@array, @string_or_true) 26 | @hash_of_string_integer = GenericType.new(@hash, @string, @integer) 27 | @hash_of_string_true_integer = GenericType.new(@hash, @string_or_true, @integer) 28 | @a_a_f = GenericType.new(@array, @array_of_integer) 29 | @a_a_a_f = GenericType.new(@array, @a_a_f) 30 | @a_a_a_a_f = GenericType.new(@array, @a_a_a_f) 31 | end 32 | 33 | def test_intersection_same 34 | t1 = @parser.scan_str "(Integer) -> Integer" 35 | t2 = @parser.scan_str "(Integer) -> Integer" 36 | t3 = @parser.scan_str "(Integer) -> Integer" 37 | i = IntersectionType.new(t1, t2, t3) 38 | 39 | assert_equal(t1, i) 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /lib/rdl/types/var.rb: -------------------------------------------------------------------------------- 1 | module RDL::Type 2 | class VarType < Type 3 | attr_reader :name 4 | 5 | @@cache = {} 6 | 7 | class << self 8 | alias :__new__ :new 9 | end 10 | 11 | def self.new(name) 12 | name = name.to_s.to_sym 13 | t = @@cache[name] 14 | return t if t 15 | t = self.__new__ name 16 | return (@@cache[name] = t) # assignment evaluates to t 17 | end 18 | 19 | def initialize(name) 20 | @name = name 21 | end 22 | 23 | def to_s # :nodoc: 24 | return @name.to_s 25 | end 26 | 27 | def ==(other) 28 | return false if other.nil? 29 | other = other.canonical 30 | return (other.instance_of? self.class) && (other.name.to_s == @name.to_s) 31 | end 32 | 33 | alias eql? == 34 | 35 | # an uninstantiated variable is only comparable to itself 36 | def <=(other) 37 | return Type.leq(self, other) 38 | end 39 | 40 | def match(other) 41 | other = other.canonical 42 | other = other.type if other.instance_of? AnnotatedArgType 43 | return true if other.instance_of? WildQuery 44 | return self == other 45 | end 46 | 47 | def hash # :nodoc: 48 | return @name.to_s.hash 49 | end 50 | 51 | def member?(obj, vars_wild: false) 52 | return true if vars_wild 53 | raise TypeError, "Unbound type variable #{@name}" 54 | end 55 | 56 | def instantiate(inst) 57 | return inst[@name] if inst[@name] 58 | return self 59 | end 60 | end 61 | end 62 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014-2016, University of Maryland, College Park. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright 12 | notice, this list of conditions and the following disclaimer in the 13 | documentation and/or other materials provided with the distribution. 14 | 15 | 3. Neither the name of the copyright holder nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /lib/rdl/types/optional.rb: -------------------------------------------------------------------------------- 1 | module RDL::Type 2 | class OptionalType < Type 3 | attr_reader :type 4 | 5 | def initialize(type) 6 | raise RuntimeError, "Attempt to create optional type with non-type" unless type.is_a? Type 7 | raise "Can't have optional optional type" if type.is_a? OptionalType 8 | raise "Can't have optional vararg type" if type.is_a? VarargType 9 | raise "Can't have optional annotated type" if type.is_a? AnnotatedArgType 10 | @type = type 11 | super() 12 | end 13 | 14 | def to_s 15 | if @type.is_a? UnionType 16 | "?(#{@type.to_s})" 17 | elsif @type.is_a? MethodType 18 | "?{ #{@type.to_s} }" 19 | else 20 | "?#{@type.to_s}" 21 | end 22 | end 23 | 24 | def ==(other) # :nodoc: 25 | return false if other.nil? 26 | other = other.canonical 27 | return (other.instance_of? OptionalType) && (other.type == @type) 28 | end 29 | 30 | alias eql? == 31 | 32 | def match(other) 33 | other = other.canonical 34 | other = other.type if other.instance_of? AnnotatedArgType 35 | return true if other.instance_of? WildQuery 36 | return (other.instance_of? OptionalType) && (@type.match(other.type)) 37 | end 38 | 39 | # Note: no member?, because these can only appear in MethodType, where they're handled specially 40 | 41 | def instantiate(inst) 42 | return OptionalType.new(@type.instantiate(inst)) 43 | end 44 | 45 | def hash # :nodoc: 46 | return 57 + @type.hash 47 | end 48 | 49 | def optional? 50 | return true 51 | end 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /lib/rdl/types/singleton.rb: -------------------------------------------------------------------------------- 1 | module RDL::Type 2 | class SingletonType < Type 3 | attr_accessor :val 4 | attr_reader :nominal 5 | 6 | @@cache = {} 7 | @@cache.compare_by_identity 8 | 9 | class << self 10 | alias :__new__ :new 11 | end 12 | 13 | def self.new(val) 14 | t = @@cache[val] 15 | return t if t 16 | t = self.__new__ val 17 | return (@@cache[val] = t) # assignment evaluates to t 18 | end 19 | 20 | def initialize(val) 21 | @val = val 22 | @nominal = NominalType.new(val.class) 23 | end 24 | 25 | def ==(other) 26 | return false if other.nil? 27 | other = other.canonical 28 | return (other.instance_of? self.class) && (other.val.equal? @val) 29 | end 30 | 31 | alias eql? == 32 | 33 | def match(other) 34 | other = other.canonical 35 | other = other.type if other.instance_of? AnnotatedArgType 36 | return true if other.instance_of? WildQuery 37 | return self == other 38 | end 39 | 40 | def hash # :nodoc: 41 | return @val.hash 42 | end 43 | 44 | def to_s 45 | if @val.instance_of? Symbol 46 | ":#{@val}" 47 | elsif @val.nil? 48 | "nil" 49 | else 50 | @val.to_s 51 | # "Singleton(#{@val.to_s})" 52 | end 53 | end 54 | 55 | def <=(other) 56 | return Type.leq(self, other) 57 | end 58 | 59 | def member?(obj, *args) 60 | t = RDL::Util.rdl_type obj 61 | return t <= self if t 62 | obj.equal?(@val) 63 | end 64 | 65 | def instantiate(inst) 66 | return self 67 | end 68 | end 69 | end 70 | -------------------------------------------------------------------------------- /lib/rdl/types/dependent_arg.rb: -------------------------------------------------------------------------------- 1 | require_relative 'type' 2 | 3 | module RDL::Type 4 | class DependentArgType < Type 5 | attr_reader :name 6 | attr_reader :type 7 | attr_reader :predicate 8 | 9 | def initialize(name, type, predicate) 10 | @name = name 11 | @type = type 12 | @predicate = predicate 13 | raise RuntimeError, "Attempt to create annotated type with non-type" unless type.is_a? Type 14 | raise RuntimeError, "Attempt to create doubly annotated type" if (type.is_a? AnnotatedArgType) || (type.is_a? DependentArgType) 15 | super() 16 | end 17 | 18 | def to_s 19 | return "#{@type.to_s} #{@name} {{#{@predicate}}}" 20 | end 21 | 22 | def ==(other) # :nodoc: 23 | return false if other.nil? 24 | other = other.canonical 25 | return (other.instance_of? DependentArgType) && (other.name == @name) && (other.type == @type) 26 | end 27 | 28 | alias eql? == 29 | 30 | # match on the base type, ignoring refinement 31 | def match(other) 32 | return @type.match(other) 33 | end 34 | 35 | def hash # :nodoc: 36 | return (57 + @name.hash) * @type.hash 37 | end 38 | 39 | # ignore refinement in comparison for now 40 | def <=(other) 41 | return @type <= other 42 | end 43 | 44 | def leq_inst(other, inst=nil, ileft=true) 45 | return @type.leq_inst(other, inst, ileft) 46 | end 47 | 48 | def member?(obj, *args) 49 | return @type.member?(obj, *args) 50 | end 51 | 52 | def instantiate(inst) 53 | return DependentArgType.new(@name, @type.instantiate(inst), @predicate) 54 | end 55 | end 56 | end 57 | -------------------------------------------------------------------------------- /lib/types/rails/_helpers.rb: -------------------------------------------------------------------------------- 1 | # :integer, :bigint, :float, :decimal, :numeric, :datetime, :time, :date, :binary, :boolean. 2 | # null allowed 3 | 4 | RDL.type_alias '%symstr', 'Symbol or String' 5 | 6 | class RDL::Rails 7 | 8 | # [+ rails_type +] is a Rails column type (:string, :integer, etc) 9 | # returns a String containing an RDL type 10 | def self.column_to_rdl(rails_type) 11 | case rails_type 12 | when :string, :text, :binary 13 | return 'String' 14 | when :integer 15 | return 'Integer' 16 | when :float 17 | return 'Float' 18 | when :decimal 19 | return 'BigDecimal' 20 | when :boolean 21 | return '%bool' 22 | when :date 23 | return 'Date' 24 | when :time 25 | return 'Time' 26 | when :datetime 27 | return 'DateTime' 28 | when :json 29 | return 'Json' 30 | when :inet 31 | return 'Inet' 32 | when :tsvector 33 | return 'tsvector' 34 | else 35 | raise RuntimeError, "Unrecoganized column type #{rails_type}" 36 | end 37 | end 38 | 39 | # [+ model +] is an ActiveRecord::Base subclass that has been loaded. 40 | # Gets the columns_hash of the model and returns a String that can 41 | # serve as the paramter list to a method that accepts any number 42 | # of the model's attributes keyed by the attribute names. 43 | def self.attribute_types(model) 44 | args = [] 45 | 46 | model.columns_hash.each { |name, col| 47 | t = column_to_rdl(col.type) 48 | if col.null 49 | args << "#{name}: ?#{t}" 50 | else 51 | args << "#{name}: ?!#{t}" 52 | end 53 | } 54 | return args.join ',' 55 | end 56 | end 57 | -------------------------------------------------------------------------------- /lib/rdl/types/ast_node.rb: -------------------------------------------------------------------------------- 1 | require 'pp' 2 | 3 | module RDL::Type 4 | class AstNode < Type 5 | attr_reader :op 6 | attr_accessor :val, :children, :parent 7 | 8 | def initialize(op, val) 9 | @op = op 10 | @val = val 11 | @children = [] 12 | @parent = nil 13 | end 14 | 15 | def root 16 | unless self.parent 17 | self 18 | else 19 | root(self.parent) 20 | end 21 | end 22 | 23 | def insert(child) 24 | raise "AstNode expected" unless child.is_a? AstNode 25 | @children << child 26 | end 27 | 28 | def find_all(op) 29 | @children.find_all { |obj| obj.op == op } 30 | end 31 | 32 | def find_one(op) 33 | results = self.find_all(op) 34 | raise "One node expected" unless results.size < 2 35 | results[0] 36 | end 37 | 38 | def ==(other) 39 | return false if other.nil? 40 | other = other.canonical 41 | return (other.instance_of? self.class) && (other.val.equal? @val) 42 | end 43 | 44 | alias eql? == 45 | 46 | def match(other) 47 | other = other.canonical 48 | other = other.type if other.instance_of? AnnotatedArgType 49 | return true if other.instance_of? WildQuery 50 | return self == other 51 | end 52 | 53 | def hash # :nodoc: 54 | return @val.hash 55 | end 56 | 57 | def to_s 58 | self.pretty_inspect 59 | end 60 | 61 | def <=(other) 62 | return Type.leq(self, other) 63 | end 64 | 65 | def member?(obj, *args) 66 | raise "member? on AstNode called" 67 | end 68 | 69 | def instantiate(inst) 70 | return self 71 | end 72 | end 73 | end 74 | -------------------------------------------------------------------------------- /lib/types/core/regexp.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :Regexp 2 | 3 | RDL.type :Regexp, 'self.escape', '(String or Symbol) -> String' 4 | RDL.type :Regexp, 'self.last_match', '() -> MatchData', wrap: false # Can't wrap or messes up MatchData 5 | RDL.type :Regexp, 'self.last_match', '(Integer) -> String', wrap: false 6 | RDL.type :Regexp, :initialize, '(String, ?%any options, ?String kcode) -> self' 7 | RDL.type :Regexp, :initialize, '(Regexp) -> self' 8 | RDL.rdl_alias :Regexp, 'self.compile', 'self.new' 9 | RDL.rdl_alias :Regexp, 'self.quote', 'self.escape' 10 | RDL.type :Regexp, 'self.try_convert', '(%any obj) -> Regexp or nil' 11 | RDL.type :Regexp, 'self.union', '(*(Regexp or String) pats) -> Regexp' 12 | RDL.type :Regexp, 'self.union', '(Array pats) -> Regexp' 13 | RDL.type :Regexp, :==, '(%any other) -> %bool' 14 | RDL.type :Regexp, :===, '(%any other) -> %bool', wrap: false # Can't wrap this of it messes with $1, $2, etc as well! 15 | RDL.type :Regexp, :=~, '(String str) -> Integer or nil', wrap: false # Can't wrap this or it will mess with $1, $2, etc 16 | RDL.type :Regexp, :casefold?, '() -> %bool' 17 | RDL.type :Regexp, :encoding, '() -> Encoding' 18 | RDL.rdl_alias :Regexp, :eql?, :== 19 | RDL.type :Regexp, :fixed_encoding?, '() -> %bool' 20 | RDL.type :Regexp, :hash, '() -> Integer' 21 | RDL.type :Regexp, :inspect, '() -> String' 22 | RDL.type :Regexp, :match, '(String, ?Integer) -> MatchData or nil' 23 | RDL.type :Regexp, :named_captures, '() -> Hash>' 24 | RDL.type :Regexp, :names, '() -> Array' 25 | RDL.type :Regexp, :options, '() -> Integer' 26 | RDL.type :Regexp, :source, '() -> String' 27 | RDL.type :Regexp, :to_s, '() -> String' 28 | RDL.type :Regexp, :~, '() -> Integer or nil' 29 | -------------------------------------------------------------------------------- /lib/rdl/types/lexer.rex: -------------------------------------------------------------------------------- 1 | module RDL::Type 2 | class Parser 3 | 4 | macro 5 | ID ((\w|\:\:)+(!|\?|=)?)|~|\+|-|\/|&|\||\^ 6 | SYMBOL :\w+ 7 | SPECIAL_ID %\w+ 8 | FIXNUM -?(\d)+ 9 | FLOAT -?\d\.\d+ 10 | PREDICATE \{\{(?:(?!}}).)+\}\} 11 | COMP ``(?:(?!``).)+`` 12 | 13 | 14 | rule 15 | \s # skip 16 | -> { [:RARROW, text] } 17 | => { [:RASSOC, text] } 18 | \( { [:LPAREN, text] } 19 | \) { [:RPAREN, text] } 20 | {PREDICATE} { [:PREDICATE, text[2..-3]] } 21 | \{ { [:LBRACE, text] } 22 | \} { [:RBRACE, text] } 23 | \[ { [:LBRACKET, text] } 24 | \] { [:RBRACKET, text] } 25 | < { [:LESS, text] } 26 | > { [:GREATER, text] } 27 | = { [:EQUAL, text] } 28 | , { [:COMMA, text] } 29 | \? { [:QUERY, text] } 30 | \! { [:BANG, text] } 31 | ~ { [:TILDE, text] } 32 | \*\* { [:STARSTAR, text] } 33 | \* { [:STAR, text] } 34 | \#T { [:HASH_TYPE, text] } 35 | \#Q { [:HASH_QUERY, text] } 36 | \$\{ { [:CONST_BEGIN, text] } 37 | \.\.\. { [:DOTS, text] } 38 | \. { [:DOT, text] } 39 | {COMP} { [:COMP, text[2..-3]] } 40 | {FLOAT} { [:FLOAT, text] } # Must go before FIXNUM 41 | {FIXNUM} { [:FIXNUM, text] } 42 | {ID} { if text == "or" then [:OR, text] else [:ID, text] end } 43 | {SYMBOL} { [:SYMBOL, text[1..-1]] } 44 | \: { [:COLON, text] } # Must come after SYMBOL 45 | {SPECIAL_ID} { [:SPECIAL_ID, text] } 46 | '[^']*' { [:STRING, text.gsub("'", "")] } 47 | "[^"]*" { [:STRING, text.gsub('"', "")] } 48 | 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /test/test_dsl.rb: -------------------------------------------------------------------------------- 1 | require 'minitest/autorun' 2 | $LOAD_PATH << File.dirname(__FILE__) + "/../lib" 3 | require 'rdl' 4 | 5 | class TestDsl < Minitest::Test 6 | 7 | class Pair 8 | 9 | # dsl { 10 | # type :left, '(Integer) -> Integer' 11 | # type :right, '(Integer) -> Integer' 12 | # } 13 | def entry(&blk) 14 | instance_eval(&blk) 15 | end 16 | 17 | def left(x) 18 | @left = x 19 | end 20 | 21 | def right(x) 22 | @right = x 23 | end 24 | 25 | def get 26 | [@left, @right] 27 | end 28 | end 29 | 30 | class Tree 31 | 32 | # dsl :tree { # recursive DSL 33 | # type :left, '(Integer) -> Integer' 34 | # dsl :left, :tree 35 | # type :right, '(Integer) -> Integer' 36 | # dsl :right, :tree 37 | # } 38 | def entry(val, &blk) 39 | @val = val 40 | instance_eval(&blk) 41 | end 42 | 43 | def left(x, &blk) 44 | if blk 45 | @left = Tree.new.entry(x, &blk) 46 | else 47 | @left = x 48 | end 49 | end 50 | 51 | def right(x, &blk) 52 | if blk 53 | @right = Tree.new.entry(x, &blk) 54 | else 55 | @right = x 56 | end 57 | end 58 | 59 | def get 60 | l = @left.instance_of?(Tree) ? @left.get : @left 61 | r = @right.instance_of?(Tree) ? @right.get : @right 62 | [@val, l, r] 63 | end 64 | end 65 | 66 | def test_pair 67 | _ = Pair.new.entry { 68 | left 3 69 | right 4 70 | } 71 | end 72 | 73 | def test_tree 74 | _ = Tree.new.entry(2) { 75 | left(3) 76 | right(4) { 77 | left(5) { 78 | left(6) 79 | right(7) 80 | } 81 | right(8) 82 | } 83 | } 84 | end 85 | end 86 | -------------------------------------------------------------------------------- /lib/rdl/types/vararg.rb: -------------------------------------------------------------------------------- 1 | module RDL::Type 2 | class VarargType < Type 3 | attr_reader :type 4 | 5 | @@cache = {} 6 | 7 | class << self 8 | alias :__new__ :new 9 | end 10 | 11 | def self.new(type) 12 | t = @@cache[type] 13 | return t if t 14 | raise RuntimeError, "Attempt to create vararg type with non-type" unless type.is_a? Type 15 | t = VarargType.__new__ type 16 | return (@@cache[type] = t) # assignment evaluates to t 17 | end 18 | 19 | def initialize(type) 20 | raise "Can't have vararg optional type" if type.is_a? OptionalType 21 | raise "Can't have vararg vararg type" if type.is_a? VarargType 22 | raise "Can't have optional annotated type" if type.is_a? AnnotatedArgType 23 | @type = type 24 | super() 25 | end 26 | 27 | def to_s 28 | if @type.instance_of? UnionType 29 | "*(#{@type.to_s})" 30 | else 31 | "*#{@type.to_s}" 32 | end 33 | end 34 | 35 | def ==(other) # :nodoc: 36 | return false if other.nil? 37 | other = other.canonical 38 | return (other.instance_of? VarargType) && (other.type == @type) 39 | end 40 | 41 | alias eql? == 42 | 43 | def match(other) 44 | other = other.canonical 45 | other = other.type if other.instance_of? AnnotatedArgType 46 | return true if other.instance_of? WildQuery 47 | return (other.instance_of? VarargType) && (@type.match(other.type)) 48 | end 49 | 50 | # Note: no member?, because these can only appear in MethodType, where they're handled specially 51 | 52 | def instantiate(inst) 53 | return VarargType.new(@type.instantiate(inst)) 54 | end 55 | 56 | def hash # :nodoc: 57 | return 59 + @type.hash 58 | end 59 | 60 | def vararg? 61 | return true 62 | end 63 | end 64 | end 65 | -------------------------------------------------------------------------------- /lib/types/core/range.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :Range 2 | 3 | # Range is immutable, so covariant 4 | RDL.type_params(:Range, [:t], nil, variance: [:+]) { |t| t.member?(self.begin) && t.member?(self.end) } # TODO: And instantiated if t instantiated 5 | 6 | # TODO: Parse error 7 | #RDL.type :Range, :Range, 'self.new', '(begin: [<=> : (u, u) -> Integer], end: [<=>, (u, u) -> Integer], exclude_end: ?%bool) -> Range' 8 | RDL.type :Range, :==, '(%any obj) -> %bool' 9 | RDL.type :Range, :===, '(%any obj) -> %bool' 10 | RDL.type :Range, :begin, '() -> t' 11 | RDL.type :Range, :bsearch, '() { (t) -> %bool } -> u or nil' 12 | RDL.type :Range, :cover?, '(%any obj) -> %bool' 13 | RDL.type :Range, :each, '() { (t) -> %any } -> self' 14 | RDL.type :Range, :each, '() -> Enumerator' 15 | RDL.type :Range, :end, '() -> t' 16 | RDL.rdl_alias :Range, :eql?, :== 17 | RDL.type :Range, :exclude_end?, '() -> %bool' 18 | RDL.type :Range, :first, '() -> t' 19 | RDL.type :Range, :first, '(Integer n) -> Array' 20 | RDL.type :Range, :hash, '() -> Integer' 21 | RDL.type :Range, :include?, '(%any obj) -> %bool' 22 | RDL.type :Range, :inspect, '() -> String' 23 | RDL.type :Range, :last, '() -> t' 24 | RDL.type :Range, :last, '(Integer n) -> Array' 25 | RDL.type :Range, :max, '() -> t' 26 | RDL.type :Range, :max, '() { (t, t) -> Integer } -> t' 27 | RDL.type :Range, :max, '(Integer n) -> Array' 28 | RDL.type :Range, :max, '(Integer n) { (t, t) -> Integer } -> Array' 29 | RDL.rdl_alias :Range, :member?, :include 30 | RDL.type :Range, :min, '() -> t' 31 | RDL.type :Range, :min, '() { (t, t) -> Integer } -> t' 32 | RDL.type :Range, :min, '(Integer n) -> Array' 33 | RDL.type :Range, :min, '(Integer n) { (t, t) -> Integer } -> Array' 34 | RDL.type :Range, :size, '() -> Integer or nil' 35 | RDL.type :Range, :step, '(?Integer n) { (t) -> %any } -> self' 36 | RDL.type :Range, :step, '(?Integer n) -> Enumerator' 37 | RDL.type :Range, :to_s, '() -> String' 38 | -------------------------------------------------------------------------------- /lib/types/core/dir.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :Dir 2 | 3 | RDL.rdl_alias :Dir, :[], :glob 4 | 5 | RDL.type :Dir, 'self.chdir', '(?(String or Pathname)) -> 0' 6 | RDL.type :Dir, 'self.chdir', '(?(String or Pathname)) { (String) -> u } -> u' 7 | RDL.type :Dir, 'self.chroot', '(String) -> 0' 8 | RDL.type :Dir, 'self.delete', '(String) -> 0' 9 | RDL.type :Dir, 'self.entries', '(String, ?Encoding) -> Array' 10 | RDL.type :Dir, 'self.exist?', '(String file) -> %bool' 11 | # exists? deprecated 12 | RDL.type :Dir, 'self.foreach', '(String dir, ?Encoding) { (String) -> %any } -> nil' 13 | RDL.type :Dir, 'self.foreach', '(String dir, ?Encoding) -> Enumerator' 14 | RDL.type :Dir, 'self.getwd', '() -> String' 15 | RDL.type :Dir, 'self.glob', '(String or Array pattern, ?Fixum flags) -> Array' 16 | RDL.type :Dir, 'self.glob', '(String or Array pattern, ?Fixum flags) { (String) -> %any} -> nil' 17 | RDL.type :Dir, 'self.home', '(?String) -> String' 18 | RDL.type :Dir, 'self.mkdir', '(String, ?Integer) -> 0' 19 | RDL.type :Dir, 'self.open', '(String, ?Encoding) -> Dir' 20 | RDL.type :Dir, 'self.open', '(String, ?Encoding) { (Dir) -> u } -> u' 21 | RDL.type :Dir, 'self.pwd', '() -> String' 22 | RDL.type :Dir, 'self.rmdir', '(String) -> 0' 23 | RDL.type :Dir, 'self.unlink', '(String) -> 0' 24 | RDL.type :Dir, :close, '() -> nil' 25 | RDL.type :Dir, :each, '() { (String) -> %any } -> self' 26 | RDL.type :Dir, :each, '() -> Enumerator' 27 | RDL.type :Dir, :fileno, '() -> Integer' 28 | RDL.type :Dir, :initialize, '(String, ?Encoding) -> self' 29 | RDL.type :Dir, :inspect, '() -> String' 30 | RDL.type :Dir, :path, '() -> String or nil' 31 | RDL.type :Dir, :pos, '() -> Integer' 32 | RDL.type :Dir, :pos=, '(Integer) -> Integer' 33 | RDL.type :Dir, :read, '() -> String or nil' 34 | RDL.type :Dir, :rewind, '() -> self' 35 | RDL.type :Dir, :seek, '(Integer) -> self' 36 | RDL.type :Dir, :tell, '() -> Integer' 37 | RDL.type :Dir, :to_path, '() -> String or nil' 38 | -------------------------------------------------------------------------------- /lib/rdl_disable.rb: -------------------------------------------------------------------------------- 1 | # Defines RDL methods that do nothing 2 | 3 | module RDL 4 | end 5 | 6 | module RDL::Annotate 7 | def pre(*args); end 8 | def post(*args); end 9 | def type(*args); end 10 | def var_type(*args); end 11 | def attr_accessor_type(*args) 12 | args.each_slice(2) { |name, typ| attr_accessor name } 13 | nil 14 | end 15 | 16 | def attr_reader_type(*args) 17 | args.each_slice(2) { |name, typ| attr_reader name } 18 | nil 19 | end 20 | 21 | alias_method :attr_type, :attr_reader_type 22 | 23 | def attr_writer_type(*args) 24 | args.each_slice(2) { |name, typ| attr_writer name } 25 | nil 26 | end 27 | 28 | def rdl_alias(*args); end 29 | def type_params(*args); end 30 | end 31 | 32 | module RDL::RDLAnnotate 33 | define_method :rdl_pre, RDL::Annotate.instance_method(:pre) 34 | define_method :rdl_post, RDL::Annotate.instance_method(:post) 35 | define_method :rdl_type, RDL::Annotate.instance_method(:type) 36 | define_method :rdl_var_type, RDL::Annotate.instance_method(:var_type) 37 | define_method :rdl_alias, RDL::Annotate.instance_method(:rdl_alias) 38 | define_method :rdl_type_params, RDL::Annotate.instance_method(:type_params) 39 | define_method :rdl_attr_accessor_type, RDL::Annotate.instance_method(:attr_accessor_type) # note in disable these don't call var_type 40 | define_method :rdl_attr_reader_type, RDL::Annotate.instance_method(:attr_reader_type) 41 | define_method :rdl_attr_type, RDL::Annotate.instance_method(:attr_type) 42 | define_method :rdl_attr_writer_type, RDL::Annotate.instance_method(:attr_writer_type) 43 | end 44 | 45 | 46 | module RDL 47 | extend RDL::Annotate 48 | def self.type_alias(*args); end 49 | def self.nowrap(*args); end 50 | def self.do_typecheck(*args); end 51 | def self.at(*args); end 52 | def self.note_type(*args); end 53 | def self.remove_type(*args); end 54 | def self.instantaite!(*args); self; end 55 | def self.deinstantaite!(*args); self; end 56 | def self.type_cast(*args); self; end 57 | def self.query(*args); end 58 | end 59 | 60 | def RDL.config(*args); end 61 | -------------------------------------------------------------------------------- /lib/rdl/types/nominal.rb: -------------------------------------------------------------------------------- 1 | module RDL::Type 2 | class NominalType < Type 3 | attr_reader :name # string 4 | 5 | @@cache = {} 6 | 7 | class << self 8 | alias :__new__ :new 9 | end 10 | 11 | def self.new(name) 12 | name = name.to_s 13 | t = @@cache[name] 14 | return t if t 15 | t = self.__new__ name 16 | return (@@cache[name] = t) # assignment evaluates to t 17 | end 18 | 19 | def initialize(name) 20 | @name = name 21 | end 22 | 23 | def ==(other) 24 | return false if other.nil? 25 | other = other.canonical 26 | return (other.instance_of? self.class) && (other.name == @name) 27 | end 28 | 29 | alias eql? == 30 | 31 | def match(other) 32 | other = other.canonical 33 | other = other.type if other.instance_of? AnnotatedArgType 34 | return true if other.instance_of? WildQuery 35 | return self == other 36 | end 37 | 38 | def hash # :nodoc: 39 | return @name.hash 40 | end 41 | 42 | def to_s 43 | if @name.start_with? '#' 46 | else 47 | n = @name 48 | end 49 | return RDL::Util.add_singleton_marker(n[8..-2]) 50 | else 51 | return @name 52 | end 53 | end 54 | 55 | def klass 56 | @klass = RDL::Util.to_class(name) unless defined? @klass 57 | return @klass 58 | end 59 | 60 | def <=(other) 61 | return Type.leq(self, other) 62 | end 63 | 64 | def member?(obj, *args) 65 | t = RDL::Util.rdl_type obj 66 | return t <= self if t 67 | return true if obj.nil? 68 | return obj.is_a? klass 69 | end 70 | 71 | def instantiate(inst) 72 | return self 73 | end 74 | 75 | @@cache.merge!({"NilClass" => SingletonType.new(nil), 76 | "TrueClass" => SingletonType.new(true), 77 | "FalseClass" => SingletonType.new(false), 78 | }) 79 | end 80 | end 81 | -------------------------------------------------------------------------------- /lib/rdl/types/intersection.rb: -------------------------------------------------------------------------------- 1 | require_relative 'type' 2 | 3 | module RDL::Type 4 | class IntersectionType < Type 5 | attr_reader :types 6 | 7 | @@cache = {} 8 | 9 | class << self 10 | alias :__new__ :new 11 | end 12 | 13 | def self.new(*types) 14 | ts = [] 15 | types.each { |t| 16 | if t == RDL::Globals.types[:bot] 17 | next 18 | elsif t.instance_of? IntersectionType 19 | ts.concat t.types 20 | else 21 | raise RuntimeError, "Attempt to create intersection type with non-type" unless t.is_a? Type 22 | ts << t 23 | end 24 | } 25 | ts.sort! { |a,b| a.object_id <=> b.object_id } 26 | ts.uniq! 27 | 28 | return RDL::Globals.types[:bot] if ts.size == 0 29 | return ts[0] if ts.size == 1 30 | 31 | t = @@cache[ts] 32 | return t if t 33 | t = IntersectionType.__new__(ts) 34 | return (@@cache[ts] = t) # assignment evaluates to t 35 | end 36 | 37 | def initialize(types) 38 | @types = types 39 | super() 40 | end 41 | 42 | def to_s # :nodoc: 43 | return "(#{@types.map { |t| t.to_s }.join(' and ')})" 44 | end 45 | 46 | def ==(other) # :nodoc: 47 | return false if other.nil? 48 | other = other.type if other.is_a? DependentArgType 49 | other = other.canonical 50 | return (other.instance_of? IntersectionType) && (other.types == @types) 51 | end 52 | 53 | alias eql? == 54 | 55 | def match(other) 56 | other = other.canonical 57 | other = other.type if other.instance_of? AnnotatedArgType 58 | return true if other.instance_of? WildQuery 59 | return false unless other.instance_of? IntersectionType 60 | return false if @types.length != other.types.length 61 | @types.all? { |t| other.types.any? { |ot| t.match(ot) } } 62 | end 63 | 64 | def member?(obj, *args) 65 | @types.all? { |t| t.member?(obj, *args) } 66 | end 67 | 68 | def instantiate(inst) 69 | return IntersectionType.new(*(@types.map { |t| t.instantiate(inst) })) 70 | end 71 | 72 | def hash # :nodoc: 73 | return 47 + @types.hash 74 | end 75 | end 76 | end 77 | -------------------------------------------------------------------------------- /test/test_alias.rb: -------------------------------------------------------------------------------- 1 | require 'minitest/autorun' 2 | $LOAD_PATH << File.dirname(__FILE__) + "/../lib" 3 | require 'rdl' 4 | 5 | class TestAlias < Minitest::Test 6 | extend RDL::Annotate 7 | 8 | def test_alias_lookup 9 | self.class.class_eval { 10 | rdl_alias :foobar1, :foobar 11 | rdl_alias :foobar2, :foobar 12 | rdl_alias :foobar3, :foobar2 13 | rdl_alias :foobar4, :foobar3 14 | rdl_alias :foobar5, :foobar2 15 | } 16 | assert_equal :foobar, RDL::Wrap.resolve_alias(TestAlias, :foobar) 17 | assert_equal :foobar, RDL::Wrap.resolve_alias(TestAlias, :foobar1) 18 | assert_equal :foobar, RDL::Wrap.resolve_alias(TestAlias, :foobar2) 19 | assert_equal :foobar, RDL::Wrap.resolve_alias(TestAlias, :foobar3) 20 | assert_equal :foobar, RDL::Wrap.resolve_alias(TestAlias, :foobar4) 21 | assert_equal :foobar, RDL::Wrap.resolve_alias(TestAlias, :foobar5) 22 | end 23 | 24 | def test_basic_alias_contract 25 | self.class.class_eval { 26 | pre { |x| x > 0 } 27 | def m1(x) return x; end 28 | alias_method :m2, :m1 29 | } 30 | assert_equal 3, m2(3) 31 | assert_raises(RDL::Contract::ContractError) { m2(-1) } 32 | self.class.class_eval { alias m3 m1 } 33 | assert_equal 3, m3(3) 34 | assert_raises(RDL::Contract::ContractError) { m3(-1) } 35 | end 36 | 37 | def test_existing_alias_contract 38 | self.class.class_eval { 39 | def m4(x) return x; end 40 | alias_method :m5, :m4 41 | rdl_alias :m5, :m4 42 | pre(:m4) { |x| x > 0 } 43 | } 44 | assert_equal 3, m5(3) 45 | assert_raises(RDL::Contract::ContractError) { m5(-1) } 46 | 47 | def m6(x) return x; end 48 | self.class.class_eval { 49 | alias m7 m6 50 | rdl_alias :m7, :m6 51 | pre(:m6) { |x| x > 0 } 52 | } 53 | assert_equal 3, m7(3) 54 | assert_raises(RDL::Contract::ContractError) { m7(-1) } 55 | 56 | def m8(x) return x; end 57 | self.class.class_eval { 58 | alias_method :m9, :m8 59 | rdl_alias :m9, :m8 60 | alias_method :m10, :m9 61 | rdl_alias :m10, :m9 62 | pre(:m8) { |x| x > 0 } 63 | } 64 | assert_equal 3, m10(3) 65 | assert_raises(RDL::Contract::ContractError) { m10(-1) } 66 | end 67 | 68 | end 69 | -------------------------------------------------------------------------------- /lib/rdl/types/generic.rb: -------------------------------------------------------------------------------- 1 | require_relative 'type' 2 | 3 | module RDL::Type 4 | # A type that is parameterized on one or more other types. The base type 5 | # must be a NominalType or self, while the parameters should be strings or symbols 6 | class GenericType < Type 7 | attr_reader :base 8 | attr_reader :params 9 | 10 | def initialize(base, *params) 11 | raise RuntimeError, "Attempt to create generic type with non-type param" unless params.all? { |p| p.is_a? Type } 12 | raise "base must be NominalType or self, got #{base} of type #{base.class}" unless ((base.instance_of? NominalType) || ((base.instance_of? VarType) && (base.name.to_s == "self"))) 13 | @base = base 14 | @params = params 15 | super() 16 | end 17 | 18 | def to_s 19 | "#{@base}<#{@params.map { |t| t.to_s }.join(', ')}>" 20 | end 21 | 22 | def ==(other) # :nodoc: 23 | return false if other.nil? 24 | other = other.canonical 25 | return (other.instance_of? GenericType) && (other.base == @base) && (other.params == @params) 26 | end 27 | 28 | alias eql? == 29 | 30 | def match(other) 31 | other = other.canonical 32 | other = other.type if other.instance_of? AnnotatedArgType 33 | return true if other.instance_of? WildQuery 34 | return false unless other.instance_of? GenericType 35 | return @params.length == other.params.length && @params.zip(other.params).all? { |t,o| t.match(o) } 36 | end 37 | 38 | def <=(other) 39 | return Type.leq(self, other) 40 | end 41 | 42 | def member?(obj, *args) 43 | raise "No type parameters defined for #{base.name}" unless RDL::Globals.type_params[base.name] 44 | # formals = RDL::Globals.type_params[base.name][0] 45 | t = RDL::Util.rdl_type obj 46 | return t <= self if t 47 | return false unless base.member?(obj, *args) 48 | return true 49 | end 50 | 51 | def instantiate(inst) 52 | GenericType.new(base.instantiate(inst), *params.map { |t| t.instantiate(inst) }) 53 | end 54 | 55 | def hash 56 | (61 + @base.hash) * @params.hash 57 | end 58 | 59 | def to_inst 60 | return RDL::Globals.type_params[base.name][0].zip(@params).to_h 61 | end 62 | end 63 | end 64 | -------------------------------------------------------------------------------- /lib/rdl/types/structural.rb: -------------------------------------------------------------------------------- 1 | module RDL::Type 2 | class StructuralType < Type 3 | attr_reader :methods 4 | 5 | @@cache = {} 6 | 7 | class << self 8 | alias :__new__ :new 9 | end 10 | 11 | def self.new(methods) 12 | t = @@cache[methods] 13 | return t if t 14 | t = StructuralType.__new__(methods) 15 | return (@@cache[methods] = t) # assignment evaluates to t 16 | end 17 | 18 | # Create a new StructuralType. 19 | # 20 | # [+methods+] Map from method names as symbols to their types. 21 | def initialize(methods) 22 | raise "methods can't be empty" if methods.empty? 23 | methods.each { |m, t| 24 | raise RuntimeError, "Method names in StructuralType must be symbols" unless m.instance_of? Symbol 25 | raise RuntimeError, "Got #{t.class} where MethodType expected" unless t.instance_of? MethodType 26 | # Note intersection types not allowed as subtyping would be tricky 27 | } 28 | @methods = methods 29 | super() 30 | end 31 | 32 | def to_s # :nodoc: 33 | "[ " + @methods.each_pair.map { |m, t| "#{m.to_s}: #{t.to_s}" }.sort.join(", ") + " ]" 34 | end 35 | 36 | def <=(other) 37 | return Type.leq(self, other) 38 | end 39 | 40 | def member?(obj, *args) 41 | t = RDL::Util.rdl_type obj 42 | return t <= self if t 43 | return NominalType.new(obj.class) <= self 44 | end 45 | 46 | def instantiate(inst) 47 | StructuralType.new(Hash[*@methods.each_pair.map { |m, t| [m, t.instantiate(inst)] }.flatten]) 48 | end 49 | 50 | def ==(other) # :nodoc: 51 | return false if other.nil? 52 | other = other.canonical 53 | return (other.instance_of? StructuralType) && (other.methods == @methods) 54 | end 55 | 56 | alias eql? == 57 | 58 | def match(other) 59 | other = other.canonical 60 | other = other.type if other.instance_of? AnnotatedArgType 61 | return true if other.instance_of? WildQuery 62 | return false unless other.instance_of? StructuralType 63 | return (@methods.length == other.methods.length && 64 | @methods.all? { |k, v| (other.methods.has_key? k) && (v.match(other.methods[k]))}) 65 | end 66 | 67 | def hash # :nodoc: 68 | @methods.hash 69 | end 70 | end 71 | end 72 | -------------------------------------------------------------------------------- /lib/types/rails/active_record/model_schema.rb: -------------------------------------------------------------------------------- 1 | class ActiveRecord::Base 2 | extend RDL::RDLAnnotate 3 | end 4 | 5 | module ActiveRecord::ModelSchema::ClassMethods 6 | extend RDL::RDLAnnotate 7 | 8 | rdl_post(:load_schema!) { |ret| # load_schema! doesn't return anything interesting 9 | =begin 10 | columns_hash.each { |name, col| 11 | t = RDL::Rails.column_to_rdl(col.type) 12 | if col.null 13 | # may be null; show nullability in return type 14 | rdl_type name, "() -> #{t} or nil" # getter 15 | rdl_type :"#{name}=", "(#{t}) -> #{t} or nil" # setter 16 | rdl_type :write_attribute, "(:#{name}, #{t}) -> %bool" 17 | rdl_type :update_attribute, "(:#{name}, #{t}) -> %bool" 18 | rdl_type :update_column, "(:#{name}, #{t}) -> %bool" 19 | else 20 | # not null; can't truly check in type system but hint via the name 21 | rdl_type name, "() -> !#{t}" # getter 22 | rdl_type :"#{name}=", "(!#{t}) -> !#{t}" # setter 23 | rdl_type :write_attribute, "(:#{name}, !#{t}) -> %bool" 24 | rdl_type :update_attribute, "(:#{name}, #{t}) -> %bool" 25 | rdl_type :update_column, "(:#{name}, #{t}) -> %bool" 26 | end 27 | } 28 | 29 | attribute_types = RDL::Rails.attribute_types(self) 30 | rdl_type :'self.find_by', '(' + attribute_types + ") -> #{self} or nil" 31 | rdl_type :'self.find_by!', '(' + attribute_types + ") -> #{self}" 32 | rdl_type :update, '(' + attribute_types + ') -> %bool' 33 | rdl_type :update_columns, '(' + attribute_types + ') -> %bool' 34 | rdl_type :'attributes=', '(' + attribute_types + ') -> %bool' 35 | 36 | # If called with String arguments, can't check types as precisely 37 | rdl_type :write_attribute, '(String, %any) -> %bool' 38 | rdl_type :update_attribute, '(String, %any) -> %bool' 39 | rdl_type :update_column, '(String, %any) -> %bool' 40 | 41 | rdl_type :'self.joins', "(Symbol or String) -> ActiveRecord::Associations::CollectionProxy<#{self.to_s}>" 42 | rdl_type :'self.none', "() -> ActiveRecord::Associations::CollectionProxy<#{self.to_s}>" 43 | rdl_type :'self.where', '(String, *%any) -> ActiveRecord::Associations::CollectionProxy' 44 | rdl_type :'self.where', '(**%any) -> ActiveRecord::Associations::CollectionProxy' 45 | =end 46 | true 47 | } 48 | 49 | end 50 | -------------------------------------------------------------------------------- /lib/rdl/types/type_inferencer.rb: -------------------------------------------------------------------------------- 1 | module RDL 2 | class TypeInferencer 3 | def self.infer_type(it) 4 | current_types = Set.new 5 | it_types = it.map {|t| t.rdl_type} 6 | it_types = it_types.to_set 7 | 8 | it_types.each {|t| 9 | subtype = current_types.any? {|ct| t.le(ct)} 10 | current_types.add(t) if not subtype 11 | } 12 | 13 | if current_types.size == 1 14 | current_types.to_a[0] 15 | elsif current_types.size == 0 16 | RDL::Globals.types[:nil] 17 | else 18 | RDL::Type::UnionType.new(*self.unify_param_types(current_types)) 19 | end 20 | end 21 | 22 | private 23 | 24 | def self.extract_types(param_type) 25 | param_type.instance_of?(RDL::Type::UnionType) ? param_type.types.to_a : [param_type] 26 | end 27 | 28 | # Unifies i.e. #, Array>}> into 29 | # Array<(Array or String)> 30 | # If this step is not called, then infer_type for 31 | # [["a", "b"], [["c"]]].rdl_type would return 32 | # (Array> or Array) instead of 33 | # (Array<(Array or String)>) 34 | def self.unify_param_types(type_set) 35 | non_param_classes = [] 36 | parameterized_classes = {} 37 | 38 | type_set.each {|member_type| 39 | if member_type.instance_of? RDL::Type::GenericType 40 | nominal_type = member_type.base 41 | 42 | tparam_set = parameterized_classes.fetch(nominal_type) {|n_type| 43 | cls = eval(n_type.name.to_s) 44 | type_parameters = cls.instance_variable_get :@__cls_params 45 | [].fill([], 0, type_parameters.size) 46 | } 47 | 48 | cls = eval(nominal_type.name.to_s) 49 | type_parameters = cls.instance_variable_get :@__cls_params 50 | ((0..(type_parameters.size - 1)).map {|tparam_index| 51 | extract_types(member_type.params[tparam_index]) 52 | }).each_with_index {|type_parameter,index| 53 | tparam_set[index]+=type_parameter 54 | } 55 | 56 | parameterized_classes[nominal_type] = tparam_set 57 | else 58 | non_param_classes << member_type 59 | end 60 | } 61 | 62 | parameterized_classes.each {|nominal, ts| 63 | nt = ts.map {|unioned_type_parameter| 64 | RDL::Type::UnionType.new(*unify_param_types(unioned_type_parameter)) 65 | } 66 | 67 | non_param_classes << RDL::Type::GenericType.new(nominal, *nt) 68 | } 69 | 70 | non_param_classes 71 | end 72 | end 73 | end 74 | -------------------------------------------------------------------------------- /test/test_contract.rb: -------------------------------------------------------------------------------- 1 | require 'minitest/autorun' 2 | $LOAD_PATH << File.dirname(__FILE__) + "/../lib" 3 | require 'rdl' 4 | 5 | class TestContract < Minitest::Test 6 | include RDL::Contract 7 | 8 | def test_flat 9 | pos = FlatContract.new("Positive") { |x| x > 0 } 10 | assert_equal "Positive", pos.to_s 11 | assert_raises(ContractError) { pos.check self, 0 } 12 | assert (pos.check self, 1) 13 | gt = FlatContract.new("Greater Than") { |x, y| x > y } 14 | assert (gt.check self, 4, 3) 15 | assert_raises(ContractError) { gt.check self, 3, 4 } 16 | end 17 | 18 | def test_and 19 | pos = FlatContract.new("Positive") { |x| x > 0 } 20 | five = FlatContract.new("Five") { |x| x == 5 } 21 | gt = FlatContract.new("Greater Than 3") { |x| x > 3 } 22 | posfive = AndContract.new(pos, five) 23 | assert_equal "Positive && Five", posfive.to_s 24 | posfivegt = AndContract.new(pos, five, gt) 25 | assert (posfive.check self, 5) 26 | assert_raises(ContractError) { posfive.check self, 4 } 27 | assert (posfivegt.check self, 5) 28 | assert_raises(ContractError) { posfivegt.check self, 4 } 29 | end 30 | 31 | def test_or 32 | pos = FlatContract.new("Positive") { |x| x > 0 } 33 | zero = FlatContract.new("Zero") { |x| x == 0 } 34 | neg = FlatContract.new("Neg") { |x| x < 0 } 35 | poszero = OrContract.new(pos, zero) 36 | assert_equal "Positive && Zero", poszero.to_s 37 | poszeroneg = OrContract.new(pos, zero, neg) 38 | assert (poszero.check self, 1) 39 | assert (poszero.check self, 0) 40 | assert_raises(ContractError) { poszero.check self, (-1) } 41 | assert (poszeroneg.check self, (-1)) 42 | end 43 | 44 | def test_proc 45 | pos = FlatContract.new("Positive") { |x| x > 0 } 46 | neg = FlatContract.new("Negative") { |ret, x| ret < 0 } 47 | pc = ProcContract.new(pre_cond: pos, post_cond: neg) 48 | proc1 = pc.wrap(self) { |x| -x } 49 | assert (proc1.call(42)) 50 | assert_raises(ContractError) { proc1.call(-42) } 51 | proc2 = pc.wrap(self) { |x| x } 52 | assert_raises(ContractError) { proc2.call(42) } 53 | end 54 | 55 | def test_proc_with_block 56 | skip "Not working yet." 57 | pos = FlatContract.new("Positive") { |x| x > 0 } 58 | pc = ProcContract.new(pre_cond: pos) 59 | proc = pc.wrap(self) { |x, &blk| blk.call(x) } 60 | assert_equal 42, (proc.call(42) { |y| y }) 61 | end 62 | 63 | def test_turn_off 64 | foo = FlatContract.new("Foo") { 65 | pos = FlatContract.new("Positive") { |x| x > 0 } 66 | pos.check self, -42 67 | true 68 | } 69 | assert_equal true, foo.check(self) 70 | end 71 | end 72 | -------------------------------------------------------------------------------- /lib/rdl/util.rb: -------------------------------------------------------------------------------- 1 | class RDL::Util 2 | 3 | SINGLETON_MARKER = "[s]" 4 | SINGLETON_MARKER_REGEXP = Regexp.escape(SINGLETON_MARKER) 5 | GLOBAL_NAME = "_Globals" # something that's not a valid class name 6 | 7 | def self.to_class(klass) 8 | return klass if klass.class == Class 9 | if has_singleton_marker(klass) 10 | klass = remove_singleton_marker(klass) 11 | sing = true 12 | end 13 | c = klass.to_s.split("::").inject(Object) { |base, name| base.const_get(name) } 14 | c = c.singleton_class if sing 15 | return c 16 | end 17 | 18 | def self.singleton_class_to_class(cls) 19 | cls_str = cls.to_s 20 | cls_str = cls_str.split('(')[0] + '>' if cls_str['('] 21 | to_class cls_str[8..-2] 22 | end 23 | 24 | def self.to_class_str(cls) 25 | cls_str = cls.to_s 26 | if cls_str.start_with? '#' if cls_str['('] 28 | cls_str = RDL::Util.add_singleton_marker(cls_str[8..-2]) 29 | end 30 | cls_str 31 | end 32 | 33 | def self.has_singleton_marker(klass) 34 | return (klass =~ /^#{SINGLETON_MARKER_REGEXP}/) 35 | end 36 | 37 | def self.remove_singleton_marker(klass) 38 | if klass =~ /^#{SINGLETON_MARKER_REGEXP}(.*)/ 39 | return $1 40 | else 41 | return nil 42 | end 43 | end 44 | 45 | def self.add_singleton_marker(klass) 46 | return SINGLETON_MARKER + klass 47 | end 48 | 49 | # Duplicate method... 50 | # Klass should be a string and may have a singleton marker 51 | # def self.pretty_name(klass, meth) 52 | # if klass =~ /^#{SINGLETON_MARKER_REGEXP}(.*)/ 53 | # return "#{$1}.#{meth}" 54 | # else 55 | # return "#{klass}##{meth}" 56 | # end 57 | # end 58 | 59 | def self.method_defined?(klass, method) 60 | begin 61 | sk = self.to_class klass 62 | msym = method.to_sym 63 | rescue NameError 64 | return false 65 | end 66 | 67 | return sk.methods.include?(:new) if method == :new 68 | 69 | sk.public_instance_methods(false).include?(msym) or 70 | sk.protected_instance_methods(false).include?(msym) or 71 | sk.private_instance_methods(false).include?(msym) 72 | end 73 | 74 | # Returns the @__rdl_type field of [+obj+] 75 | def self.rdl_type(obj) 76 | return (obj.instance_variable_defined?('@__rdl_type') && obj.instance_variable_get('@__rdl_type')) 77 | end 78 | 79 | def self.rdl_type_or_class(obj) 80 | return self.rdl_type(obj) || obj.class 81 | end 82 | 83 | def self.pp_klass_method(klass, meth) 84 | klass = klass.to_s 85 | if has_singleton_marker klass 86 | remove_singleton_marker(klass) + "." + meth.to_s 87 | else 88 | klass + "#" + meth.to_s 89 | end 90 | end 91 | end 92 | -------------------------------------------------------------------------------- /lib/types/core/math.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :Math 2 | 3 | RDL.type :Math, 'self.acos', '(%real x) -> Float' 4 | RDL.pre(:Math, 'self.acos') { |x| -1 <= x && x <= 1 } 5 | RDL.post(:Math, 'self.acos') { |r, _| 0 <= r && r <= Math::PI } 6 | RDL.type :Math, 'self.acosh', '(%real x) -> Float' 7 | RDL.pre(:Math, 'self.acosh') { |x| 1 <= x } 8 | RDL.post(:Math, 'self.acosh') { |r, _| 0 <= r } 9 | RDL.type :Math, 'self.asin', '(%real x) -> Float' 10 | RDL.pre(:Math, 'self.asin') { |x| -1 <= x && x <= 1 } 11 | RDL.post(:Math, 'self.asin') { |r, _| -Math::PI/2 <= r && r <= Math::PI/2 } 12 | RDL.type :Math, 'self.asinh', '(%real x) -> Float' 13 | RDL.type :Math, 'self.atan', '(%real x) -> Float' 14 | RDL.post(:Math, 'self.atan') { |r, _| -Math::PI/2 <= r && r <= Math::PI/2 } 15 | RDL.type :Math, 'self.atan2', '(%real y, %real x) -> Float' 16 | RDL.post(:Math, 'self.atan2') { |r, _| -Math::PI <= r && r <= Math::PI } 17 | RDL.type :Math, 'self.atanh', '(%real x) -> Float' 18 | RDL.pre(:Math, 'self.atanh') { |x| -1 < x && x < 1 } 19 | RDL.type :Math, 'self.cbrt', '(%real x) -> Float' 20 | RDL.pre(:Math, 'self.cbrt') { |x| 0 <= x } 21 | RDL.post(:Math, 'self.cbrt') { |x| 0 <= x } 22 | RDL.type :Math, 'self.cos', '(%real x) -> Float' 23 | RDL.post(:Math, 'self.cos') { |r, _| -1 <= r && r <= 1 } 24 | RDL.type :Math, 'self.cosh', '(%real x) -> Float' 25 | RDL.post(:Math, 'self.cosh') { |r, _| 1 <= r } 26 | RDL.type :Math, 'self.erf', '(%real x) -> Float' 27 | RDL.post(:Math, 'self.erf') { |r, _| -1 < r && r < 1 } 28 | RDL.type :Math, 'self.erfc', '(%real x) -> Float' 29 | RDL.post(:Math, 'self.erfc') { |r, _| 0 < r && r < 2 } 30 | RDL.type :Math, 'self.exp', '(%real x) -> Float' 31 | RDL.post(:Math, 'self.exp') { |r, _| 0 < r } 32 | RDL.type :Math, 'self.frexp', '(%real x) -> [%real, %real]' 33 | RDL.type :Math, 'self.gamma', '(%real x) -> Float' 34 | RDL.type :Math, 'self.hypot', '(%real x, %real y) -> Float' 35 | RDL.type :Math, 'self.ldexp', '(%real fraction, %real exponent) -> Float' 36 | RDL.type :Math, 'self.lgamma', '(%real x) -> -1 or 1 or Float' 37 | RDL.type :Math, 'self.log', '(%real x, ?(%real) base) -> Float' 38 | RDL.type :Math, 'self.log10', '(%real x) -> Float' 39 | RDL.pre(:Math, 'self.log10') { |x| 0 < x } 40 | RDL.type :Math, 'self.log2', '(%real x) -> Float' 41 | RDL.pre(:Math, 'self.log2') { |x| 0 < x } 42 | RDL.type :Math, 'self.sin', '(%real x) -> Float' 43 | RDL.post(:Math, 'self.sin') { |r, _| -1 <= r && r <= 1 } 44 | RDL.type :Math, 'self.sinh', '(%real x) -> Float' 45 | RDL.type :Math, 'self.sqrt', '(%real x) -> Float' 46 | RDL.pre(:Math, 'self.sqrt') { |x| 0 <= x } 47 | RDL.post(:Math, 'self.sqrt') { |r, _| 0 <= r } 48 | RDL.type :Math, 'self.tan', '(%real x) -> Float' 49 | RDL.type :Math, 'self.tanh', '(%real x) -> Float' 50 | RDL.post(:Math, 'self.tanh') { |r, _| -1 < r && r < 1 } 51 | -------------------------------------------------------------------------------- /lib/types/core/set.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :Set 2 | 3 | RDL.type_params :Set, [:t], :all? 4 | 5 | RDL.type :Set, 'self.[]', '(*u) -> Set' 6 | RDL.type :Set, :initialize, '(?Enumerable enum) -> self' 7 | 8 | RDL.rdl_alias :Set, :&, :intersection 9 | RDL.type :Set, :+, '(Enumerable enum) -> Set' 10 | RDL.rdl_alias :Set, :-, :difference 11 | RDL.rdl_alias :Set, :<, :proper_subset? 12 | RDL.rdl_alias :Set, :<<, :add 13 | RDL.rdl_alias :Set, :<=, :subset? 14 | RDL.rdl_alias :Set, :>, :proper_superset? 15 | RDL.rdl_alias :Set, :>=, :superset? 16 | RDL.type :Set, :^, '(Enumerable enum) -> Set' 17 | RDL.type :Set, :add, '(t o) -> self' 18 | RDL.type :Set, :add?, '(t o) -> self or nil' 19 | RDL.type :Set, :classify, '() { (u) -> t } -> Hash>' 20 | RDL.type :Set, :clear, '() -> self' 21 | RDL.rdl_alias :Set, :collect!, :map 22 | RDL.type :Set, :delete, '(t o) -> self' 23 | RDL.type :Set, :delete?, '(t o) -> self or nil' 24 | RDL.type :Set, :delete_if, '() { (t) -> %bool } -> self' 25 | RDL.type :Set, :difference, '(Enumerable enum) -> Set' 26 | RDL.type :Set, :disjoint?, '(Set set) -> %bool' 27 | #??RDL.type :Set, :divide, '() { BLOCK }' 28 | RDL.type :Set, :each, '() { (t) -> %any } -> self' 29 | RDL.type :Set, :each, '() -> Enumerator' 30 | RDL.type :Set, :empty?, '() -> %bool' 31 | RDL.type :Set, :flatten!, '() -> self or nil' 32 | RDL.post(:Set, :flatten!) { |r| (not r) || (r.none? { |x| x.is_a?(Set) }) } 33 | RDL.type :Set, :flatten, '() -> Set' 34 | RDL.post(:Set, :flatten) { |r| r.none? { |x| x.is_a?(Set) } } 35 | # RDL.type :Set, :flatten_merge, '(set : XXXX, seen : ?XXXX)' #?? 36 | RDL.rdl_alias :Set, :include?, :member? 37 | RDL.type :Set, :intersect?, '(Set set) -> %bool' 38 | RDL.type :Set, :intersection, '(Enumerable enum) -> Set' 39 | RDL.type :Set, :keep_if, '() { (t) -> %bool } -> self' 40 | RDL.rdl_alias :Set, :length, :size 41 | RDL.type :Set, :map!, '() { (t) -> u } -> Set' # !! Fix, actually changes RDL.type! 42 | RDL.type :Set, :member?, '(t o) -> %bool' 43 | RDL.type :Set, :merge, '(Enumerable enum) -> self' 44 | RDL.type :Set, :proper_subset?, '(Set set) -> %bool' 45 | RDL.type :Set, :proper_superset?, '(Set set) -> %bool' 46 | RDL.type :Set, :reject!, '() { (t) -> %bool } -> self or nil' 47 | RDL.type :Set, :replace, '(Enumerable enum) -> Set' # !! Fix, actually changes RDL.type! 48 | RDL.type :Set, :select!, '() { (t) -> %bool } -> self or nil' 49 | RDL.type :Set, :size, '() -> Integer' 50 | RDL.type :Set, :subset?, '(Set set) -> %bool' 51 | RDL.type :Set, :subtract, '(Enumerable enum) -> self' 52 | RDL.type :Set, :superset?, '(Set set) -> %bool' 53 | RDL.type :Set, :to_a, '() -> Array' 54 | #RDL.type :Set, :to_set, '(klass: ?Class, args : *XXXX) { BLOCK }' # ?? 55 | RDL.rdl_alias :Set, :|, :+ 56 | RDL.rdl_alias :Set, :union, :+ 57 | -------------------------------------------------------------------------------- /lib/types/core/numeric.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :Numeric 2 | 3 | RDL.type :Numeric, :%, '(%numeric) -> %numeric' 4 | RDL.pre(:Numeric, :%) { |x| x!=0} 5 | RDL.type :Numeric, :+, '(%numeric) -> %numeric' 6 | RDL.type :Numeric, :-, '() -> %numeric' 7 | RDL.type :Numeric, :-@, '() -> %numeric' 8 | RDL.type :Numeric, :+@, '() -> %numeric' 9 | RDL.type :Numeric, :<=>, '(%numeric) -> Object' 10 | RDL.post(:Numeric, :<=>) { |r,x| r == -1 || r==0 || r==1 || r==nil} 11 | RDL.type :Numeric, :abs, '() -> %numeric' 12 | RDL.post(:Numeric, :abs) { |r,x| r >= 0 } 13 | RDL.type :Numeric, :abs2, '() -> %numeric' 14 | RDL.post(:Numeric, :abs2) { |r,x| r >= 0 } 15 | RDL.type :Numeric, :angle, '() -> %numeric' 16 | RDL.type :Numeric, :arg, '() -> %numeric' 17 | RDL.type :Numeric, :ceil, '() -> Integer' 18 | RDL.type :Numeric, :coerce, '(%numeric) -> [%numeric, %numeric]' 19 | RDL.type :Numeric, :conj, '() -> %numeric' 20 | RDL.type :Numeric, :conjugate, '() -> %numeric' 21 | RDL.type :Numeric, :denominator, '() -> Integer' 22 | RDL.post(:Numeric, :denominator) { |r,x| r >= 0 } 23 | RDL.type :Numeric, :div, '(%numeric) -> Integer' 24 | RDL.pre(:Numeric, :div) { |x| x!=0} 25 | RDL.type :Numeric, :divmod, '(%numeric) -> [%numeric, %numeric]' 26 | RDL.pre(:Numeric, :divmod) { |x| x!=0 } 27 | RDL.type :Numeric, :eql?, '(%numeric) -> %bool' 28 | RDL.type :Numeric, :fdiv, '(%numeric) -> %numeric' 29 | RDL.type :Numeric, :floor, '() -> Integer' 30 | RDL.type :Numeric, :i, '() -> Complex' 31 | RDL.type :Numeric, :imag, '() -> %numeric' 32 | RDL.type :Numeric, :imaginary, '() -> %numeric' 33 | RDL.type :Numeric, :integer?, '() -> %bool' 34 | RDL.type :Numeric, :magnitude, '() -> %numeric' 35 | RDL.type :Numeric, :modulo, '(%numeric) -> %real' 36 | RDL.pre(:Numeric, :modulo) { |x| x!=0 } 37 | RDL.type :Numeric, :nonzero?, '() -> self or nil' 38 | RDL.type :Numeric, :numerator, '() -> Integer' 39 | RDL.type :Numeric, :phase, '() -> %numeric' 40 | RDL.type :Numeric, :polar, '() -> [%numeric, %numeric]' 41 | RDL.type :Numeric, :quo, '(%numeric) -> %numeric' 42 | RDL.type :Numeric, :real, '() -> %numeric' 43 | RDL.type :Numeric, :real?, '() -> %numeric' 44 | RDL.type :Numeric, :rect, '() -> [%numeric, %numeric]' 45 | RDL.type :Numeric, :rectangular, '() -> [%numeric, %numeric]' 46 | RDL.type :Numeric, :remainder, '(%numeric) -> %real' 47 | RDL.type :Numeric, :round, '(%numeric) -> %numeric' 48 | RDL.type :Numeric, :singleton_method_added, '(Symbol) -> TypeError' 49 | RDL.type :Numeric, :step, '(%numeric) { (%numeric) -> %any } -> %numeric' 50 | RDL.type :Numeric, :step, '(%numeric) -> Enumerator<%numeric>' 51 | RDL.type :Numeric, :step, '(%numeric, %numeric) { (%numeric) -> %any } -> %numeric' 52 | RDL.type :Numeric, :step, '(%numeric, %numeric) -> Enumerator<%numeric>' 53 | RDL.type :Numeric, :to_c, '() -> Complex' 54 | RDL.type :Numeric, :to_int, '() -> Integer' 55 | RDL.type :Numeric, :truncate, '() -> Integer' 56 | RDL.type :Numeric, :zero?, '() -> %bool' 57 | -------------------------------------------------------------------------------- /lib/rdl/info.rb: -------------------------------------------------------------------------------- 1 | class RDL::Info 2 | # map from klass (String) to label (Symbol) to kind (Symbol) to either array or some other value 3 | # 4 | # class names are strings because they need to be manipulated in case they include :: 5 | # (class names may have Util.add_singleton_marker applied to them to indicate they're singleton classes.) 6 | 7 | attr_accessor :info 8 | 9 | def initialize 10 | @info = Hash.new 11 | end 12 | 13 | # [+kind+] must map to an array 14 | def add(klass, label, kind, val) 15 | klass = klass.to_s 16 | label = label.to_sym 17 | @info[klass] = {} unless @info[klass] 18 | @info[klass][label] = {} unless @info[klass][label] 19 | @info[klass][label][kind] = [] unless @info[klass][label][kind] 20 | @info[klass][label][kind] << val 21 | end 22 | 23 | # if no prev info for kind, set to val and return true 24 | # if prev info for kind, return true if prev == val and false otherwise 25 | def set(klass, label, kind, val) 26 | klass = RDL::Util.to_class_str(klass) 27 | label = label.to_sym 28 | @info[klass] = {} unless @info[klass] 29 | @info[klass][label] = {} unless @info[klass][label] 30 | if @info[klass][label].has_key? kind 31 | return (val == @info[klass][label][kind]) 32 | else 33 | @info[klass][label][kind] = val 34 | return true 35 | end 36 | end 37 | 38 | # replace info for kind 39 | def set!(klass, label, kind, val) 40 | klass = klass.to_s 41 | label = label.to_sym 42 | @info[klass] = {} unless @info[klass] 43 | @info[klass][label] = {} unless @info[klass][label] 44 | @info[klass][label][kind] = val 45 | end 46 | 47 | def has?(klass, label, kind) 48 | klass = klass.to_s 49 | label = label.to_sym 50 | return (@info.has_key? klass) && 51 | (@info[klass].has_key? label) && 52 | (@info[klass][label].has_key? kind) 53 | end 54 | 55 | def has_any?(klass, label, kinds) 56 | klass = klass.to_s 57 | label = label.to_sym 58 | return (@info.has_key? klass) && 59 | (@info[klass].has_key? label) && 60 | (kinds.any? { |k| @info[klass][label].has_key? k }) 61 | end 62 | 63 | # eventually replace with Hash#dig 64 | def get(klass, label, kind) 65 | klass = klass.to_s 66 | label = label.to_sym 67 | t1 = @info[klass] 68 | return t1 if t1.nil? 69 | t2 = t1[label] 70 | return t2 if t2.nil? 71 | return t2[kind] 72 | # return @info[klass][label][kind] 73 | end 74 | 75 | def get_with_aliases(klass, label, kind) 76 | while RDL::Globals.aliases[klass] && RDL::Globals.aliases[klass][label] 77 | label = RDL::Globals.aliases[klass][label] 78 | end 79 | get(klass, label, kind) 80 | end 81 | 82 | def remove(klass, label, kind) 83 | klass = klass.to_s 84 | label = label.to_sym 85 | return unless @info.has_key? klass 86 | return unless @info[klass].has_key? label 87 | @info[klass][label].delete kind 88 | end 89 | 90 | end 91 | -------------------------------------------------------------------------------- /lib/rdl/types/tuple.rb: -------------------------------------------------------------------------------- 1 | module RDL::Type 2 | # A specialized GenericType for tuples, i.e., fixed-sized arrays 3 | class TupleType < Type 4 | attr_reader :params 5 | attr_reader :array # either nil or array type if self has been promoted to array 6 | attr_accessor :ubounds # upper bounds this tuple has been compared with using <= 7 | attr_accessor :lbounds # lower bounds... 8 | 9 | # no caching because array might be mutated 10 | def initialize(*params) 11 | raise RuntimeError, "Attempt to create tuple type with non-type param" unless params.all? { |p| p.is_a? Type } 12 | @params = params 13 | @array = nil # emphasize initially this is a tuple, not an array 14 | @cant_promote = false 15 | @ubounds = [] 16 | @lbounds = [] 17 | super() 18 | end 19 | 20 | def canonical 21 | return @array if @array 22 | return self 23 | end 24 | 25 | def to_s 26 | return @array.to_s if @array 27 | return "[#{@params.map { |t| t.to_s }.join(', ')}]" 28 | end 29 | 30 | def ==(other) # :nodoc: 31 | return false if other.nil? 32 | return (@array == other) if @array 33 | other = other.canonical 34 | return (other.instance_of? TupleType) && (other.params == @params) 35 | end 36 | 37 | alias eql? == 38 | 39 | def match(other) 40 | return @array.match(other) if @array 41 | other = other.canonical 42 | other = other.type if other.instance_of? AnnotatedArgType 43 | return true if other.instance_of? WildQuery 44 | return (other.instance_of? TupleType) && (@params.length == other.params.length) && (@params.zip(other.params).all? { |t,o| t.match(o) }) 45 | end 46 | 47 | def promote! 48 | return false if @cant_promote 49 | @array = GenericType.new(RDL::Globals.types[:array], UnionType.new(*@params)) 50 | # note since we promoted this, lbounds and ubounds will be ignored in future constraints, which 51 | # is good because otherwise we'd get infinite loops 52 | return (@lbounds.all? { |lbound| lbound <= self }) && (@ubounds.all? { |ubound| self <= ubound }) 53 | end 54 | 55 | def cant_promote! 56 | raise RuntimeError, "already promoted!" if @array 57 | @cant_promote = true 58 | end 59 | 60 | def <=(other) 61 | return Type.leq(self, other) 62 | end 63 | 64 | def member?(obj, *args) 65 | return @array.member?(obj, *args) if @array 66 | t = RDL::Util.rdl_type obj 67 | return t <= self if t 68 | return false unless obj.instance_of?(Array) && obj.size == @params.size 69 | return @params.zip(obj).all? { |formal, actual| formal.member?(actual, *args) } 70 | end 71 | 72 | def instantiate(inst) 73 | return @array.instantiate(inst) if @array 74 | return TupleType.new(*@params.map { |t| t.instantiate(inst) }) 75 | end 76 | 77 | def hash 78 | # note don't change hash value if @array becomes non-nil 79 | 73 * @params.hash 80 | end 81 | 82 | end 83 | end 84 | -------------------------------------------------------------------------------- /test/test_rdl_type.rb: -------------------------------------------------------------------------------- 1 | require 'minitest/autorun' 2 | $LOAD_PATH << File.dirname(__FILE__) + "/../lib" 3 | require 'rdl' 4 | 5 | class TestRDLType < Minitest::Test 6 | extend RDL::Annotate 7 | 8 | def test_single_type_contract 9 | def m1(x) return x; end 10 | RDL.type TestRDLType, :m1, "(Integer) -> Integer" 11 | assert_equal 5, m1(5) 12 | assert_raises(RDL::Type::TypeError) { m1("foo") } 13 | 14 | self.class.class_eval { 15 | type :m2, "(Integer) -> Integer" 16 | def m2(x) return x; end 17 | } 18 | assert_equal 5, m2(5) 19 | assert_raises(RDL::Type::TypeError) { m2("foo") } 20 | 21 | self.class.class_eval { 22 | type "(Integer) -> Integer" 23 | def m3(x) return x; end 24 | } 25 | assert_equal 5, m3(5) 26 | assert_raises(RDL::Type::TypeError) { m3("foo") } 27 | end 28 | 29 | def test_intersection_type_contract 30 | self.class.class_eval { 31 | type "(Integer) -> Integer" 32 | type "(String) -> String" 33 | def m4(x) return x; end 34 | } 35 | assert_equal 5, m4(5) 36 | assert_equal "foo", m4("foo") 37 | assert_raises(RDL::Type::TypeError) { m4(:foo) } 38 | 39 | self.class.class_eval { 40 | type "(Integer) -> Integer" 41 | type "(String) -> String" 42 | def m5(x) return 42; end 43 | } 44 | assert_equal 42, m5(3) 45 | assert_raises(RDL::Type::TypeError) { m5("foo") } 46 | 47 | self.class.class_eval { 48 | type "(Integer) -> Integer" 49 | type "(Integer) -> String" 50 | def m6(x) if x > 10 then :oops elsif x > 5 then x else "small" end end 51 | } 52 | assert_equal 8, m6(8) 53 | assert_equal "small", m6(1) 54 | assert_raises(RDL::Type::TypeError) { m6(42) } 55 | end 56 | 57 | def test_fixnum_type_contract 58 | self.class.class_eval { 59 | type "(0) -> Integer" 60 | def m7(x) return x; end 61 | } 62 | assert_equal 0, m7(0) 63 | assert_raises(RDL::Type::TypeError) { m7(1) } 64 | end 65 | 66 | def test_wrap_new_inherited 67 | self.class.class_eval "class NI_A; def initialize(x); @x = x; end; end; class NI_B < NI_A; end" 68 | RDL.type "TestRDLType::NI_A", "self.new", "(Integer) -> TestRDLType::NI_A" 69 | assert (TestRDLType::NI_B.new(3)) 70 | assert_raises(RDL::Type::TypeError) { TestRDLType::NI_B.new("3") } 71 | end 72 | 73 | def test_version 74 | RDL.type "TestRDLType::TestVersion", "m1", "() -> nil", version: Gem.ruby_version.to_s 75 | assert (RDL::Globals.info.has? "TestRDLType::TestVersion", "m1", :type) 76 | RDL.type "TestRDLType::TestVersion", "m2", "() -> nil", version: Gem.ruby_version.bump.to_s 77 | assert !(RDL::Globals.info.has? "TestRDLType::TestVersion", "m2", :type) 78 | end 79 | 80 | def test_wrap_subclass_method 81 | self.class.class_eval "class NI_C; def foo; :A; end; end" 82 | self.class.class_eval "class NI_D < NI_C; def foo; :B; end; end" 83 | RDL.type 'TestRDLType::NI_C', :foo, '() -> :A' 84 | RDL.type 'TestRDLType::NI_D', :foo, '() -> :A' 85 | assert TestRDLType::NI_C.new.foo 86 | assert_raises(RDL::Type::TypeError) { TestRDLType::NI_D.new.foo} 87 | end 88 | end 89 | -------------------------------------------------------------------------------- /test/disabled_test_rdoc.rb: -------------------------------------------------------------------------------- 1 | require 'minitest/autorun' 2 | require 'rdoc' 3 | require 'erb' 4 | require 'fileutils' 5 | require 'pathname' 6 | require 'pp' 7 | require 'tempfile' 8 | require 'tmpdir' 9 | 10 | require 'rdoc' 11 | require_relative '../lib/rdl.rb' 12 | 13 | class RdocTest < MiniTest::Test 14 | 15 | class TestClass 16 | extend RDL 17 | 18 | typesig :size, "()->Integer" 19 | typesig :bytesize, "()->Integer" 20 | end 21 | 22 | def test_rdoc_gen 23 | skip "TEST WITH NO ASSERTIONS" 24 | rdocTypesigFor(TestClass) 25 | end 26 | end 27 | 28 | class TestRDLRDoc 29 | =begin 30 | @have_encoding = Object.const_defined? :Encoding 31 | @RM = RDoc::Markup 32 | RDoc::Markup::PreProcess.reset 33 | @pwd = Dir.pwd 34 | @store = RDoc::Store.new 35 | @rdoc = RDoc::RDoc.new 36 | @rdoc.store = @store 37 | @rdoc.options = RDoc::Options.new 38 | 39 | g = Object.new 40 | def g.class_dir() end 41 | def g.file_dir() end 42 | @rdoc.generator = g 43 | 44 | @lib_dir = "#{@pwd}/lib" 45 | $LOAD_PATH.unshift @lib_dir # ensure we load from this RDoc 46 | 47 | @options = RDoc::Options.new 48 | @options.option_parser = OptionParser.new 49 | 50 | p Dir.tmpdir 51 | @tmpdir = File.join Dir.tmpdir, "test_rdoc_generator_darkfish_#{$$}" 52 | FileUtils.mkdir_p @tmpdir 53 | Dir.chdir @tmpdir 54 | @options.op_dir = @tmpdir 55 | @options.generator = RDoc::Generator::Darkfish 56 | 57 | $LOAD_PATH.each do |path| 58 | darkfish_dir = File.join path, 'rdoc/generator/template/darkfish/' 59 | next unless File.directory? darkfish_dir 60 | @options.template_dir = darkfish_dir 61 | break 62 | end 63 | 64 | @rdoc.options = @options 65 | 66 | @g = @options.generator.new @store, @options 67 | @rdoc.generator = @g 68 | 69 | @top_level = @store.add_file 'file.rb' 70 | @top_level.parser = RDoc::Parser::Ruby 71 | klass = @top_level.add_class RDoc::NormalClass, 'RDL_TEST_Klass(String)' 72 | 73 | alis_constant = RDoc::Constant.new 'ABC', nil, '' 74 | alis_constant.record_location @top_level 75 | 76 | @top_level.add_constant alis_constant 77 | 78 | klass.add_module_alias klass, 'AAA', @top_level 79 | 80 | meth = RDoc::AnyMethod.new nil, 'Size' 81 | tmthd = String.instance_variable_get(:@__typesigs)[:size] 82 | msig = "()->#{tmthd.ret}" 83 | eval " 84 | def meth.param_seq 85 | return \"%s\" 86 | end 87 | def meth.comment 88 | true 89 | end 90 | def meth.description 91 | return \"%s\" 92 | end 93 | " % [msig,"Takes input {Params} and outputs {Return}"] 94 | 95 | meth_bang = RDoc::AnyMethod.new nil, 'method!' 96 | attr = RDoc::Attr.new nil, 'attr', 'RW', '' 97 | 98 | klass.add_method meth 99 | klass.add_method meth_bang 100 | klass.add_attribute attr 101 | 102 | ignored = @top_level.add_class RDoc::NormalClass, 'Ignored' 103 | ignored.ignore 104 | 105 | #@store.complete :private 106 | 107 | @object = @store.find_class_or_module 'Object' 108 | klass_alias = @store.find_class_or_module 'Klass::A' 109 | 110 | top_level = @store.add_file 'file.rb' 111 | top_level.add_class klass.class, klass.name 112 | 113 | @g.generate 114 | p File.file?('index.html') 115 | =end 116 | end 117 | -------------------------------------------------------------------------------- /lib/types/core/time.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :Time 2 | 3 | RDL.type :Time, 'self.at', '(Time) -> Time' 4 | RDL.type :Time, 'self.at', '(Numeric seconds_with_frac) -> Time' 5 | RDL.type :Time, 'self.at', '(Numeric seconds, Numeric microseconds_with_frac) -> Time' 6 | RDL.type :Time, 'self.gm', '(Integer year, ?(Integer or String) month, ?Integer day, ?Integer hour, ?Integer min, ?Numeric sec, ?Numeric usec_with_frac) -> Time' 7 | RDL.type :Time, 'self.local', '(Integer year, ?(Integer or String) month, ?Integer day, ?Integer hour, ?Integer min, ?Numeric sec, ?Numeric usec_with_frac) -> Time' 8 | RDL.rdl_alias :Time, 'self.mktime', 'self.local' 9 | RDL.type :Time, :initialize, '(?Integer year, ?(Integer or String) month, ?Integer day, ?Integer hour, ?Integer min, ?Numeric sec, ?Numeric usec_with_frac) -> self' 10 | RDL.type :Time, 'self.now', '() -> Time' 11 | RDL.type :Time, 'self.utc', '(Integer year, ?(Integer or String) month, ?Integer day, ?Integer hour, ?Integer min, ?Numeric sec, ?Numeric usec_with_frac) -> Time' 12 | 13 | RDL.type :Time, :+, '(Numeric) -> Time' 14 | RDL.type :Time, :-, '(Time) -> Float' 15 | RDL.type :Time, :-, '(Numeric) -> Time' 16 | RDL.type :Time, :<=>, '(Time other) -> -1 or 0 or 1 or nil' 17 | RDL.type :Time, :asctime, '() -> String' 18 | RDL.type :Time, :ctime, '() -> String' 19 | RDL.type :Time, :day, '() -> Integer' 20 | RDL.type :Time, :dst?, '() -> %bool' 21 | RDL.type :Time, :eql?, '(%any) -> %bool' 22 | RDL.type :Time, :friday?, '() -> %bool' 23 | RDL.type :Time, :getgm, '() -> Time' 24 | RDL.type :Time, :getlocal, '(?Integer utc_offset) -> Time' 25 | RDL.type :Time, :getutc, '() -> Time' 26 | RDL.type :Time, :gmt?, '() -> %bool' 27 | RDL.type :Time, :gmt_offset, '() -> Integer' 28 | RDL.type :Time, :gmtime, '() -> self' 29 | RDL.rdl_alias :Time, :gmtoff, :gmt_offset 30 | RDL.type :Time, :hash, '() -> Integer' 31 | RDL.type :Time, :hour, '() -> Integer' 32 | RDL.type :Time, :inspect, '() -> String' 33 | RDL.type :Time, :isdst, '() -> %bool' 34 | RDL.type :Time, :localtime, '(?String utc_offset) -> self' 35 | RDL.type :Time, :mday, '() -> Integer' 36 | RDL.type :Time, :min, '() -> Integer' 37 | RDL.type :Time, :mon, '() -> Integer' 38 | RDL.type :Time, :monday?, '() -> %bool' 39 | RDL.rdl_alias :Time, :month, :mon 40 | RDL.type :Time, :nsec, '() -> Integer' 41 | RDL.type :Time, :round, '(Integer) -> Time' 42 | RDL.type :Time, :saturday, '() -> %bool' 43 | RDL.type :Time, :sec, '() -> Integer' 44 | RDL.type :Time, :strftime, '(String) -> String' 45 | RDL.type :Time, :subsec, '() -> Numeric' 46 | RDL.type :Time, :succ, '() -> Time' 47 | RDL.type :Time, :sunday?, '() -> %bool' 48 | RDL.type :Time, :thursday?, '() -> %bool' 49 | RDL.type :Time, :to_a, '() -> [Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer, %bool, String]' 50 | RDL.type :Time, :to_f, '() -> Float' 51 | RDL.type :Time, :to_i, '() -> Numeric' 52 | RDL.type :Time, :to_r, '() -> Rational' 53 | RDL.type :Time, :to_s, '() -> String' 54 | RDL.type :Time, :tuesday?, '() -> %bool' 55 | RDL.type :Time, :tv_nsec, '() -> Numeric' 56 | RDL.type :Time, :tv_sec, '() -> Numeric' 57 | RDL.type :Time, :tv_usec, '() -> Numeric' 58 | RDL.type :Time, :usec, '() -> Numeric' 59 | RDL.type :Time, :utc, '() -> self' 60 | RDL.type :Time, :utc?, '() -> %bool' 61 | RDL.type :Time, :utc_offset, '() -> Integer' 62 | RDL.type :Time, :wday, '() -> Integer' 63 | RDL.type :Time, :wednesday?, '() -> %bool' 64 | RDL.type :Time, :yday, '() -> Integer' 65 | RDL.type :Time, :year, '() -> Integer' 66 | RDL.type :Time, :zone, '() -> String' 67 | -------------------------------------------------------------------------------- /lib/types/core/hash.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :Hash 2 | 3 | RDL.type_params :Hash, [:k, :v], :all? 4 | 5 | RDL.type :Hash, 'self.[]', '(*u) -> Hash' # example: Hash[1,2,3,4] 6 | RDL.type :Hash, 'self.[]', '(Array<[a,b]>) -> Hash' 7 | RDL.type :Hash, 'self.[]', '([to_hash: () -> Hash]) -> Hash' 8 | 9 | RDL.type :Hash, :[], '(k) -> v' 10 | RDL.type :Hash, :[]=, '(k, v) -> v' 11 | RDL.type :Hash, :store, '(k,v) -> v' 12 | 13 | # RDL.type :Hash, :assoc, '(k) -> [k, v]' # TODO 14 | RDL.type :Hash, :assoc, '(k) -> Array' 15 | RDL.type :Hash, :clear, '() -> Hash' 16 | RDL.type :Hash, :compare_by_identity, '() -> Hash' 17 | RDL.type :Hash, :compare_by_identity?, '() -> %bool' 18 | RDL.type :Hash, :default, '(?k) -> v' 19 | RDL.type :Hash, :default, '(k) {(k) -> v} -> v' 20 | RDL.type :Hash, :default=, '(v) -> v' 21 | 22 | # TODO: check on default_proc 23 | # RDL.type :Hash, :default_proc, '() -> (Hash,k) -> v' 24 | # RDL.type :Hash, :default_proc=, '((Hash,k) -> v) -> (Hash,k) -> v' 25 | 26 | RDL.type :Hash, :delete, '(k) -> v' 27 | RDL.type :Hash, :delete, '(k) { (k) -> u } -> u or v' 28 | RDL.type :Hash, :delete_if, '() { (k,v) -> %bool } -> Hash' 29 | RDL.type :Hash, :delete_if, '() -> Enumerator<[k, v]>' 30 | RDL.type :Hash, :each, '() { (k,v) -> %any } -> Hash' 31 | RDL.type :Hash, :each, '() -> Enumerator<[k, v]>' 32 | RDL.type :Hash, :each_pair, '() { (k,v) -> %any } -> Hash' 33 | RDL.type :Hash, :each_pair, '() -> Enumerator<[k, v]>' 34 | RDL.type :Hash, :each_key, '() { (k) -> %any } -> Hash' 35 | RDL.type :Hash, :each_key, '() -> Enumerator<[k, v]>' 36 | RDL.type :Hash, :each_value, '() { (v) -> %any } -> Hash' 37 | RDL.type :Hash, :each_value, '() -> Enumerator<[k, v]>' 38 | RDL.type :Hash, :empty?, '() -> %bool' 39 | RDL.type :Hash, :fetch, '(k) -> v' 40 | RDL.type :Hash, :fetch, '(k,u) -> u or v' 41 | RDL.type :Hash, :fetch, '(k) { (k) -> u } -> u or v' 42 | RDL.type :Hash, :member?, '(t) -> %bool' 43 | RDL.type :Hash, :has_key?, '(t) -> %bool' 44 | RDL.type :Hash, :key?, '(t) -> %bool' 45 | RDL.type :Hash, :has_value?, '(t) -> %bool' 46 | RDL.type :Hash, :value?, '(t) -> %bool' 47 | RDL.type :Hash, :to_s, '() -> String' 48 | RDL.type :Hash, :inspect, '() -> String' 49 | RDL.type :Hash, :invert, '() -> Hash' 50 | RDL.type :Hash, :keep_if, '() { (k,v) -> %bool } -> Hash' 51 | RDL.type :Hash, :keep_if, '() -> Enumerator<[k, v]>' 52 | RDL.type :Hash, :key, '(t) -> k' 53 | RDL.type :Hash, :keys, '() -> Array' 54 | RDL.type :Hash, :length, '() -> Integer' 55 | RDL.type :Hash, :size, '() -> Integer' 56 | RDL.type :Hash, :merge, '(Hash) -> Hash' 57 | RDL.type :Hash, :merge, '(Hash) { (k,v,b) -> v or b } -> Hash' 58 | # RDL.type :Hash, :rassoc, '(k) -> Tuple' 59 | RDL.type :Hash, :rassoc, '(k) -> Array' 60 | RDL.type :Hash, :rehash, '() -> Hash' 61 | RDL.type :Hash, :reject, '() -> Enumerator<[k, v]>' 62 | RDL.type :Hash, :reject, '() {(k,v) -> %bool} -> Hash' 63 | RDL.type :Hash, :reject!, '() {(k,v) -> %bool} -> Hash' 64 | RDL.type :Hash, :select, '() {(k,v) -> %bool} -> Hash' 65 | RDL.type :Hash, :select!, '() {(k,v) -> %bool} -> Hash' 66 | # RDL.type :Hash, :shift, '() -> Tuple' 67 | RDL.type :Hash, :shift, '() -> Array' 68 | # RDL.type :Hash, :to_a, '() -> Array>' 69 | RDL.type :Hash, :to_a, '() -> Array>' 70 | RDL.type :Hash, :to_hash, '() -> Hash' 71 | RDL.type :Hash, :values, '() -> Array' 72 | RDL.type :Hash, :values_at, '(*k) -> Array' 73 | -------------------------------------------------------------------------------- /lib/rdl/query.rb: -------------------------------------------------------------------------------- 1 | class RDL::Query 2 | 3 | # Return a pair [name, array of the types] for the method specified by q. Valid queries are: 4 | # Class#method - instance method 5 | # Class.method - class method 6 | # method - method of self's class 7 | def self.method_query(q) 8 | klass = nil 9 | meth = nil 10 | if q =~ /(.+)#(.+)/ then 11 | klass = $1 12 | meth = $2.to_sym 13 | elsif q =~ /(.+)\.(.+)/ then 14 | klass = RDL::Util.add_singleton_marker($1) 15 | meth = $2.to_sym 16 | # else 17 | # klass = self.class.to_s 18 | # meth = q.to_sym 19 | end 20 | return RDL::Globals.info.get(klass, meth, :type) 21 | end 22 | 23 | # Return an ordered list of all method types of a class. The query should be a class name. 24 | def self.class_query(q) 25 | klass = q.to_s 26 | return nil unless RDL::Globals.info.info.has_key? klass 27 | cls_meths = [] 28 | cls_klass = RDL::Util.add_singleton_marker(klass) 29 | if RDL::Globals.info.info.has_key? cls_klass then 30 | RDL::Globals.info.info[cls_klass].each { |meth, kinds| 31 | if kinds.has_key? :type then 32 | kinds[:type].each { |t| cls_meths << [meth.to_s, t] } 33 | end 34 | } 35 | end 36 | inst_meths = [] 37 | if RDL::Globals.info.info.has_key? klass then 38 | RDL::Globals.info.info[klass].each { |meth, kinds| 39 | if kinds.has_key? :type then 40 | kinds[:type].each { |t| inst_meths << [meth.to_s, t] } 41 | end 42 | } 43 | end 44 | cls_meths.sort! { |p1, p2| p1[0] <=> p2[0] } 45 | cls_meths.each { |m, t| m.insert(0, "self.") } 46 | inst_meths.sort! { |p1, p2| p1[0] <=> p2[0] } 47 | return cls_meths + inst_meths 48 | end 49 | 50 | # Returns sorted list of pairs [method name, type] matching query. The query should be a string containing a method type query. 51 | def self.method_type_query(q) 52 | q = RDL::Globals.parser.scan_str "#Q #{q}" 53 | result = [] 54 | RDL::Globals.info.info.each { |klass, meths| 55 | meths.each { |meth, kinds| 56 | if kinds.has_key? :type then 57 | kinds[:type].each { |t| 58 | if q.match(t) 59 | result << [RDL::Util.pp_klass_method(klass, meth), t] 60 | end 61 | } 62 | end 63 | } 64 | } 65 | result.sort! { |p1, p2| p1[0] <=> p2[0] } 66 | return result 67 | end 68 | end 69 | 70 | module RDL 71 | 72 | def self.query(q) 73 | RDL::Globals.contract_switch.off { 74 | if q =~ /^[A-Z]\w*(#|\.)([a-z_]\w*(!|\?|=)?|!|~|\+|\*\*|-|\*|\/|%|<<|>>|&|\||\^|<|<=|=>|>|==|===|!=|=~|!~|<=>|\[\]|\[\]=)$/ 75 | typs = RDL::Query.method_query(q) 76 | if typs.nil? then 77 | puts "No types for #{q}" 78 | else 79 | typs.each { |t| 80 | puts "#{q}: #{t}" 81 | } 82 | end 83 | elsif q =~ /^[A-Z]\w*$/ 84 | typs = RDL::Query.class_query(q) 85 | if typs.nil? then 86 | puts "No method types for #{q}" 87 | else 88 | typs.each { |m, t| puts "#{m}: #{t}"} 89 | end 90 | elsif q =~ /\(.*\)/ 91 | typs = RDL::Query.method_type_query(q) 92 | if typs.empty? then 93 | puts "No matching methods" 94 | else 95 | typs.each { |m, t| puts "#{m}: #{t}" } 96 | end 97 | else 98 | raise "Don't know how to handle query" 99 | end 100 | nil 101 | } 102 | end 103 | 104 | end 105 | -------------------------------------------------------------------------------- /lib/rdl/types/union.rb: -------------------------------------------------------------------------------- 1 | module RDL::Type 2 | class UnionType < Type 3 | attr_reader :types 4 | 5 | class << self 6 | alias :__new__ :new 7 | end 8 | 9 | def self.new(*types) 10 | return RDL::Globals.types[:bot] if types.size == 0 11 | ts = [] 12 | # flatten nested unions, check that all args are types 13 | types.each { |t| 14 | if t.instance_of? UnionType 15 | ts.concat t.types 16 | else 17 | raise RuntimeError, "Attempt to create union type with non-type" unless t.is_a? Type 18 | raise RuntimeError, "Attempt to create union with optional type" if t.is_a? OptionalType 19 | raise RuntimeError, "Attempt to create union with vararg type" if t.is_a? VarargType 20 | raise RuntimeError, "Attempt to create union with annotated type" if t.is_a? AnnotatedArgType 21 | ts << t 22 | end 23 | } 24 | return ts[0] if ts.size == 1 25 | return UnionType.__new__(ts) 26 | end 27 | 28 | def initialize(types) 29 | @types = types 30 | @canonical = false 31 | @canonicalized = false 32 | @hash = 41 + @types.hash # don't rehash if @types changes 33 | super() 34 | end 35 | 36 | def canonical 37 | canonicalize! 38 | return @canonical if @canonical 39 | return self 40 | end 41 | 42 | def canonicalize! 43 | return if @canonicalized 44 | # for any type such that a supertype is already in ts, set its position to nil 45 | for i in 0..(@types.length-1) 46 | for j in (i+1)..(@types.length-1) 47 | next if (@types[j].nil?) || (@types[i].nil?) 48 | (@types[i] = nil; break) if @types[i] <= @types[j] 49 | (@types[j] = nil) if @types[j] <= @types[i] 50 | end 51 | end 52 | @types.delete(nil) # eliminate any "deleted" elements 53 | @types.sort! { |a, b| a.object_id <=> b.object_id } # canonicalize order 54 | @types.uniq! 55 | @canonical = @types[0] if @types.size == 1 56 | @canonicalized = true 57 | end 58 | 59 | def to_s # :nodoc: 60 | return @canonical.to_s if @canonical 61 | return "#{@types.map { |t| t.to_s }.join(' or ')}" 62 | end 63 | 64 | def ==(other) # :nodoc: 65 | return false if other.nil? 66 | canonicalize! 67 | return @canonical == other if @canonical 68 | other = other.canonical 69 | return false unless other.instance_of? UnionType 70 | other.canonicalize! 71 | return false unless @types.length == other.types.length 72 | return @types.all? { |t| other.types.any? { |ot| t == ot } } 73 | end 74 | 75 | alias eql? == 76 | 77 | def match(other) 78 | canonicalize! 79 | return @canonical.match(other) if @canonical 80 | other = other.canonical 81 | other = other.type if other.instance_of? AnnotatedArgType 82 | return true if other.instance_of? WildQuery 83 | return false unless other.instance_of? UnionType 84 | return false if @types.length != other.types.length 85 | @types.all? { |t| other.types.any? { |ot| t.match(ot) } } 86 | end 87 | 88 | def <=(other) 89 | return Type.leq(self, other) 90 | end 91 | 92 | def leq_inst(other, inst=nil, ileft=true) 93 | canonicalize! 94 | return @canonical.leq_inst(other, inst, ileft) if @canonical 95 | other = other.type if other.is_a? DependentArgType 96 | other = other.canonical 97 | if inst && !ileft && other.is_a?(VarType) 98 | return leq_inst(inst[other.name], inst, ileft) if inst[other.name] 99 | inst.merge!(other.name => self) 100 | return true 101 | end 102 | return @types.all? { |t| t.leq_inst(other, inst, ileft) } 103 | end 104 | 105 | def member?(obj, *args) 106 | canonicalize! 107 | return @canonical.member?(obj, *args) if @canonical 108 | @types.any? { |t| t.member?(obj, *args) } 109 | end 110 | 111 | def instantiate(inst) 112 | canonicalize! 113 | return @canonical.instantiate(inst) if @canonical 114 | return UnionType.new(*(@types.map { |t| t.instantiate(inst) })) 115 | end 116 | 117 | def hash # :nodoc: 118 | return @hash 119 | end 120 | end 121 | end 122 | -------------------------------------------------------------------------------- /lib/types/core/object.rb: -------------------------------------------------------------------------------- 1 | # Instead of rdl_nowrap, mark individual methods as not being wrapped so 2 | # we can wrap stuff defined by the user at the top level (since those 3 | # methods are added to Object). 4 | 5 | # RDL.type :ARGF, ARGF 6 | # RDL.type :ARGV, 'Array' 7 | # RDL.type :DATA, 'File' 8 | # RDL.type :ENV, ENV 9 | # RDL.type :FALSE, '%false' 10 | # RDL.type :NIL, 'nil' 11 | # RDL.type :RUBY_COPYRIGHT, 'String' 12 | # RDL.type :RUBY_DESCRIPTION, 'String' 13 | # RDL.type :RUBY_ENGINE, 'String' 14 | # RDL.type :RUBY_PATCHLEVEL, Integer 15 | # RDL.type :RUBY_PLATFORM, 'String' 16 | # RDL.type :RUBY_RELEASE_DATE, 'String' 17 | # RDL.type :RUBY_REVISION, Integer 18 | # RDL.type :RUBY_VERSION, 'String' 19 | # RDL.type :STDERR, 'IO' 20 | # RDL.type :STDIN, 'IO' 21 | # RDL.type :STDOUT, 'IO' 22 | # RDL.type :TOPLEVEL_BINDING, 'Binding' 23 | # RDL.type :TRUE, '%true' 24 | 25 | RDL.type :Object, :!~, '(%any other) -> %bool', wrap: false 26 | RDL.type :Object, :<=>, '(%any other) -> Integer or nil', wrap: false 27 | RDL.type :Object, :===, '(%any other) -> %bool', wrap: false 28 | RDL.type :Object, :=~, '(%any other) -> nil', wrap: false 29 | RDL.type :Object, :class, '() -> Class', wrap: false 30 | RDL.type :Object, :clone, '() -> self', wrap: false 31 | # RDL.type :Object, :define_singleton_method, '(XXXX : *XXXX)') # TODO 32 | RDL.type :Object, :display, '(IO port) -> nil', wrap: false 33 | RDL.type :Object, :dup, '() -> self an_object', wrap: false 34 | RDL.type :Object, :enum_for, '(?Symbol method, *%any args) -> Enumerator<%any>', wrap: false 35 | RDL.type :Object, :enum_for, '(?Symbol method, *%any args) { (*%any args) -> %any } -> Enumerator<%any>', wrap: false 36 | RDL.type :Object, :eql?, '(%any other) -> %bool', wrap: false 37 | # RDL.type :Object, :extend, '(XXXX : *XXXX)') # TODO 38 | RDL.type :Object, :freeze, '() -> self', wrap: false 39 | RDL.type :Object, :frozen?, '() -> %bool', wrap: false 40 | RDL.type :Object, :hash, '() -> Integer', wrap: false 41 | RDL.type :Object, :inspect, '() -> String', wrap: false 42 | RDL.type :Object, :instance_of?, '(Class) -> %bool', wrap: false 43 | RDL.type :Object, :instance_variable_defined?, '(Symbol or String) -> %bool', wrap: false 44 | RDL.type :Object, :instance_variable_get, '(Symbol or String) -> %any', wrap: false 45 | RDL.type :Object, :instance_variable_set, '(Symbol or String, %any) -> %any', wrap: false # returns 2nd argument 46 | RDL.type :Object, :instance_variables, '() -> Array', wrap: false 47 | RDL.type :Object, :is_a?, '(Class or Module) -> %bool', wrap: false 48 | RDL.type :Object, :kind_of?, '(Class) -> %bool', wrap: false 49 | RDL.type :Object, :method, '(Symbol) -> Method', wrap: false 50 | RDL.type :Object, :methods, '(?%bool regular) -> Array', wrap: false 51 | RDL.type :Object, :nil?, '() -> %bool', wrap: false 52 | RDL.type :Object, :private_methods, '(?%bool all) -> Array', wrap: false 53 | RDL.type :Object, :protected_methods, '(?%bool all) -> Array', wrap: false 54 | RDL.type :Object, :public_method, '(Symbol) -> Method', wrap: false 55 | RDL.type :Object, :public_methods, '(?%bool all) -> Array', wrap: false 56 | RDL.type :Object, :public_send, '(Symbol or String, *%any args) -> %any', wrap: false 57 | RDL.type :Object, :remove_instance_variable, '(Symbol) -> %any', wrap: false 58 | # RDL.type :Object, :respond_to?, '(Symbol or String, ?%bool include_all) -> %bool' 59 | RDL.type :Object, :send, '(Symbol or String, *%any args) -> %any', wrap: false # Can't wrap this, used outside wrap switch 60 | RDL.type :Object, :singleton_class, '() -> Class', wrap: false 61 | RDL.type :Object, :singleton_method, '(Symbol) -> Method', wrap: false 62 | RDL.type :Object, :singleton_methods, '(?%bool all) -> Array', wrap: false 63 | RDL.type :Object, :taint, '() -> self', wrap: false 64 | RDL.type :Object, :tainted?, '() -> %bool', wrap: false 65 | # RDL.type :Object, :tap, '()') # TODO 66 | RDL.type :Object, :to_enum, '(?Symbol method, *%any args) -> Enumerator<%any>', wrap: false 67 | RDL.type :Object, :to_enum, '(?Symbol method, *%any args) {(*%any args) -> %any} -> Enumerator<%any>', wrap: false 68 | # TODO: above alias for enum_for? 69 | RDL.type :Object, :to_s, '() -> String', wrap: false 70 | RDL.type :Object, :trust, '() -> self', wrap: false 71 | RDL.type :Object, :untaint, '() -> self', wrap: false 72 | RDL.type :Object, :untrust, '() -> self', wrap: false 73 | RDL.type :Object, :untrusted?, '() -> %bool', wrap: false 74 | -------------------------------------------------------------------------------- /CHANGES.md: -------------------------------------------------------------------------------- 1 | # Change log! 2 | 3 | ## [Unreleased] 4 | 5 | ### Fixed 6 | - Dynamic type checking of initialize method 7 | - Bug with handling constants of certain types 8 | - Broken rdl_attr_* methods 9 | - Bug handling optional annotated/dependent types 10 | - Add RDLAnnotate to rdl_disable 11 | - Type checking of Object class singleton methods 12 | - #52 Kernel.raise annotation 13 | - #42 use grandparent type information for methods 14 | - #43 allow fully qualified calls 15 | - #45 handle local constants 16 | - #62 allow more method names in structural types 17 | - #34 clean up discussion of how type checking works in README 18 | 19 | ## [2.1.0] - 2017-06-14 20 | 21 | ### Fixed 22 | - Type checking bug in const expressions when env[:self] is SingletonType 23 | - Type for unary minus in numeric type files (changed :- to :-@) 24 | - Type checking initialize method bugs 25 | - Type checking of Module methods 26 | - Type checking method when class name is included in type annotation 27 | - Dynamic type checks after calls to instantiate! 28 | - Ruby 2.4 compatibility! 29 | - Various core and standard library types 30 | - Parsing bug with `or` 31 | - Sub-classes not wrapped bug 32 | - Exception from case/when branch with empty body 33 | 34 | ### Added 35 | - Support operator assignment when left-hand side has method args 36 | - Support nested class names 37 | - Type for unary plus in numeric type files 38 | - Support for instantiate! for binding type parameters during static type checking 39 | - New "check" flag for calls to instantiate! indicating whether we want to check type of receiving object on call 40 | - More precise static type checking for `Object#class` method 41 | - Klass argument to rdl_nowrap, rdl_alias 42 | - Some more support for Rails 43 | - Support for next/break in block arguments 44 | - Support for super in static analysis 45 | 46 | ### Changed 47 | - Global variables are now module variables of RDL::Globals 48 | - at_exit handler only installed if `Config.report` or `.guess_types` are accessed 49 | - Subclass Parser::Diagnostic instead of monkey patching it 50 | - Replaced `Fixnum` with `Integer` in README (suggested by https://github.com/Dorian) 51 | - All annotations removed from `Object` and added to `RDL::Annotate` 52 | - `type_cast`, `instantiate!`, and `deinstantiate!` are now part of the `RDL` module to avoid adding them to `Object` 53 | 54 | ## [2.0.1] - 2016-11-11 55 | 56 | ### Fixed 57 | - Improved support for modules (still incomplete) 58 | - Fix a bug with typing self.new 59 | - Fix bug with annotated return types 60 | - Fix bug with rdl_query 61 | - Fix bug with running under Rails where type files don't exist (Joel Holdbrooks) 62 | 63 | ## [2.0.0] - 2016-08-24 64 | ### Added 65 | - Static type checking! 66 | - `wrap: false` optional argument to `type`, `pre`, and `post` 67 | - Non-null type annotation (not checked) 68 | - Default argument configuration for `type`, `pre`, and `post` 69 | - `attr_*_type` methods 70 | - Initial types for Rails 71 | 72 | ### Changed 73 | - Modified `self` type to be any instance of the self's class 74 | - Library types now use new aliases %integer and %numeric instead of the Integer and Numeric classes 75 | - Instead of requiring `rdl_types.rb`, require `types/core` 76 | 77 | ### Fixed 78 | - Fix issue #14 - allow type/pre/post to coexist, improve docs on dependent types 79 | - Fix typos in README, pull req #13 80 | - Fix bug where calling method overloaded sometimes with block and sometimes without would always report type error 81 | 82 | ## [1.1.1] - 2016-05-21 83 | ### Fixed 84 | - Update code to eliminate Ruby 2.3 warning messages 85 | - Fixed errors in post conditions of numeric types (incorrect number of args) 86 | - Added syntax highlighting in README.md as pointed out by jsyeo 87 | - Comprehensive changes to types of Numeric subclass methods to make types more specific & accurate 88 | - Changed superclasses of numeric classes to be `Numeric` 89 | 90 | ### Added 91 | - Higher-order types and tests for them 92 | - Dependent types 93 | - `/extras` directory, which contains random type tests for numeric subclass method types 94 | - `BigDecimal` added to alias `%real` 95 | - Changelog added! 96 | 97 | ## [1.1.0] - 2016-01-03 98 | ### Added 99 | - Added much enhanced `rdl_query` facility and accompanying command-line script. 100 | 101 | ## [1.0.0] - 2015-12-18 102 | - First release! 103 | -------------------------------------------------------------------------------- /lib/rdl/types/lexer.rex.rb: -------------------------------------------------------------------------------- 1 | #-- 2 | # DO NOT MODIFY!!!! 3 | # This file is automatically generated by rex 1.0.5 4 | # from lexical definition file "lexer.rex". 5 | #++ 6 | 7 | require 'racc/parser' 8 | module RDL::Type 9 | class Parser < Racc::Parser 10 | require 'strscan' 11 | 12 | class ScanError < StandardError ; end 13 | 14 | attr_reader :lineno 15 | attr_reader :filename 16 | attr_accessor :state 17 | 18 | def scan_setup(str) 19 | @ss = StringScanner.new(str) 20 | @lineno = 1 21 | @state = nil 22 | end 23 | 24 | def action 25 | yield 26 | end 27 | 28 | def scan_str(str) 29 | scan_setup(str) 30 | do_parse 31 | end 32 | alias :scan :scan_str 33 | 34 | def load_file( filename ) 35 | @filename = filename 36 | open(filename, "r") do |f| 37 | scan_setup(f.read) 38 | end 39 | end 40 | 41 | def scan_file( filename ) 42 | load_file(filename) 43 | do_parse 44 | end 45 | 46 | 47 | def next_token 48 | return if @ss.eos? 49 | 50 | # skips empty actions 51 | until token = _next_token or @ss.eos?; end 52 | token 53 | end 54 | 55 | def _next_token 56 | text = @ss.peek(1) 57 | @lineno += 1 if text == "\n" 58 | token = case @state 59 | when nil 60 | case 61 | when (text = @ss.scan(/\s/)) 62 | ; 63 | 64 | when (text = @ss.scan(/->/)) 65 | action { [:RARROW, text] } 66 | 67 | when (text = @ss.scan(/=>/)) 68 | action { [:RASSOC, text] } 69 | 70 | when (text = @ss.scan(/\(/)) 71 | action { [:LPAREN, text] } 72 | 73 | when (text = @ss.scan(/\)/)) 74 | action { [:RPAREN, text] } 75 | 76 | when (text = @ss.scan(/\{\{(?:(?!}}).)+\}\}/)) 77 | action { [:PREDICATE, text[2..-3]] } 78 | 79 | when (text = @ss.scan(/\{/)) 80 | action { [:LBRACE, text] } 81 | 82 | when (text = @ss.scan(/\}/)) 83 | action { [:RBRACE, text] } 84 | 85 | when (text = @ss.scan(/\[/)) 86 | action { [:LBRACKET, text] } 87 | 88 | when (text = @ss.scan(/\]/)) 89 | action { [:RBRACKET, text] } 90 | 91 | when (text = @ss.scan(//)) 95 | action { [:GREATER, text] } 96 | 97 | when (text = @ss.scan(/=/)) 98 | action { [:EQUAL, text] } 99 | 100 | when (text = @ss.scan(/,/)) 101 | action { [:COMMA, text] } 102 | 103 | when (text = @ss.scan(/\?/)) 104 | action { [:QUERY, text] } 105 | 106 | when (text = @ss.scan(/\!/)) 107 | action { [:BANG, text] } 108 | 109 | when (text = @ss.scan(/~/)) 110 | action { [:TILDE, text] } 111 | 112 | when (text = @ss.scan(/\*\*/)) 113 | action { [:STARSTAR, text] } 114 | 115 | when (text = @ss.scan(/\*/)) 116 | action { [:STAR, text] } 117 | 118 | when (text = @ss.scan(/\#T/)) 119 | action { [:HASH_TYPE, text] } 120 | 121 | when (text = @ss.scan(/\#Q/)) 122 | action { [:HASH_QUERY, text] } 123 | 124 | when (text = @ss.scan(/\$\{/)) 125 | action { [:CONST_BEGIN, text] } 126 | 127 | when (text = @ss.scan(/\.\.\./)) 128 | action { [:DOTS, text] } 129 | 130 | when (text = @ss.scan(/\./)) 131 | action { [:DOT, text] } 132 | 133 | when (text = @ss.scan(/``(?:(?!``).)+``/)) 134 | action { [:COMP, text[2..-3]] } 135 | 136 | when (text = @ss.scan(/-?\d\.\d+/)) 137 | action { [:FLOAT, text] } # Must go before FIXNUM 138 | 139 | when (text = @ss.scan(/-?(\d)+/)) 140 | action { [:FIXNUM, text] } 141 | 142 | when (text = @ss.scan(/((\w|\:\:)+(!|\?|=)?)|~|\+|-|\/|&|\||\^/)) 143 | action { if text == "or" then [:OR, text] else [:ID, text] end } 144 | 145 | when (text = @ss.scan(/:\w+/)) 146 | action { [:SYMBOL, text[1..-1]] } 147 | 148 | when (text = @ss.scan(/\:/)) 149 | action { [:COLON, text] } # Must come after SYMBOL 150 | 151 | when (text = @ss.scan(/%\w+/)) 152 | action { [:SPECIAL_ID, text] } 153 | 154 | when (text = @ss.scan(/'[^']*'/)) 155 | action { [:STRING, text.gsub("'", "")] } 156 | 157 | when (text = @ss.scan(/"[^"]*"/)) 158 | action { [:STRING, text.gsub('"', "")] } 159 | 160 | else 161 | text = @ss.string[@ss.pos .. -1] 162 | raise ScanError, "can not match: '" + text + "'" 163 | end # if 164 | 165 | else 166 | raise ScanError, "undefined state: '" + state.to_s + "'" 167 | end # case state 168 | token 169 | end # def _next_token 170 | 171 | end # class 172 | end 173 | -------------------------------------------------------------------------------- /lib/rdl/types/finite_hash.rb: -------------------------------------------------------------------------------- 1 | require_relative 'type' 2 | 3 | module RDL::Type 4 | # Type for finite maps from values to types; values are compared with ==. 5 | # These are used for "named" arguments in Ruby, in which case the values are symbols. 6 | # Finite hashes can also have a "rest" type (okay, they're not exactly finite in this case...) 7 | # which is treated as a hash from Symbol to the type. 8 | class FiniteHashType < Type 9 | attr_reader :elts 10 | attr_reader :rest 11 | attr_reader :the_hash # either nil or hash type if self has been promoted to hash 12 | attr_accessor :ubounds # upper bounds this tuple has been compared with using <= 13 | attr_accessor :lbounds # lower bounds... 14 | 15 | # [+ elts +] is a map from keys to types 16 | def initialize(elts, rest) 17 | elts.each { |k, t| 18 | raise RuntimeError, "Got #{t.inspect} where Type expected" unless t.is_a? Type 19 | raise RuntimeError, "Type may not be annotated or vararg" if (t.instance_of? AnnotatedArgType) || (t.instance_of? VarargType) 20 | } 21 | @elts = elts 22 | @rest = rest 23 | @the_hash = nil 24 | @cant_promote = false 25 | @ubounds = [] 26 | @lbounds = [] 27 | super() 28 | end 29 | 30 | def canonical 31 | return @the_hash if @the_hash 32 | return self 33 | end 34 | 35 | def to_s 36 | return @the_hash.to_s if @the_hash 37 | return "{ " + @elts.map { |k, t| k.to_s + ": " + t.to_s }.join(', ') + (if @rest then ", **" + @rest.to_s else "" end) + " }" 38 | end 39 | 40 | def ==(other) # :nodoc: 41 | return false if other.nil? 42 | return (@the_hash == other) if @the_hash 43 | other = other.canonical 44 | return (other.instance_of? FiniteHashType) && (other.elts == @elts) && (other.rest == @rest) 45 | end 46 | 47 | alias eql? == 48 | 49 | def match(other) 50 | return @the_hash.match(other) if @the_hash 51 | other = other.canonical 52 | other = other.type if other.instance_of? AnnotatedArgType 53 | return true if other.instance_of? WildQuery 54 | return false unless other.instance_of? FiniteHashType 55 | return false unless ((@rest.nil? && other.rest.nil?) || 56 | (!@rest.nil? && !other.rest.nil? && @rest.match(other.rest))) 57 | return (@elts.length == other.elts.length && 58 | @elts.all? { |k, v| (other.elts.has_key? k) && (v.match(other.elts[k]))}) 59 | end 60 | 61 | def promote! 62 | return false if @cant_promote 63 | # TODO look at key types 64 | domain_type = UnionType.new(*(@elts.keys.map { |k| NominalType.new(k.class) })) 65 | range_type = UnionType.new(*@elts.values) 66 | if @rest 67 | domain_type = UnionType.new(domain_type, RDL::Globals.types[:symbol]) 68 | range_type = UnionType.new(range_type, @rest) 69 | end 70 | @the_hash = GenericType.new(RDL::Globals.types[:hash], domain_type, range_type) 71 | # same logic as Tuple 72 | return (@lbounds.all? { |lbound| lbound <= self }) && (@ubounds.all? { |ubound| self <= ubound }) 73 | end 74 | 75 | def cant_promote! 76 | raise RuntimeError, "already promoted!" if @the_hash 77 | @cant_promote = true 78 | end 79 | 80 | def <=(other) 81 | return Type.leq(self, other) 82 | end 83 | 84 | def member?(obj, *args) 85 | return @the_hash.member(obj, *args) if @the_hash 86 | t = RDL::Util.rdl_type obj 87 | return t <= self if t 88 | right_elts = @elts.clone # shallow copy 89 | 90 | return false unless obj.instance_of? Hash 91 | 92 | # Check that every mapping in obj exists in @map and matches the type 93 | obj.each_pair { |k, v| 94 | if @elts.has_key? k 95 | t = @elts[k] 96 | t = t.type if t.instance_of? OptionalType 97 | return false unless t.member? v 98 | right_elts.delete k 99 | else 100 | return false unless @rest && @rest.member?(v) 101 | end 102 | } 103 | 104 | # Check that any remaining types are optional 105 | right_elts.each_pair { |k, vt| 106 | return false unless vt.instance_of? OptionalType 107 | } 108 | 109 | return true 110 | end 111 | 112 | def instantiate(inst) 113 | return @the_hash.instantiate(inst) if @the_hash 114 | return FiniteHashType.new(Hash[@elts.map { |k, t| [k, t.instantiate(inst)] }], (if @rest then @rest.instantiate(inst) end)) 115 | end 116 | 117 | def hash 118 | # note don't change hash value if @the_hash becomes non-nil 119 | return 229 * @elts.hash * @rest.hash 120 | end 121 | end 122 | end 123 | -------------------------------------------------------------------------------- /lib/types/core/module.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :Module 2 | 3 | RDL.type :Module, 'self.constants', '() -> Array' # also constants(inherited), but undocumented 4 | RDL.type :Module, 'self.nesting', '() -> Array' 5 | RDL.type :Module, :initialize, '() -> self' 6 | RDL.type :Module, :initialize, '() { (Module) -> %any } -> self' 7 | 8 | RDL.type :Module, :<, '(Module other) -> %bool or nil' 9 | RDL.type :Module, :<=, '(Module other) -> %bool or nil' 10 | RDL.type :Module, :<=>, '(Module other) -> -1 or 0 or 1 or nil' 11 | RDL.type :Module, :==, '(%any other) -> %bool' 12 | RDL.type :Module, :equal, '(%any other) -> %bool' 13 | RDL.type :Module, :eql, '(%any other) -> %bool' 14 | RDL.type :Module, :===, '(%any other) -> %bool' 15 | RDL.type :Module, :>, '(Module other) -> %bool or nil' 16 | RDL.type :Module, :>=, '(Module other) -> %bool or nil' 17 | RDL.type :Module, :ancestors, '() -> Array' 18 | RDL.type :Module, :autoload, '(Symbol module, String filename) -> nil' 19 | RDL.type :Module, :autoload?, '(Symbol name) -> String or nil' 20 | RDL.type :Module, :class_eval, '(String, ?String filename, ?Integer lineno) -> %any' 21 | RDL.type :Module, :class_exec, '(*%any args) { (*%any args) -> %any } -> %any' 22 | RDL.type :Module, :class_variable_defined?, '(Symbol or String) -> %bool' 23 | RDL.type :Module, :class_variable_get, '(Symbol or String) -> %any' 24 | RDL.type :Module, :class_variable_set, '(Symbol or String, %any) -> %any' 25 | RDL.type :Module, :class_variables, '(?%bool inherit) -> Array' 26 | RDL.type :Module, :const_defined?, '(Symbol or String, ?%bool inherit) -> %bool' 27 | RDL.type :Module, :const_get, '(Symbol or String, ?%bool inherit) -> %any' 28 | RDL.type :Module, :const_missing, '(Symbol) -> %any' 29 | RDL.type :Module, :const_set, '(Symbol or String, %any) -> %any' 30 | RDL.type :Module, :constants, '(?%bool inherit) -> Array' 31 | RDL.type :Module, :freeze, '() -> self' 32 | RDL.type :Module, :include, '(*Module) -> self' 33 | RDL.type :Module, :include?, '(Module) -> %bool' 34 | RDL.type :Module, :included_modules, '() -> Array' 35 | RDL.rdl_alias :Module, :inspect, :to_s 36 | RDL.type :Module, :instance_method, '(Symbol) -> UnboundMethod' 37 | RDL.type :Module, :instance_methods, '(?%bool include_super) -> Array' 38 | RDL.type :Module, :method_defined?, '(Symbol or String) -> %bool' 39 | RDL.type :Module, :module_eval, '(String, ?String filename, ?Integer lineno) -> %any' # matches rdoc example but not RDL.type 40 | RDL.type :Module, :module_exec, '(*%any args) { (*%any args) -> %any } -> %any' 41 | RDL.type :Module, :name, '() -> String' 42 | RDL.type :Module, :prepend, '(*Module) -> self' 43 | RDL.type :Module, :private_class_method, '(*(Symbol or String)) -> self' 44 | RDL.type :Module, :private_constant, '(*Symbol) -> self' 45 | RDL.type :Module, :private_instance_methods, '(?%bool include_super) -> Array' 46 | RDL.type :Module, :private_method_defined?, '(Symbol or String) -> %bool' 47 | RDL.type :Module, :protected_instance_methods, '(?%bool include_super) -> Array' 48 | RDL.type :Module, :protected_method_defined?, '(Symbol or String) -> %bool' 49 | RDL.type :Module, :public_class_method, '(*(Symbol or String)) -> self' 50 | RDL.type :Module, :public_constant, '(*Symbol) -> self' 51 | RDL.type :Module, :public_instance_method, '(Symbol) -> UnboundMethod' 52 | RDL.type :Module, :public_instance_methods, '(?%bool include_super) -> Array' 53 | RDL.type :Module, :public_method_defined?, '(Symbol or String) -> %bool' 54 | RDL.type :Module, :remove_class_variable, '(Symbol) -> %any' 55 | RDL.type :Module, :singleton_class?, '() -> %bool' 56 | RDL.type :Module, :to_s, '() -> String' 57 | # private methods below here 58 | RDL.type :Module, :alias_method, '(Symbol new_name, Symbol old_name) -> self' 59 | RDL.type :Module, :append_features, '(Module) -> self' 60 | RDL.rdl_alias :Module, :attr, :attr_reader 61 | RDL.type :Module, :attr_accessor, '(*(Symbol or String)) -> nil' 62 | RDL.type :Module, :attr_reader, '(*(Symbol or String)) -> nil' 63 | RDL.type :Module, :attr_writer, '(*(Symbol or String)) -> nil' 64 | RDL.type :Module, :define_method, '(Symbol, Method) -> Symbol' 65 | RDL.type :Module, :define_method, '(Symbol) { (*%any) -> %any } -> Symbol' 66 | RDL.type :Module, :extend_object, '(%any) -> %any' 67 | RDL.type :Module, :extended, '(Module othermod) -> %any' 68 | RDL.type :Module, :included, '(Module othermod) -> %any' 69 | RDL.type :Module, :method_added, '(Symbol method_name) -> %any' 70 | RDL.type :Module, :method_removed, '(Symbol method_name) -> %any' 71 | RDL.type :Module, :module_function, '(*(Symbol or String)) -> self' 72 | RDL.type :Module, :prepend_features, '(Module) -> self' 73 | RDL.type :Module, :prepended, '(Module othermod) -> %any' 74 | RDL.type :Module, :private, '(*(Symbol or String)) -> self' 75 | RDL.type :Module, :protected, '(*(Symbol or String)) -> self' 76 | RDL.type :Module, :public, '(*(Symbol or String)) -> self' 77 | RDL.type :Module, :refine, '(Class) { (%any) -> %any } -> self' # ?? 78 | RDL.type :Module, :remove_const, '(Symbol) -> %any' 79 | RDL.type :Module, :remove_method, '(Symbol or String) -> self' 80 | RDL.type :Module, :undef_method, '(Symbol or String) -> self' 81 | RDL.type :Module, :using, '(Module) -> self' 82 | -------------------------------------------------------------------------------- /test/disabled_test_coverage.rb: -------------------------------------------------------------------------------- 1 | require 'set' 2 | require 'abbrev' 3 | require 'base64' 4 | require 'benchmark' 5 | require 'bigdecimal' 6 | require 'bigdecimal/math' 7 | require 'coverage.so' 8 | 9 | require 'minitest/autorun' 10 | require_relative '../lib/rdl.rb' 11 | require_relative '../lib/rdl_types.rb' 12 | 13 | RDL::Config.instance.profile_stats 14 | 15 | class Dummy 16 | def self.each 17 | end 18 | def each 19 | end 20 | end 21 | 22 | class TestStdlibTypes < Minitest::Test 23 | 24 | def test_abbrev 25 | assert_raises(RDL::Type::TypeError) { s0 = Abbrev.abbrev 5} 26 | # From the Ruby stdlib documentation 27 | s1 = Abbrev.abbrev(['ruby']) # -> {"ruby"=>"ruby", "rub"=>"ruby", "ru"=>"ruby", "r"=>"ruby"} 28 | ev = {"ruby"=>"ruby", "rub"=>"ruby", "ru"=>"ruby", "r"=>"ruby"} 29 | assert_equal(s1,ev) 30 | # Other tests 31 | assert_raises(RDL::Type::TypeError) { s2 = Abbrev.abbrev Dummy.new } 32 | end 33 | 34 | def test_base64 35 | # From the Ruby stdlib documentation 36 | e0 = Base64.encode64('Send reinforcements') # -> "U2VuZCByZWluZm9yY2VtZW50cw==\n" 37 | d0 = Base64.decode64(e0) # -> "Send reinforcements" 38 | #assert_equal(e0,d0) 39 | e1 = Base64.strict_encode64('Send reinforcements') 40 | d1 = Base64.strict_decode64(e1) 41 | #assert_equal(e1,d1) 42 | e2 = Base64.urlsafe_encode64('Send reinforcements') 43 | d2 = Base64.urlsafe_decode64(e2) 44 | #assert_equal(e2,d2) 45 | end 46 | 47 | def test_benchmark 48 | skip "Skip these because they print to stdout" 49 | # From the Ruby stdlib documentation 50 | Benchmark.measure { "a"*1_000_000_000 } 51 | n = 5000000 52 | Benchmark.bm do |x| 53 | x.report { for i in 1..n; a = "1"; end } 54 | x.report { n.times do ; a = "1"; end } 55 | x.report { 1.upto(n) do ; a = "1"; end } 56 | end 57 | Benchmark.bm(7) do |x| 58 | x.report("for:") { for i in 1..n; a = "1"; end } 59 | x.report("times:") { n.times do ; a = "1"; end } 60 | x.report("upto:") { 1.upto(n) do ; a = "1"; end } 61 | end 62 | array = (1..1000000).map { rand } 63 | Benchmark.bmbm do |x| 64 | #x.report("sort!") { array.dup.sort! } # TODO this causes a hang 65 | #x.report("sort") { array.dup.sort } 66 | end 67 | Benchmark.benchmark(Benchmark::CAPTION, 7, Benchmark::FORMAT, ">total:", ">avg:") do |x| 68 | tf = x.report("for:") { for i in 1..n; a = "1"; end } 69 | tt = x.report("times:") { n.times do ; a = "1"; end } 70 | tu = x.report("upto:") { 1.upto(n) do ; a = "1"; end } 71 | [tf+tt+tu, (tf+tt+tu)/3] 72 | end 73 | end 74 | 75 | def test_bigdecimal 76 | # From the RUby stdlib documentation 77 | BigDecimal.save_exception_mode do 78 | BigDecimal.mode(BigDecimal::EXCEPTION_OVERFLOW, false) 79 | BigDecimal.mode(BigDecimal::EXCEPTION_NaN, false) 80 | 81 | BigDecimal.new(BigDecimal('Infinity')) 82 | BigDecimal.new(BigDecimal('-Infinity')) 83 | BigDecimal(BigDecimal.new('NaN')) 84 | end 85 | BigDecimal.save_limit do 86 | BigDecimal.limit(200) 87 | end 88 | BigDecimal.save_rounding_mode do 89 | BigDecimal.mode(BigDecimal::ROUND_MODE, :up) 90 | end 91 | # Additional test calls for coverage 92 | BigDecimal.double_fig 93 | BigDecimal.limit(5) 94 | BigDecimal.mode(BigDecimal::EXCEPTION_NaN, true) 95 | BigDecimal.mode(BigDecimal::EXCEPTION_NaN, false) 96 | BigDecimal.mode(BigDecimal::EXCEPTION_NaN) 97 | BigDecimal.ver 98 | 99 | # TODO 100 | end 101 | 102 | def test_bigmath 103 | # From the Ruby stdlib documentation 104 | BigMath.E(10) 105 | BigMath.PI(10) 106 | BigMath.atan(BigDecimal.new('-1'), 16) 107 | BigMath.cos(BigMath.PI(4), 16) 108 | BigMath.sin(BigMath.PI(5)/4, 5) 109 | BigMath.sqrt(BigDecimal.new('2'), 16) 110 | end 111 | 112 | def test_coverage 113 | Coverage.start 114 | Coverage.result 115 | #Coverage.result # TODO This cannot be typechecked 116 | end 117 | 118 | def test_set 119 | assert_raises(RDL::Type::TypeError) { s6 = Set.new(1,2) } 120 | # From the Ruby stdlib documentation 121 | s1 = Set.new [1, 2] # -> # 122 | s2 = [1, 2].to_set # -> # 123 | s1 == s2 # -> true 124 | s1.add("foo") # -> # 125 | s1.merge([2, 6]) # -> # 126 | s1.subset? s2 # -> false 127 | s2.subset? s1 # -> true 128 | Set[1, 2, 3].disjoint? Set[3, 4] # => false 129 | Set[1, 2, 3].disjoint? Set[4, 5] # => true 130 | numbers = Set[1, 3, 4, 6, 9, 10, 11] 131 | set = numbers.divide { |i,j| (i - j).abs == 1 } 132 | Set[1, 2, 3].intersect? Set[4, 5] # => false 133 | Set[1, 2, 3].intersect? Set[3, 4] # => true 134 | # Some more tests, just to make sure type checking doesn't cause crashes 135 | s3 = s1 - s2 136 | s1.proper_subset? s2 137 | s1.superset? s2 138 | s1 ^ s2 139 | s1.add?("bar") 140 | h = s1.classify { |x| x.size } 141 | s2.clear 142 | s4 = s1.map { |x| 42 } 143 | s1.delete "foo" 144 | s1.delete? "bar" 145 | s1.delete_if { |x| false } 146 | s1.each { |x| nil } 147 | s1.empty? 148 | s1.member? 42 149 | s1.intersection [1,2,3] 150 | s1.keep_if { |x| true } 151 | s1.size 152 | s1.difference [1,2,3] 153 | s1.to_a 154 | s5 = s1 + s2 155 | end 156 | end -------------------------------------------------------------------------------- /lib/types/core/enumerable.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :Enumerable 2 | 3 | RDL.type_params :Enumerable, [:t], :all? 4 | 5 | RDL.type :Enumerable, :all?, '() -> %bool' 6 | RDL.type :Enumerable, :all?, '() { (t) -> %bool } -> %bool' 7 | RDL.type :Enumerable, :any?, '() -> %bool' 8 | RDL.type :Enumerable, :any?, '() { (t) -> %bool } -> %bool' 9 | # RDL.type :Enumerable, :chunk, '(XXXX : *XXXX)' # TODO 10 | RDL.type :Enumerable, :collect, '() { (t) -> u } -> Array' 11 | RDL.type :Enumerable, :collect, '() -> Enumerator' 12 | # RDL.type :Enumerable, :collect_concat # TODO 13 | RDL.type :Enumerable, :count, '() -> Integer' 14 | RDL.type :Enumerable, :count, '(%any) -> Integer' 15 | RDL.type :Enumerable, :count, '() { (t) -> %bool } -> Integer' 16 | RDL.type :Enumerable, :cycle, '(?Integer n) { (t) -> %any } -> nil' 17 | RDL.type :Enumerable, :cycle, '(?Integer n) -> Enumerator' 18 | RDL.type :Enumerable, :detect, '(?Proc ifnone) { (t) -> %bool } -> t or nil' # TODO ifnone 19 | RDL.type :Enumerable, :detect, '(?Proc ifnone) -> Enumerator' 20 | RDL.type :Enumerable, :drop, '(Integer n) -> Array' 21 | RDL.type :Enumerable, :drop_while, '() { (t) -> %bool } -> Array' 22 | RDL.type :Enumerable, :drop_while, '() -> Enumerator' 23 | RDL.type :Enumerable, :each_cons, '(Integer n) { (Array) -> %any } -> nil' 24 | RDL.type :Enumerable, :each_cons, '(Integer n) -> Enumerator' 25 | # RDL.type :Enumerable, :each_entry, '(XXXX : *XXXX)' # TODO 26 | RDL.rdl_alias :Enumerable, :each_slice, :each_cons 27 | RDL.type :Enumerable, :each_with_index, '() { (t, Integer) -> %any } -> Enumerable' # args! note may not return self 28 | RDL.type :Enumerable, :each_with_index, '() -> Enumerable' # args! note may not return self 29 | # RDL.type :Enumerable, :each_with_object, '(XXXX : XXXX)' #TODO 30 | RDL.type :Enumerable, :entries, '() -> Array' # TODO args? 31 | RDL.rdl_alias :Enumerable, :find, :detect 32 | RDL.type :Enumerable, :find_all, '() { (t) -> %bool } -> Array' 33 | RDL.type :Enumerable, :find_all, '() -> Enumerator' 34 | RDL.type :Enumerable, :find_index, '(%any value) -> Integer or nil' 35 | RDL.type :Enumerable, :find_index, '() { (t) -> %bool } -> Integer or nil' 36 | RDL.type :Enumerable, :find_index, '() -> Enumerator' 37 | RDL.type :Enumerable, :first, '() -> t or nil' 38 | RDL.type :Enumerable, :first, '(Integer n) -> Array or nil' 39 | # RDL.rdl_alias :Enumerable, :flat_map, :collect_concat 40 | RDL.type :Enumerable, :grep, '(%any) -> Array' 41 | RDL.type :Enumerable, :grep, '(%any) { (t) -> u } -> Array' 42 | RDL.type :Enumerable, :group_by, '() { (t) -> u } -> Hash>' 43 | RDL.type :Enumerable, :group_by, '() -> Enumerator' 44 | RDL.type :Enumerable, :include?, '(%any) -> %bool' 45 | RDL.type :Enumerable, :inject, '(any initial, Symbol) -> %any' # can't tell initial, return RDL.type; not enough info in Symbol 46 | RDL.type :Enumerable, :inject, '(Symbol) -> %any' 47 | RDL.type :Enumerable, :inject, '(u initial) { (u, t) -> u } -> u' 48 | RDL.type :Enumerable, :inject, '() { (t, t) -> t } -> t' # if initial not given, first element is initial 49 | # RDL.type :Enumerable, :lazy # TODO 50 | RDL.rdl_alias :Enumerable, :map, :collect 51 | RDL.type :Enumerable, :max, '() -> t' 52 | RDL.type :Enumerable, :max, '() { (t, t) -> Integer } -> t' 53 | RDL.type :Enumerable, :max, '(Integer) -> Array' 54 | RDL.type :Enumerable, :max, '(Integer) { (t, t) -> Integer } -> Array' 55 | RDL.type :Enumerable, :max_by, '() -> Enumerator' 56 | RDL.type :Enumerable, :max_by, '() { (t, t) -> Integer } -> t' 57 | RDL.type :Enumerable, :max_by, '(Integer) -> Enumerator' 58 | RDL.type :Enumerable, :max_by, '(Integer) { (t, t) -> Integer } -> Array' 59 | RDL.rdl_alias :Enumerable, :member?, :include? 60 | RDL.type :Enumerable, :min, '() -> t' 61 | RDL.type :Enumerable, :min, '() { (t, t) -> Integer } -> t' 62 | RDL.type :Enumerable, :min, '(Integer) -> Array' 63 | RDL.type :Enumerable, :min, '(Integer) { (t, t) -> Integer } -> Array' 64 | RDL.type :Enumerable, :min_by, '() -> Enumerator' 65 | RDL.type :Enumerable, :min_by, '() { (t, t) -> Integer } -> t' 66 | RDL.type :Enumerable, :min_by, '(Integer) -> Enumerator' 67 | RDL.type :Enumerable, :min_by, '(Integer) { (t, t) -> Integer } -> Array' 68 | RDL.type :Enumerable, :minmax, '() -> [t, t]' 69 | RDL.type :Enumerable, :minmax, '() { (t, t) -> Integer } -> [t, t]' 70 | RDL.type :Enumerable, :minmax_by, '() -> [t, t]' 71 | RDL.type :Enumerable, :minmax_by, '() { (t, t) -> Integer } -> Enumerator' 72 | RDL.type :Enumerable, :none?, '() -> %bool' 73 | RDL.type :Enumerable, :none?, '() { (t) -> %bool } -> %bool' 74 | RDL.type :Enumerable, :one?, '() -> %bool' 75 | RDL.type :Enumerable, :one?, '() { (t) -> %bool } -> %bool' 76 | RDL.type :Enumerable, :partition, '() { (t) -> %bool } -> [Array, Array]' 77 | RDL.type :Enumerable, :partition, '() -> Enumerator' 78 | RDL.rdl_alias :Enumerable, :reduce, :inject 79 | RDL.type :Enumerable, :reject, '() { (t) -> %bool } -> Array' 80 | RDL.type :Enumerable, :reject, '() -> Enumerator' 81 | RDL.type :Enumerable, :reverse_each, '() { (t) -> %any } -> Enumerator' # is that really the return RDL.type? TODO args 82 | RDL.type :Enumerable, :reverse_each, '() -> Enumerator' # TODO args 83 | RDL.rdl_alias :Enumerable, :select, :find_all 84 | # RDL.type :Enumerable, :slice_after, '(XXXX : *XXXX)' # TODO 85 | # RDL.type :Enumerable, :slice_before, '(XXXX : *XXXX)' # TODO 86 | # RDL.type :Enumerable, :slice_when, '()' # TODO 87 | RDL.type :Enumerable, :sort, '() -> Array' 88 | RDL.type :Enumerable, :sort, '() { (t, t) -> Integer } -> Array' 89 | RDL.type :Enumerable, :sort_by, '() { (t) -> %any } -> Array' 90 | RDL.type :Enumerable, :sort_by, '() -> Enumerator' 91 | RDL.type :Enumerable, :take, '(Integer n) -> Array or nil' 92 | RDL.type :Enumerable, :take_while, '() { (t) -> %bool } -> Array' 93 | RDL.type :Enumerable, :take_while, '() -> Enumerator' 94 | RDL.rdl_alias :Enumerable, :to_a, :entries 95 | RDL.type :Enumerable, :to_h, '() -> Hash' # TODO args? 96 | # RDL.type :Enumerable, :zip, '(XXXX : *XXXX)' # TODO 97 | -------------------------------------------------------------------------------- /lib/types/core/kernel.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :Kernel 2 | 3 | # RDL.type :Kernel, 'self.Array', '([to_ary: () -> Array]) -> Array' 4 | # RDL.type :Kernel, 'self.Array', '([to_a: () -> Array]) -> Array' 5 | RDL.type :Kernel, 'self.Complex', '(Numeric x, Numeric y) -> Complex' 6 | RDL.type :Kernel, 'self.Complex', '(String x) -> Complex' 7 | RDL.type :Kernel, 'self.Float', '(Numeric x) -> Float' 8 | # RDL.type :Kernel, 'self.Float', '(x : [to_f : () -> Float]) -> Float' 9 | # RDL.type :Kernel, 'self.Hash', '(x : [to_hash : () -> Hash]) -> Hash' 10 | RDL.type :Kernel, 'self.Hash', '(nil x) -> Hash' 11 | # RDL.type :Kernel, 'self.Hash, '(x : []) -> Hash' 12 | RDL.type :Kernel, 'self.Integer', '(Numeric or String arg, ?Integer base) -> Integer' 13 | # RDL.type :Kernel, 'self.Integer', '(arg : [to_int : () -> Integer], base : ?Integer) -> Integer' 14 | # RDL.type :Kernel, 'self.Integer', '(arg : [to_i : () -> Integer], base : ?Integer) -> Integer' 15 | RDL.type :Kernel, 'self.Rational', '(Numeric x, Numeric y) -> Rational' 16 | RDL.type :Kernel, 'self.Rational', '(String x) -> Rational' 17 | # RDL.type :Kernel, 'self.String', '(arg : [to_s : () -> String]) -> String' 18 | RDL.type :Kernel, 'self.__callee__', '() -> Symbol or nil' 19 | RDL.type :Kernel, 'self.__dir__', '() -> String or nil' 20 | RDL.type :Kernel, 'self.__method__', '() -> Symbol or nil' 21 | RDL.type :Kernel, 'self.`', '(String) -> String' 22 | RDL.type :Kernel, 'self.abort', '(?String msg) -> %bot' 23 | RDL.type :Kernel, 'self.at_exit', '() { () -> %any} -> Proc' # TODO: Fix proc 24 | RDL.type :Kernel, 'self.autoload', '(String or Symbol module, String filename) -> nil' 25 | RDL.type :Kernel, 'self.autoload?', '(Symbol or String name) -> String or nil' 26 | RDL.type :Kernel, 'self.binding', '() -> Binding' 27 | RDL.type :Kernel, 'self.block_given?', '() -> %bool' 28 | RDL.type :Kernel, 'self.caller', '(?Integer start, ?Integer length) -> Array or nil' 29 | RDL.type :Kernel, 'self.caller', '(Range) -> Array or nil' 30 | RDL.type :Kernel, 'self.caller_locations', '(?Integer start, ?Integer length) -> Array or nil' 31 | RDL.type :Kernel, 'self.caller_locations', '(Range) -> Array or nil' 32 | # RDL.type :Kernel, 'self.catch' # TODO 33 | RDL.type :Kernel, 'self.eval', '(String, ?Binding, ?String filename, ?Integer lineno) -> %any' 34 | # RDL.type :Kernel, 'self.exec' #TODO 35 | RDL.type :Kernel, 'self.exit', '() -> %bot' 36 | RDL.type :Kernel, 'self.exit', '(Integer or %bool status) -> %bot' 37 | RDL.type :Kernel, 'self.exit!', '(Integer or %bool status) -> %bot' 38 | RDL.type :Kernel, 'self.fail', '() -> %bot' 39 | RDL.type :Kernel, 'self.fail', '(String) -> %bot' 40 | RDL.type :Kernel, 'self.fail', '(Class, Array) -> %bot' 41 | RDL.type :Kernel, 'self.fail', '(Class, String, Array) -> %bot' 42 | # RDL.type :Kernel, 'self.fail', '(String or [exception : () -> String], ?String, ?Array) -> %any' 43 | # RDL.type :Kernel, 'self.fork' #TODO 44 | RDL.type :Kernel, 'self.format', '(String format, *%any args) -> String' 45 | RDL.type :Kernel, 'self.gets', '(?String, ?Integer) -> String' 46 | RDL.type :Kernel, 'self.global_variables', '() -> Array' 47 | RDL.type :Kernel, 'self.iterator?', '() -> %bool' 48 | # RDL.type :Kernel, 'self.lambda' # TODO 49 | RDL.type :Kernel, 'self.load', '(String filename, ?%bool) -> %bool' 50 | RDL.type :Kernel, 'self.local_variables', '() -> Array' 51 | # RDL.type :Kernel, 'self.loop' #TODO 52 | RDL.type :Kernel, 'self.open', '(String path, ?(String or Integer) mode, ?String perm) -> IO or nil' 53 | # RDL.type :Kernel, 'self.open', '(String path, mode : ?String, perm: ?String) {(IO) -> %any)} -> %any' # TODO: returns block value 54 | # RDL.type :Kernel, 'self.open', '(String path, mode : ?Integer, perm: ?String) {(IO) -> %any)} -> %any' # TODO: returns block value 55 | # RDL.type :Kernel, 'self.p', '(*[inspect : () -> String]) -> nil' 56 | # RDL.type :Kernel, 'self.print', '(*[to_s : () -> String] -> nil' 57 | RDL.type :Kernel, 'self.printf', '(?IO, ?String, *%any) -> nil' 58 | RDL.type :Kernel, :proc, '() {(*%any) -> %any} -> Proc' # TODO more precise 59 | RDL.type :Kernel, 'self.putc', '(Integer) -> Integer' 60 | RDL.type :Kernel, 'self.puts', '(*[to_s : () -> String]) -> nil' 61 | RDL.type :Kernel, 'self.raise', '() -> %bot' 62 | # RDL.type :Kernel, 'self.raise', '(String or [exception : () -> String], ?String, ?Array) -> %any' 63 | # TODO: above same as fail? 64 | RDL.type :Kernel, 'self.rand', '(Integer or Range max) -> Numeric' 65 | RDL.type :Kernel, 'self.readline', '(?String, ?Integer) -> String' 66 | RDL.type :Kernel, 'self.readlines', '(?String, ?Integer) -> Array' 67 | RDL.type :Kernel, 'self.require', '(String name) -> %bool' 68 | RDL.type :Kernel, 'self.require_relative', '(String name) -> %bool' 69 | RDL.type :Kernel, 'self.select', 70 | '(Array read, ?Array write, ?Array error, ?Integer timeout) -> Array' # TODO: return RDL.type? 71 | # RDL.type :Kernel, 'self.set_trace_func' #TODO 72 | RDL.type :Kernel, 'self.sleep', '(Numeric duration) -> Integer' 73 | # RDL.type :Kernel, 'self.spawn' #TODO 74 | RDL.rdl_alias :Kernel, :sprintf, :format # TODO: are they aliases? 75 | RDL.type :Kernel, 'self.srand', '(Numeric number) -> Numeric' 76 | RDL.type :Kernel, 'self.syscall', '(Integer num, *%any args) -> %any' # TODO : ? 77 | # RDL.type :Kernel, 'self.system' # TODO 78 | RDL.type :Kernel, 'self.test', '(String cmd, String file1, ?String file2) -> %bool or Time' # TODO: better, dependent RDL.type? 79 | # RDL.type :Kernel, 'self.throw' # TODO 80 | # RDL.type :Kernel, 'self.trace_var' # TODO 81 | # RDL.type :Kernel, 'self.trap' # TODO 82 | # RDL.type :Kernel, 'self.untrace_var' # TODO 83 | RDL.type :Kernel, 'self.warn', '(*String msg) -> nil' 84 | RDL.type :Kernel, :clone, '() -> self' 85 | RDL.type :Kernel, :raise, '() -> %bot' 86 | RDL.type :Kernel, :raise, '(String) -> %bot' 87 | RDL.type :Kernel, :raise, '(Class, ?String, ?Array) -> %bot' 88 | RDL.type :Kernel, :raise, '(Exception, ?String, ?Array) -> %bot' 89 | RDL.type :Kernel, :send, '(String or Symbol, *%any) -> %any' 90 | RDL.type :Kernel, :send, '(String or Symbol, *%any) { (*%any) -> %any } -> %any' 91 | -------------------------------------------------------------------------------- /lib/types/core/pathname.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :Pathname 2 | 3 | RDL.type :Pathname, 'self.getwd', '() -> Pathname' 4 | RDL.type :Pathname, 'self.glob', '(String p1, ?String p2) -> Array' 5 | RDL.rdl_alias :Pathname, 'self.pwd', 'self.getwd' 6 | RDL.type :Pathname, :+, '(String or Pathname other) -> Pathname' 7 | RDL.rdl_alias :Pathname, :/, :+ 8 | RDL.type :Pathname, :<=>, '(%any p1) -> -1 or 0 or 1 or nil' 9 | RDL.type :Pathname, :==, '(%any p1) -> %bool' 10 | RDL.type :Pathname, :===, '(%any p1) -> %bool' 11 | RDL.type :Pathname, :absolute?, '() -> %bool' 12 | RDL.type :Pathname, :ascend, '() { (Pathname) -> %any } -> %any' 13 | RDL.type :Pathname, :atime, '() -> Time' 14 | RDL.type :Pathname, :basename, '(?String p1) -> Pathname' # guessing about arg RDL.type 15 | RDL.type :Pathname, :binread, '(?Integer length, ?Integer offset) -> String' 16 | RDL.type :Pathname, :binwrite, '(String, ?Integer offset) -> Integer' # TODO open_args 17 | RDL.type :Pathname, :birthtime, '() -> Time' 18 | RDL.type :Pathname, :blockdev?, '() -> %bool' 19 | RDL.type :Pathname, :chardev?, '() -> %bool' 20 | RDL.type :Pathname, :children, '(%bool with_directory) -> Array' 21 | RDL.type :Pathname, :chmod, '(Integer mode) -> Integer' 22 | RDL.type :Pathname, :chown, '(Integer owner, Integer group) -> Integer' 23 | RDL.type :Pathname, :cleanpath, '(?%bool consider_symlink) -> %any' 24 | RDL.type :Pathname, :ctime, '() -> Time' 25 | RDL.type :Pathname, :delete, '() -> %any' 26 | RDL.type :Pathname, :descend, '() { (Pathname) -> %any } -> %any' 27 | RDL.type :Pathname, :directory?, '() -> %bool' 28 | RDL.type :Pathname, :dirname, '() -> Pathname' 29 | RDL.type :Pathname, :each_child, '(%bool with_directory) { (Pathname) -> %any } -> %any' 30 | RDL.type :Pathname, :each_entry, '() { (Pathname) -> %any } -> %any' 31 | RDL.type :Pathname, :each_filename, '() { (String) -> %any } -> %any' 32 | RDL.type :Pathname, :each_filename, '() -> Enumerator' 33 | RDL.type :Pathname, :each_line, '(?String sep, ?Integer limit) { (String) -> %any } -> %any' # TODO open_args 34 | RDL.type :Pathname, :each_line, '(?String sep, ?Integer limit) -> Enumerator' 35 | RDL.type :Pathname, :entries, '() -> Array' 36 | RDL.type :Pathname, :eql?, '(%any) -> %bool' 37 | RDL.type :Pathname, :executable?, '() -> %bool' 38 | RDL.type :Pathname, :executable_real?, '() -> %bool' 39 | RDL.type :Pathname, :exist?, '() -> %bool' 40 | RDL.type :Pathname, :expand_path, '(?(String or Pathname) p1) -> Pathname' 41 | RDL.type :Pathname, :extname, '() -> String' 42 | RDL.type :Pathname, :file?, '() -> %bool' 43 | RDL.type :Pathname, :find, '(%bool ignore_error) { (Pathname) -> %any } -> %any' 44 | RDL.type :Pathname, :find, '(%bool ignore_error) -> Enumerator' 45 | RDL.type :Pathname, :fnmatch, '(String pattern, ?Integer flags) -> %bool' 46 | RDL.type :Pathname, :freeze, '() -> self' # TODO return RDL.type? 47 | RDL.type :Pathname, :ftype, '() -> String' 48 | RDL.type :Pathname, :grpowned?, '() -> %bool' 49 | #RDL.type :Pathname, :initialize, '(%string or Pathname p1) -> self' # p1 can be String-like 50 | RDL.type :Pathname, :join, '(*(String or Pathname) args) -> Pathname' 51 | RDL.type :Pathname, :lchmod, '(Integer mode) -> Integer' 52 | RDL.type :Pathname, :lchown, '(Integer owner, Integer group) -> Integer' 53 | RDL.type :Pathname, :lstat, '() -> File::Stat' 54 | RDL.type :Pathname, :make_link, '(String old) -> 0' 55 | RDL.type :Pathname, :symlink, '(String old) -> 0' 56 | RDL.type :Pathname, :mkdir, '(String p1) -> 0' 57 | RDL.type :Pathname, :mkpath, '() -> %any' # TODO return? 58 | RDL.type :Pathname, :mountpoint?, '() -> %bool' 59 | RDL.type :Pathname, :mtime, '() -> Time' 60 | RDL.type :Pathname, :open, '(?String mode, ?String perm, ?Integer opt) -> File' 61 | RDL.type :Pathname, :open, '(?String mode, ?String perm, ?Integer opt) { (File) -> t } -> t' 62 | RDL.type :Pathname, :opendir, '(?Encoding) -> Dir' 63 | RDL.type :Pathname, :opendir, '(?Encoding) { (Dir) -> u } -> u' 64 | RDL.type :Pathname, :owned?, '() -> %bool' 65 | RDL.type :Pathname, :parent, '() -> Pathname' 66 | RDL.type :Pathname, :pipe?, '() -> %bool' 67 | RDL.type :Pathname, :read, '(?Integer length, ?Integer offset, ?Integer open_args) -> String' 68 | RDL.type :Pathname, :readable?, '() -> %bool' 69 | RDL.type :Pathname, :readable_real, '() -> %bool' 70 | RDL.type :Pathname, :readlines, '(?String sep, ?Integer limit, ?Integer open_args) -> Array' 71 | RDL.type :Pathname, :readlink, '() -> String file' 72 | RDL.type :Pathname, :realdirpath, '(?String p1) -> String' 73 | RDL.type :Pathname, :realpath, '(?String p1) -> String' 74 | RDL.type :Pathname, :relative?, '() -> %bool' 75 | RDL.type :Pathname, :relative_path_from, '(String or Pathname base_directory) -> Pathname' 76 | RDL.type :Pathname, :rename, '(String p1) -> 0' 77 | RDL.type :Pathname, :rmdir, '() -> 0' 78 | RDL.type :Pathname, :rmtree, '() -> 0' 79 | RDL.type :Pathname, :root?, '() -> %bool' 80 | RDL.type :Pathname, :setgid?, '() -> %bool' 81 | RDL.type :Pathname, :setuid?, '() -> %bool' 82 | RDL.type :Pathname, :size, '() -> Integer' 83 | RDL.type :Pathname, :size?, '() -> %bool' 84 | RDL.type :Pathname, :socket?, '() -> %bool' 85 | RDL.type :Pathname, :split, '() -> [Pathname, Pathname]' 86 | RDL.type :Pathname, :stat, '() -> File::Stat' 87 | RDL.type :Pathname, :sticky?, '() -> %bool' 88 | RDL.type :Pathname, :sub, '(*String args) -> Pathname' 89 | RDL.type :Pathname, :sub_ext, '(String p1) -> Pathname' 90 | RDL.type :Pathname, :symlink?, '() -> %bool' 91 | RDL.type :Pathname, :sysopen, '(?Integer mode, ?Integer perm) -> Integer' 92 | RDL.type :Pathname, :taint, '() -> self' 93 | RDL.type :Pathname, :to_path, '() -> String' 94 | RDL.rdl_alias :Pathname, :to_s, :to_path 95 | RDL.type :Pathname, :truncate, '(Integer length) -> 0' 96 | RDL.type :Pathname, :unlink, '() -> Integer' 97 | RDL.type :Pathname, :untaint, '() -> self' 98 | RDL.type :Pathname, :utime, '(Time atime, Time mtime) -> Integer' 99 | RDL.type :Pathname, :world_readable?, '() -> %bool' 100 | RDL.type :Pathname, :world_writable?, '() -> %bool' 101 | RDL.type :Pathname, :writable?, '() -> %bool' 102 | RDL.type :Pathname, :writable_real?, '() -> %bool' 103 | RDL.type :Pathname, :write, '(String, ?Integer offset, ?Integer open_args) -> Integer' 104 | RDL.type :Pathname, :zero?, '() -> %bool' 105 | -------------------------------------------------------------------------------- /lib/rdl/boot.rb: -------------------------------------------------------------------------------- 1 | require 'delegate' 2 | require 'digest' 3 | require 'set' 4 | require 'parser/current' 5 | 6 | module RDL 7 | end 8 | 9 | require 'rdl/config.rb' 10 | def RDL.config 11 | yield(RDL::Config.instance) 12 | end 13 | require 'rdl/info.rb' 14 | 15 | module RDL::Globals 16 | # Method/variable info table with kinds: 17 | # For methods 18 | # :pre to array of precondition contracts 19 | # :post to array of postcondition contracts 20 | # :type to array of types 21 | # :source_location to [filename, linenumber] location of most recent definition 22 | # :typecheck - boolean that is true if method should be statically type checked 23 | # :otype to set of types that were observed at run time, where a type is a finite hash {:args => Array, :ret => Class, :block => %bool} 24 | # :context_types to array of [klass, meth, Type] - method types that exist only within this method. An icky hack to deal with Rails `params`. 25 | # For variables 26 | # :type to type 27 | @info = RDL::Info.new 28 | 29 | # Map from full_method_name to number of times called when wrapped 30 | @wrapped_calls = Hash.new 0 31 | 32 | # Hash from class name to array of symbols that are the class's type parameters 33 | @type_params = Hash.new 34 | 35 | # Hash from class name to method name to its alias method name 36 | # class names are strings 37 | # method names are symbols 38 | @aliases = Hash.new 39 | 40 | # Set of [class, method] pairs to wrap. 41 | # class is a string 42 | # method is a symbol 43 | @to_wrap = Set.new 44 | 45 | # Map from symbols to set of [class, method] pairs to type check when those symbols are rdl_do_typecheck'd 46 | # (or the methods are defined, for the symbol :now) 47 | @to_typecheck = Hash.new 48 | @to_typecheck[:now] = Set.new 49 | 50 | # Map from symbols to Array where the Procs are called when those symbols are rdl_do_typecheck'd 51 | @to_do_at = Hash.new 52 | 53 | # List of contracts that should be applied to the next method definition 54 | @deferred = [] 55 | end 56 | 57 | class << RDL::Globals # add accessors and readers for module variables 58 | attr_accessor :info 59 | attr_accessor :wrapped_calls 60 | attr_accessor :type_params 61 | attr_reader :aliases 62 | attr_accessor :to_wrap 63 | attr_accessor :to_typecheck 64 | attr_accessor :to_do_at 65 | attr_accessor :deferred 66 | end 67 | 68 | # Create switches to control whether wrapping happens and whether 69 | # contracts are checked. These need to be created before rdl/wrap.rb 70 | # is loaded. 71 | require 'rdl/switch.rb' 72 | module RDL::Globals 73 | @wrap_switch = RDL::Switch.new 74 | @contract_switch = RDL::Switch.new 75 | end 76 | 77 | class << RDL::Globals 78 | attr_reader :wrap_switch 79 | attr_reader :contract_switch 80 | end 81 | 82 | require 'rdl/types/type.rb' 83 | require 'rdl/types/annotated_arg.rb' 84 | require 'rdl/types/bot.rb' 85 | require 'rdl/types/computed.rb' 86 | require 'rdl/types/dependent_arg.rb' 87 | require 'rdl/types/dots_query.rb' 88 | require 'rdl/types/finite_hash.rb' 89 | require 'rdl/types/generic.rb' 90 | require 'rdl/types/intersection.rb' 91 | require 'rdl/types/lexer.rex.rb' 92 | require 'rdl/types/method.rb' 93 | require 'rdl/types/singleton.rb' 94 | require 'rdl/types/ast_node.rb' 95 | require 'rdl/types/nominal.rb' 96 | require 'rdl/types/non_null.rb' 97 | require 'rdl/types/optional.rb' 98 | require 'rdl/types/parser.tab.rb' 99 | require 'rdl/types/structural.rb' 100 | require 'rdl/types/top.rb' 101 | require 'rdl/types/tuple.rb' 102 | require 'rdl/types/type_query.rb' 103 | require 'rdl/types/union.rb' 104 | require 'rdl/types/var.rb' 105 | require 'rdl/types/vararg.rb' 106 | require 'rdl/types/wild_query.rb' 107 | 108 | require 'rdl/contracts/contract.rb' 109 | require 'rdl/contracts/and.rb' 110 | require 'rdl/contracts/flat.rb' 111 | require 'rdl/contracts/or.rb' 112 | require 'rdl/contracts/proc.rb' 113 | 114 | require 'rdl/util.rb' 115 | require 'rdl/wrap.rb' 116 | require 'rdl/query.rb' 117 | require 'rdl/typecheck.rb' 118 | #require_relative 'rdl/stats.rb' 119 | 120 | module RDL::Globals 121 | FIXBIG_VERSIONS = ['>= 2.0.0', '< 2.4.0'] 122 | # INTEGER_VERSIONS = '>= 2.4.0' 123 | 124 | @parser = RDL::Type::Parser.new 125 | 126 | # Map from file names to [digest, cache] where 2nd elt maps 127 | # :ast to the AST 128 | # :line_defs maps linenumber to AST for def at that line 129 | @parser_cache = Hash.new 130 | 131 | # Some generally useful types; not really a big deal to do this since 132 | # NominalTypes are cached, but these names are shorter to type 133 | @types = Hash.new 134 | @types[:nil] = RDL::Type::NominalType.new NilClass # actually creates singleton type 135 | @types[:top] = RDL::Type::TopType.new 136 | @types[:bot] = RDL::Type::BotType.new 137 | @types[:object] = RDL::Type::NominalType.new Object 138 | @types[:true] = RDL::Type::NominalType.new TrueClass # actually creates singleton type 139 | @types[:false] = RDL::Type::NominalType.new FalseClass # also singleton type 140 | @types[:bool] = RDL::Type::UnionType.new(@types[:true], @types[:false]) 141 | @types[:float] = RDL::Type::NominalType.new Float 142 | @types[:complex] = RDL::Type::NominalType.new Complex 143 | @types[:rational] = RDL::Type::NominalType.new Rational 144 | @types[:integer] = RDL::Type::NominalType.new Integer 145 | @types[:numeric] = RDL::Type::NominalType.new Numeric 146 | @types[:string] = RDL::Type::NominalType.new String 147 | @types[:array] = RDL::Type::NominalType.new Array 148 | @types[:hash] = RDL::Type::NominalType.new Hash 149 | @types[:symbol] = RDL::Type::NominalType.new Symbol 150 | @types[:range] = RDL::Type::NominalType.new Range 151 | @types[:regexp] = RDL::Type::NominalType.new Regexp 152 | @types[:standard_error] = RDL::Type::NominalType.new StandardError 153 | @types[:proc] = RDL::Type::NominalType.new Proc 154 | 155 | # Hash from special type names to their values 156 | @special_types = {'%any' => @types[:top], 157 | '%bot' => @types[:bot], 158 | '%bool' => @types[:bool]} 159 | end 160 | 161 | class << RDL::Globals 162 | attr_reader :parser 163 | attr_accessor :parser_cache 164 | attr_reader :types 165 | attr_reader :special_types 166 | end 167 | -------------------------------------------------------------------------------- /lib/types/core/io.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :IO # Do not wrap this class. Leads to mysterious errors. 2 | 3 | RDL.type :IO, :initialize, '(Integer fd, ?Integer mode, ?Integer opt) -> self' 4 | RDL.type :IO, 'self.binread', '(String name, ?Integer length, ?Integer offset) -> String' 5 | RDL.type :IO, 'self.binwrite', '(String name, String, ?Integer offset, %open_args) -> Integer' 6 | RDL.type :IO, 'self.copy_stream', '(String or IO src, String or IO dst, ?Integer copy_length, ?Integer src_offset) -> Integer' 7 | RDL.rdl_alias :IO, 'self.for_fd', 'initialize' 8 | RDL.type :IO, 'self.foreach', '(String name, ?String sep, ?Integer limit, %open_args) { (String) -> %any } -> nil' 9 | RDL.type :IO, 'self.foreach', '(String name, ?String sep, ?Integer limit, %open_args) -> Enumerator' 10 | RDL.type :IO, 'self.open', '(Integer fd, ?String mode, %open_args) -> IO' 11 | RDL.type :IO, 'self.open', '(Integer fd, ?String mode, %open_args) { (IO) -> t } -> t' 12 | RDL.type :IO, 'self.pipe', '(?String ext_or_ext_int_enc, %open_args) -> [IO, IO]' 13 | RDL.type :IO, 'self.pipe', '(?String ext_enc, ?String int_enc, %open_args) -> [IO, IO]' 14 | RDL.type :IO, 'self.pipe', '(?String ext_or_ext_int_enc, %open_args) { ([IO, IO]) -> t } -> t' 15 | RDL.type :IO, 'self.pipe', '(?String ext_enc, ?String int_enc, %open_args) { ([IO, IO]) -> t } -> t' 16 | RDL.type :IO, 'self.popen', '(?Hash env, String cmd, ?String mode, %open_args) -> IO' 17 | RDL.type :IO, 'self.popen', '(?Hash env, String cmd, ?String mode, %open_args) { (IO) -> t } -> t' 18 | RDL.type :IO, 'self.read', '(String name, ?Integer length, ?Integer offset, %open_args) -> String' 19 | RDL.type :IO, 'self.readlines', '(String name, ?String sep, ?Integer limit, %open_args) -> Array' 20 | RDL.type :IO, 'self.select', '(Array read_array, ?Array write_array, ?Array error_array, ?Integer timeout) -> Array or nil' 21 | RDL.type :IO, 'self.sysopen', '(String path, ?String mode, ?String perm) -> Integer' # TODO unsure of RDL.type of perm 22 | RDL.type :IO, 'self.try_convert', '([to_io: () -> IO]) -> IO or nil' 23 | RDL.type :IO, 'self.write', '(String name, String, ?Integer offset, %open_args) -> Integer' 24 | RDL.type :IO, :<<, '([to_s: () -> String]) -> self' 25 | RDL.type :IO, :advise, '(:normal or :sequence or :random or :willneed or :dontneed or :noreuse, ?Integer offset, ?Integer len) -> nil' 26 | RDL.type :IO, :autoclose=, '(%bool) -> %bool' 27 | RDL.type :IO, :autoclose?, '() -> %bool' 28 | RDL.type :IO, :binmode, '() -> self' 29 | RDL.type :IO, :binmode?, '() -> %bool' 30 | RDL.rdl_alias :IO, :bytes, :each_byte # deprecated 31 | RDL.rdl_alias :IO, :chars, :each_char # deprecated 32 | RDL.type :IO, :close, '() -> nil' 33 | RDL.type :IO, :close_on_exec=, '(%bool) -> %bool' 34 | RDL.type :IO, :close_on_exec?, '() -> %bool' 35 | RDL.type :IO, :close_read, '() -> nil' 36 | RDL.type :IO, :close_write, '() -> nil' 37 | RDL.type :IO, :closed?, '() -> %bool' 38 | RDL.rdl_alias :IO, :codepoints, :each_codepoint # deprecated 39 | RDL.type :IO, :each, '(?String sep, ?Integer limit) { (String) -> %any } -> self' 40 | RDL.type :IO, :each, '(?String sep, ?Integer limit) -> Enumerator' 41 | RDL.rdl_alias :IO, :each_line, :each 42 | RDL.type :IO, :each_byte, '() { (Integer) -> %any } -> self' 43 | RDL.type :IO, :each_byte, '() -> Enumerator' 44 | RDL.type :IO, :each_char, '() { (String) -> %any } -> self' 45 | RDL.type :IO, :each_char, '() -> Enumerator' 46 | RDL.type :IO, :each_codepoint, '() { (Integer) -> %any } -> self' 47 | RDL.type :IO, :each_codepoint, '() -> Enumerator' 48 | RDL.type :IO, :eof, '() -> %bool' 49 | RDL.rdl_alias :IO, :eof?, :eof 50 | RDL.type :IO, :external_enconding, '() -> Enconding' 51 | RDL.type :IO, :fcntl, '(Integer integer_cmd, String or Integer arg) -> Integer' 52 | RDL.type :IO, :fdatasync, '() -> 0 or nil' 53 | RDL.type :IO, :fileno, '() -> Integer' 54 | RDL.type :IO, :flush, '() -> self' 55 | RDL.type :IO, :fsync, '() -> 0 or nil' 56 | RDL.type :IO, :getbyte, '() -> Integer or nil' 57 | RDL.type :IO, :getc, '() -> String or nil' 58 | RDL.type :IO, :gets, '(?String sep, ?Integer limit) -> String or nil' 59 | RDL.type :IO, :inspect, '() -> String' 60 | RDL.type :IO, :internal_encoding, '() -> Encoding' 61 | RDL.type :IO, :ioctl, '(Integer integer_cmd, String or Integer arg) -> Integer' 62 | RDL.type :IO, :isatty, '() -> %bool' 63 | RDL.type :IO, :lineno, '() -> Integer' 64 | RDL.type :IO, :lineno=, '(Integer) -> Integer' 65 | RDL.rdl_alias :IO, :lines, :each_line # deprecated 66 | RDL.type :IO, :pid, '() -> Integer' 67 | RDL.type :IO, :pos, '() -> Integer' 68 | RDL.type :IO, :pos=, '(Integer) -> Integer' 69 | RDL.type :IO, :print, '(*[to_s: () -> String]) -> nil' 70 | RDL.type :IO, :printf, '(String format_string, *%any) -> nil' 71 | RDL.type :IO, :putc, '(Numeric or String) -> %any' 72 | RDL.type :IO, :puts, '(*[to_s: () -> String]) -> nil' 73 | RDL.type :IO, :read, '(?Integer length, ?String outbuf) -> String or nil' 74 | RDL.type :IO, :read_nonblock, '(Integer maxlen) -> String' 75 | RDL.type :IO, :read_nonblock, '(Integer maxlen, String outbuf) -> String outbuf' 76 | RDL.type :IO, :readbyte, '() -> Integer' 77 | RDL.type :IO, :readchar, '() -> String' 78 | RDL.type :IO, :readline, '(?String sep, ?Integer limit) -> String' 79 | RDL.type :IO, :readlines, '(?String sep, ?Integer limit) -> Array' 80 | RDL.type :IO, :readpartial, '(Integer maxlen) -> String' 81 | RDL.type :IO, :readpartial, '(Integer maxlen, String outbuf) -> String outbuf' 82 | RDL.type :IO, :reopen, '(IO other_IO) -> IO' 83 | RDL.type :IO, :reopen, '(String path, String mode_str) -> IO' 84 | RDL.type :IO, :rewrind, '() -> 0' 85 | RDL.type :IO, :seek, '(Integer amount, ?Integer whence) -> 0' 86 | RDL.type :IO, :set_encoding, '(?String or Encoding ext_or_ext_int_enc) -> self' 87 | RDL.type :IO, :set_encoding, '(?String or Encoding ext_enc, ?String or Encoding int_enc) -> self' 88 | RDL.type :IO, :stat, '() -> File::Stat' 89 | RDL.type :IO, :sync, '() -> %bool' 90 | RDL.type :IO, :sync=, '(%bool) -> %bool' 91 | RDL.type :IO, :sysread, '(Integer maxlen, String outbuf) -> String' 92 | RDL.type :IO, :sysseek, '(Integer amount, ?Integer whence) -> Integer' 93 | RDL.type :IO, :syswrite, '(String) -> Integer' 94 | RDL.type :IO, :tell, '() -> Integer' 95 | RDL.rdl_alias :IO, :to_i, :fileno 96 | RDL.type :IO, :to_io, '() -> self' 97 | RDL.type :IO, :tty?, '() -> %bool' 98 | RDL.type :IO, :ungetbyte, '(String or Integer) -> nil' 99 | RDL.type :IO, :ungetc, '(String) -> nil' 100 | RDL.type :IO, :write, '(String) -> Integer' 101 | RDL.type :IO, :write_nonbloc, '(String, ?Integer options) -> Integer' 102 | -------------------------------------------------------------------------------- /test/test_query.rb: -------------------------------------------------------------------------------- 1 | require 'minitest/autorun' 2 | $LOAD_PATH << File.dirname(__FILE__) + "/../lib" 3 | require 'rdl' 4 | 5 | class TestQuery < Minitest::Test 6 | include RDL::Type 7 | 8 | def setup 9 | @p = Parser.new 10 | @tinteger = NominalType.new Integer 11 | @tarray = NominalType.new Array 12 | @qwild = WildQuery.new 13 | @qwildopt = OptionalType.new @qwild 14 | @qwildvararg = VarargType.new @qwild 15 | @qwildx = AnnotatedArgType.new("x", @qwild) 16 | @qdots = DotsQuery.new 17 | end 18 | 19 | def test_parse 20 | q1 = @p.scan_str "#Q (.) -> ." 21 | assert_equal (MethodType.new [@qwild], nil, @qwild), q1 22 | q2 = @p.scan_str "#Q (., Integer) -> Integer" 23 | assert_equal (MethodType.new [@qwild, @tinteger], nil, @tinteger), q2 24 | q3 = @p.scan_str "#Q (Integer, ?.) -> Integer" 25 | assert_equal (MethodType.new [@tinteger, @qwildopt], nil, @tinteger), q3 26 | q4 = @p.scan_str "#Q (*.) -> Integer" 27 | assert_equal (MethodType.new [@qwildvararg], nil, @tinteger), q4 28 | q5 = @p.scan_str "#Q (. or Integer) -> Integer" 29 | assert_equal (MethodType.new [UnionType.new(@qwild, @tinteger)], nil, @tinteger), q5 30 | q6 = @p.scan_str "#Q (. x, Integer) -> Integer" 31 | assert_equal (MethodType.new [@qwildx, @tinteger], nil, @tinteger), q6 32 | q7 = @p.scan_str "#Q (Array<.>) -> Integer" 33 | assert_equal (MethodType.new [GenericType.new(@tarray, @qwild)], nil, @tinteger), q7 34 | # q8 = @p.scan_str "#Q (.) -> Integer" 35 | # assert_equal (MethodType.new [GenericType.new(@twild, @tinteger)], nil, @tinteger), q8 36 | q9 = @p.scan_str "#Q ([Integer, .]) -> Integer" 37 | assert_equal (MethodType.new [TupleType.new(@tinteger, @qwild)], nil, @tinteger), q9 38 | q10 = @p.scan_str "#Q ([to_str: () -> .]) -> Integer" 39 | assert_equal (MethodType.new [StructuralType.new(to_str: (MethodType.new [], nil, @qwild))], nil, @tinteger), q10 40 | q11 = @p.scan_str "#Q ({a: Integer, b: .}) -> Integer" 41 | assert_equal (MethodType.new [FiniteHashType.new({a: @tinteger, b: @qwild}, nil)], nil, @tinteger), q11 42 | q12 = @p.scan_str "#Q (Integer, x: .) -> Integer" 43 | assert_equal (MethodType.new [@tinteger, FiniteHashType.new({x: @qwild}, nil)], nil, @tinteger), q12 44 | q13 = @p.scan_str "#Q (Integer, ..., Integer) -> Integer" 45 | assert_equal (MethodType.new [@tinteger, @qdots, @tinteger], nil, @tinteger), q13 46 | q14 = @p.scan_str "#Q (Integer, ...) -> Integer" 47 | assert_equal (MethodType.new [@tinteger, @qdots], nil, @tinteger), q14 48 | q15 = @p.scan_str "#Q (...) -> Integer" 49 | assert_equal (MethodType.new [@qdots], nil, @tinteger), q15 50 | end 51 | 52 | def test_match 53 | t1 = @p.scan_str "(Integer, Integer) -> Integer" 54 | assert (@p.scan_str "#Q (Integer, Integer) -> Integer").match(t1) 55 | assert (@p.scan_str "#Q (., .) -> .").match(t1) 56 | assert (@p.scan_str "#Q (..., Integer) -> Integer").match(t1) 57 | assert (@p.scan_str "#Q (Integer, ...) -> Integer").match(t1) 58 | assert (@p.scan_str "#Q (...) -> Integer").match(t1) 59 | assert (not (@p.scan_str "#Q (Integer, String) -> Integer").match(t1)) 60 | assert (not (@p.scan_str "#Q (String, Integer) -> Integer").match(t1)) 61 | assert (not (@p.scan_str "#Q (Integer, String) -> String").match(t1)) 62 | assert (not (@p.scan_str "#Q (..., String) -> String").match(t1)) 63 | assert (not (@p.scan_str "#Q (String, ...) -> String").match(t1)) 64 | t2 = @p.scan_str "(String or Integer) -> Integer" 65 | assert (@p.scan_str "#Q (String or Integer) -> Integer").match(t2) 66 | assert (@p.scan_str "#Q (String or .) -> Integer").match(t2) 67 | assert (@p.scan_str "#Q (. or Integer) -> Integer").match(t2) 68 | assert (@p.scan_str "#Q (Integer or String) -> Integer").match(t2) 69 | assert (@p.scan_str "#Q (Integer or .) -> Integer").match(t2) 70 | assert (@p.scan_str "#Q (. or String) -> Integer").match(t2) 71 | t3 = @p.scan_str "(Array) -> Integer" 72 | assert (@p.scan_str "#Q (Array) -> Integer").match(t3) 73 | assert (@p.scan_str "#Q (Array<.>) -> Integer").match(t3) 74 | t4 = @p.scan_str "([Integer, String]) -> Integer" 75 | assert (@p.scan_str "#Q ([Integer, String]) -> Integer").match(t4) 76 | assert (@p.scan_str "#Q ([Integer, .]) -> Integer").match(t4) 77 | assert (@p.scan_str "#Q ([., String]) -> Integer").match(t4) 78 | t5 = @p.scan_str "([to_str: () -> Integer]) -> Integer" 79 | assert (@p.scan_str "#Q ([to_str: () -> Integer]) -> Integer").match(t5) 80 | assert (@p.scan_str "#Q ([to_str: () -> .]) -> Integer").match(t5) 81 | t6 = @p.scan_str "(Integer, ?Integer) -> Integer" 82 | assert (@p.scan_str "#Q (Integer, ?Integer) -> Integer").match(t6) 83 | assert (@p.scan_str "#Q (Integer, ?.) -> Integer").match(t6) 84 | assert (@p.scan_str "#Q (Integer, .) -> Integer").match(t6) 85 | t7 = @p.scan_str "(*Integer) -> Integer" 86 | assert (@p.scan_str "#Q (*Integer) -> Integer").match(t7) 87 | assert (@p.scan_str "#Q (*.) -> Integer").match(t7) 88 | assert (@p.scan_str "#Q (.) -> Integer").match(t7) 89 | t8 = @p.scan_str "({a: Integer, b: String}) -> Integer" 90 | assert (@p.scan_str "#Q ({a: Integer, b: String}) -> Integer").match(t8) 91 | assert (@p.scan_str "#Q ({a: Integer, b: .}) -> Integer").match(t8) 92 | assert (@p.scan_str "#Q ({a: ., b: String}) -> Integer").match(t8) 93 | assert (@p.scan_str "#Q ({a: ., b: .}) -> Integer").match(t8) 94 | assert (@p.scan_str "#Q ({b: String, a: Integer}) -> Integer").match(t8) 95 | assert (@p.scan_str "#Q ({b: ., a: Integer}) -> Integer").match(t8) 96 | assert (@p.scan_str "#Q ({b: String, a: .}) -> Integer").match(t8) 97 | assert (@p.scan_str "#Q ({b: ., a: .}) -> Integer").match(t8) 98 | assert (@p.scan_str "#Q (.) -> Integer").match(t8) 99 | t9 = @p.scan_str "(Integer, x: String) -> Integer" 100 | assert (@p.scan_str "#Q (Integer, x: String) -> Integer").match(t9) 101 | assert (@p.scan_str "#Q (Integer, x: .) -> Integer").match(t9) 102 | assert (@p.scan_str "#Q (Integer, .) -> Integer").match(t9) 103 | t10 = @p.scan_str "(String x, Integer) -> Integer" 104 | assert (@p.scan_str "#Q (String x, Integer) -> Integer").match(t10) 105 | assert (@p.scan_str "#Q (. x, Integer) -> Integer").match(t10) 106 | assert (@p.scan_str "#Q (String, Integer) -> Integer").match(t10) 107 | assert (@p.scan_str "#Q (., Integer) -> Integer").match(t10) 108 | t11 = @p.scan_str "(Integer, x: String, **Float) -> Integer" 109 | assert (@p.scan_str "#Q (Integer, x: String, **Float) -> Integer").match(t11) 110 | assert (@p.scan_str "#Q (Integer, x: String, **.) -> Integer").match(t11) 111 | end 112 | end 113 | -------------------------------------------------------------------------------- /test/test_member.rb: -------------------------------------------------------------------------------- 1 | require 'minitest/autorun' 2 | $LOAD_PATH << File.dirname(__FILE__) + "/../lib" 3 | require 'rdl' 4 | 5 | class TestMember < Minitest::Test 6 | include RDL::Type 7 | 8 | class A 9 | end 10 | 11 | class B < A 12 | end 13 | 14 | class C < B 15 | end 16 | 17 | def setup 18 | @tbasicobject = NominalType.new "BasicObject" 19 | @tsymfoo = SingletonType.new :foo 20 | @tarraystring = GenericType.new(RDL::Globals.types[:array], RDL::Globals.types[:string]) 21 | @tarrayobject = GenericType.new(RDL::Globals.types[:array], RDL::Globals.types[:object]) 22 | @tarrayarraystring = GenericType.new(RDL::Globals.types[:array], @tarraystring) 23 | @tarrayarrayobject = GenericType.new(RDL::Globals.types[:array], @tarrayobject) 24 | RDL::Globals.types[:hash] = NominalType.new Hash 25 | @thashstringstring = GenericType.new(RDL::Globals.types[:hash], RDL::Globals.types[:string], RDL::Globals.types[:string]) 26 | @thashobjectobject = GenericType.new(RDL::Globals.types[:hash], RDL::Globals.types[:object], RDL::Globals.types[:object]) 27 | @tstring_or_sym = UnionType.new(RDL::Globals.types[:string], RDL::Globals.types[:symbol]) 28 | @tstring_and_sym = IntersectionType.new(RDL::Globals.types[:string], RDL::Globals.types[:symbol]) 29 | @tobject_and_basicobject = IntersectionType.new(RDL::Globals.types[:object], @tbasicobject) 30 | @ta = NominalType.new A 31 | @tb = NominalType.new B 32 | @tc = NominalType.new C 33 | @tkernel = NominalType.new Kernel 34 | @tavar = VarType.new :a 35 | end 36 | 37 | def test_nil 38 | assert (RDL::Globals.types[:nil].member? nil) 39 | assert (not (RDL::Globals.types[:nil].member? "foo")) 40 | assert (not (RDL::Globals.types[:nil].member? (Object.new))) 41 | end 42 | 43 | def test_top 44 | assert (RDL::Globals.types[:top].member? nil) 45 | assert (RDL::Globals.types[:top].member? "foo") 46 | assert (RDL::Globals.types[:top].member? (Object.new)) 47 | end 48 | 49 | def test_nominal 50 | o = Object.new 51 | assert (RDL::Globals.types[:string].member? "Foo") 52 | assert (not (RDL::Globals.types[:string].member? :Foo)) 53 | assert (not (RDL::Globals.types[:string].member? o)) 54 | 55 | assert (RDL::Globals.types[:object].member? "Foo") 56 | assert (RDL::Globals.types[:object].member? :Foo) 57 | assert (RDL::Globals.types[:object].member? o) 58 | 59 | assert (@tkernel.member? "Foo") 60 | assert (@tkernel.member? :Foo) 61 | assert (@tkernel.member? o) 62 | 63 | a = A.new 64 | b = B.new 65 | c = C.new 66 | assert (@ta.member? a) 67 | assert (@ta.member? b) 68 | assert (@ta.member? c) 69 | assert (not (@tb.member? a)) 70 | assert (@tb.member? b) 71 | assert (@tb.member? c) 72 | assert (not (@tc.member? a)) 73 | assert (not (@tc.member? b)) 74 | assert (@tc.member? c) 75 | 76 | assert (RDL::Globals.types[:string].member? nil) 77 | assert (RDL::Globals.types[:object].member? nil) 78 | end 79 | 80 | def test_symbol 81 | assert (RDL::Globals.types[:symbol].member? :foo) 82 | assert (RDL::Globals.types[:symbol].member? :bar) 83 | assert (not (RDL::Globals.types[:symbol].member? "foo")) 84 | assert (@tsymfoo.member? :foo) 85 | assert (not (@tsymfoo.member? :bar)) 86 | assert (not (@tsymfoo.member? "foo")) 87 | assert (not(@tsymfoo.member? nil)) # nil no longer subtype of other singletons 88 | end 89 | 90 | def test_union_intersection 91 | o = Object.new 92 | 93 | assert (@tstring_or_sym.member? "foo") 94 | assert (@tstring_or_sym.member? :foo) 95 | assert (not (@tstring_or_sym.member? o)) 96 | assert (@tstring_or_sym.member? nil) 97 | 98 | assert (not (@tstring_and_sym.member? "foo")) 99 | assert (not (@tstring_and_sym.member? :foo)) 100 | assert (not (@tstring_and_sym.member? o)) 101 | assert (@tstring_and_sym.member? nil) 102 | 103 | assert (@tobject_and_basicobject.member? o) 104 | assert (@tobject_and_basicobject.member? nil) 105 | end 106 | 107 | def test_var 108 | assert_raises(TypeError) { @tavar.member? "foo" } 109 | end 110 | 111 | def test_tuple 112 | t1 = TupleType.new(RDL::Globals.types[:symbol], RDL::Globals.types[:string]) 113 | assert (t1.member? [:foo, "foo"]) 114 | assert (not (t1.member? ["foo", :foo])) 115 | assert (not (t1.member? [:foo, "foo", "bar"])) 116 | t2 = TupleType.new 117 | assert (t2.member? []) 118 | assert (not (t2.member? [:foo])) 119 | end 120 | 121 | def test_finite_hash 122 | t1 = FiniteHashType.new({a: RDL::Globals.types[:symbol], b: RDL::Globals.types[:string]}, nil) 123 | assert (t1.member?(a: :foo, b: "foo")) 124 | assert (not (t1.member?(a: 1, b: "foo"))) 125 | assert (not (t1.member?(a: :foo))) 126 | assert (not (t1.member?(b: "foo"))) 127 | assert (not (t1.member?(a: :foo, b: "foo", c: :baz))) 128 | t2 = FiniteHashType.new({"a"=>RDL::Globals.types[:symbol], 2=>RDL::Globals.types[:string]}, nil) 129 | assert (t2.member?({"a"=>:foo, 2=>"foo"})) 130 | assert (not (t2.member?({"a"=>2, 2=>"foo"}))) 131 | assert (not (t2.member?({"a"=>:foo}))) 132 | assert (not (t2.member?({2=>"foo"}))) 133 | assert (not (t2.member?({"a"=>:foo, 2=>"foo", 3=>"bar"}))) 134 | t3 = FiniteHashType.new({"a"=>RDL::Globals.types[:symbol], 2=>RDL::Globals.types[:string]}, RDL::Globals.types[:integer]) 135 | assert (t3.member?({"a"=>:foo, 2=>"foo"})) 136 | assert (t3.member?({"a"=>:foo, 2=>"foo", two: 2})) 137 | assert (t3.member?({"a"=>:foo, 2=>"foo", two: 2, three: 3})) 138 | assert (not (t3.member?({"a"=>:foo, 2=>"foo", two: 'two'}))) 139 | assert (not (t3.member?({"a"=>:foo, 2=>"foo", two: 2, three: 'three'}))) 140 | assert (not (t3.member?({"a"=>:foo, two: 2}))) 141 | assert (not (t3.member?({2=>"foo", two: 2}))) 142 | t4 = FiniteHashType.new({a: RDL::Globals.types[:symbol], b: RDL::Globals.types[:string]}, RDL::Globals.types[:integer]) 143 | assert (t4.member?(a: :foo, b: "foo")) 144 | assert (t4.member?(a: :foo, b: "foo", c: 3)) 145 | assert (t4.member?(a: :foo, b: "foo", c: 3, d: 4)) 146 | assert (not (t4.member?(a: :foo, b: "foo", c: "three"))) 147 | t5 = FiniteHashType.new({a: RDL::Globals.types[:symbol], b: OptionalType.new(RDL::Globals.types[:string])}, RDL::Globals.types[:integer]) 148 | assert (t5.member?(a: :foo, b: "foo")) 149 | assert (t5.member?(a: :foo, b: "foo", c: 3)) 150 | assert (t5.member?(a: :foo, b: "foo", c: 3, d: 4)) 151 | assert (not (t5.member?(a: :foo, b: "foo", c: "three"))) 152 | assert (t5.member?(a: :foo)) 153 | assert (t5.member?(a: :foo, c: 3)) 154 | assert (t5.member?(a: :foo, c: 3, d: 4)) 155 | assert (not (t5.member?(a: :foo, c: "three"))) 156 | end 157 | end 158 | -------------------------------------------------------------------------------- /test/test_lib_types.rb: -------------------------------------------------------------------------------- 1 | require 'set' 2 | require 'abbrev' 3 | require 'base64' 4 | require 'benchmark' 5 | require 'bigdecimal' 6 | require 'bigdecimal/math' 7 | require 'coverage.so' 8 | require 'uri' 9 | 10 | require 'minitest/autorun' 11 | $LOAD_PATH << File.dirname(__FILE__) + "/../lib" 12 | require 'rdl' 13 | require 'types/core' 14 | 15 | class Dummy 16 | def self.each 17 | end 18 | def each 19 | end 20 | end 21 | 22 | class TestStdlibTypes < Minitest::Test 23 | 24 | def test_abbrev 25 | skip "Skip when nowrap is enabled" 26 | assert_raises(RDL::Type::TypeError) { Abbrev.abbrev 5} 27 | # From the Ruby stdlib documentation 28 | s1 = Abbrev.abbrev(['ruby']) # -> {"ruby"=>"ruby", "rub"=>"ruby", "ru"=>"ruby", "r"=>"ruby"} 29 | ev = {"ruby"=>"ruby", "rub"=>"ruby", "ru"=>"ruby", "r"=>"ruby"} 30 | assert_equal(s1, ev) 31 | # Other tests 32 | assert_raises(RDL::Type::TypeError) { Abbrev.abbrev Dummy.new } 33 | end 34 | 35 | def test_base64 36 | skip "Skip when nowrap is enabled" 37 | # From the Ruby stdlib documentation 38 | e0 = Base64.encode64('Send reinforcements') # -> "U2VuZCByZWluZm9yY2VtZW50cw==\n" 39 | Base64.decode64(e0) # -> "Send reinforcements" 40 | #assert_equal(e0,d0) 41 | e1 = Base64.strict_encode64('Send reinforcements') 42 | Base64.strict_decode64(e1) 43 | #assert_equal(e1,d1) 44 | e2 = Base64.urlsafe_encode64('Send reinforcements') 45 | Base64.urlsafe_decode64(e2) 46 | #assert_equal(e2,d2) 47 | end 48 | 49 | def test_benchmark 50 | skip "Skip these because they print to stdout" 51 | # From the Ruby stdlib documentation 52 | Benchmark.measure { "a"*1_000_000_000 } 53 | n = 5000000 54 | Benchmark.bm do |x| 55 | x.report { for i in 1..n; a = i; a; end } 56 | x.report { n.times do ; a = "1"; a; end } 57 | x.report { 1.upto(n) do ; a = "1"; a; end } 58 | end 59 | Benchmark.bm(7) do |x| 60 | x.report("for:") { for i in 1..n; a = i; a; end } 61 | x.report("times:") { n.times do ; a = "1"; a; end } 62 | x.report("upto:") { 1.upto(n) do ; a = "1"; a; end } 63 | end 64 | _ = (1..1000000).map { rand } 65 | Benchmark.bmbm do |x| 66 | #x.report("sort!") { array.dup.sort! } # TODO this causes a hang 67 | #x.report("sort") { array.dup.sort } 68 | end 69 | Benchmark.benchmark(Benchmark::CAPTION, 7, Benchmark::FORMAT, ">total:", ">avg:") do |x| 70 | tf = x.report("for:") { for i in 1..n; a = i; a; end } 71 | tt = x.report("times:") { n.times do ; a = "1"; a; end } 72 | tu = x.report("upto:") { 1.upto(n) do ; a = "1"; a; end } 73 | [tf+tt+tu, (tf+tt+tu)/3] 74 | end 75 | end 76 | 77 | def test_bigdecimal 78 | skip "Skip when nowrap is enabled" 79 | # From the RUby stdlib documentation 80 | BigDecimal.save_exception_mode do 81 | BigDecimal.mode(BigDecimal::EXCEPTION_OVERFLOW, false) 82 | BigDecimal.mode(BigDecimal::EXCEPTION_NaN, false) 83 | 84 | BigDecimal.new(BigDecimal('Infinity')) 85 | BigDecimal.new(BigDecimal('-Infinity')) 86 | BigDecimal(BigDecimal.new('NaN')) 87 | end 88 | BigDecimal.save_limit do 89 | BigDecimal.limit(200) 90 | end 91 | BigDecimal.save_rounding_mode do 92 | BigDecimal.mode(BigDecimal::ROUND_MODE, :up) 93 | end 94 | # Additional test calls for coverage 95 | BigDecimal.double_fig 96 | BigDecimal.limit(5) 97 | BigDecimal.mode(BigDecimal::EXCEPTION_NaN, true) 98 | BigDecimal.mode(BigDecimal::EXCEPTION_NaN, false) 99 | BigDecimal.mode(BigDecimal::EXCEPTION_NaN) 100 | BigDecimal.ver 101 | 102 | # TODO 103 | end 104 | 105 | def test_bigmath 106 | # From the Ruby stdlib documentation 107 | BigMath.E(10) 108 | BigMath.PI(10) 109 | BigMath.atan(BigDecimal.new('-1'), 16) 110 | BigMath.cos(BigMath.PI(4), 16) 111 | BigMath.sin(BigMath.PI(5)/4, 5) 112 | BigMath.sqrt(BigDecimal.new('2'), 16) 113 | end 114 | 115 | def test_class 116 | Dummy.allocate 117 | Dummy.new 118 | Dummy.superclass 119 | end 120 | 121 | def test_coverage 122 | skip "Skip when nowrap is enabled" 123 | Coverage.start 124 | Coverage.result 125 | #Coverage.result # TODO This cannot be typechecked 126 | end 127 | 128 | def test_exception 129 | e1 = Exception.new 130 | _ = (e1 == 5) 131 | tmp = e1.backtrace 132 | e1.backtrace_locations 133 | e1.cause 134 | e1.exception 135 | e1.inspect 136 | e1.message 137 | e1.set_backtrace(tmp) 138 | e1.to_s 139 | end 140 | 141 | def test_set 142 | skip "Skip when nowrap is enabled" 143 | assert_raises(RDL::Type::TypeError) { _ = Set.new(1,2) } 144 | # From the Ruby stdlib documentation 145 | s1 = Set.new [1, 2] # -> # 146 | s2 = [1, 2].to_set # -> # 147 | _ = (s1 == s2) # -> true 148 | s1.add("foo") # -> # 149 | s1.merge([2, 6]) # -> # 150 | s1.subset? s2 # -> false 151 | s2.subset? s1 # -> true 152 | Set[1, 2, 3].disjoint? Set[3, 4] # => false 153 | Set[1, 2, 3].disjoint? Set[4, 5] # => true 154 | numbers = Set[1, 3, 4, 6, 9, 10, 11] 155 | _ = numbers.divide { |i,j| (i - j).abs == 1 } 156 | Set[1, 2, 3].intersect? Set[4, 5] # => false 157 | Set[1, 2, 3].intersect? Set[3, 4] # => true 158 | # Some more tests, just to make sure type checking doesn't cause crashes 159 | _ = s1 - s2 160 | s1.proper_subset? s2 161 | s1.superset? s2 162 | _ = s1 ^ s2 163 | s1.add?("bar") 164 | _ = s1.classify { |x| x.size } 165 | s2.clear 166 | _ = s1.map { |x| 42 } 167 | s1.delete "foo" 168 | s1.delete? "bar" 169 | s1.delete_if { |x| false } 170 | s1.each { |x| nil } 171 | s1.empty? 172 | s1.member? 42 173 | s1.intersection [1,2,3] 174 | s1.keep_if { |x| true } 175 | s1.size 176 | s1.difference [1,2,3] 177 | s1.to_a 178 | _ = s1 + s2 179 | end 180 | 181 | def test_uri 182 | URI.decode_www_form("a=1&a=2&b=3") 183 | URI.encode_www_form([["q", "ruby"], ["lang", "en"]]) # Internally uses _component 184 | URI.encode_www_form("q" => "ruby", "lang" => "en") 185 | URI.encode_www_form("q" => ["ruby", "perl"], "lang" => "en") 186 | URI.encode_www_form([["q", "ruby"], ["q", "perl"], ["lang", "en"]]) 187 | # URI.extract("text here http://foo.example.org/bla and here mailto:test@example.com and here also.") 188 | URI.join("http://example.com/","main.rbx") 189 | URI.parse("http://www.ruby-lang.org/") 190 | URI.scheme_list 191 | URI.split("http://www.ruby-lang.org/") 192 | # enc_uri = URI.escape("http://example.com/?a=\11\15") 193 | # URI.unescape(enc_uri) 194 | end 195 | end 196 | -------------------------------------------------------------------------------- /lib/types/core/process.rb: -------------------------------------------------------------------------------- 1 | RDL.nowrap :Process 2 | 3 | RDL.type :Process, 'self.abort', '(?String msg) -> %any' 4 | RDL.type :Process, 'self.argv0', '() -> String frozen_string' 5 | RDL.type :Process, 'self.clock_getres', '(Symbol or Integer clock_id, ?Symbol unit) -> Float or Integer' 6 | RDL.type :Process, 'self.clock_gettime', '(Symbol or Integer clock_id, ?Symbol unit) -> Float or Integer' 7 | RDL.type :Process, 'self.daemon', '(?%any nochdir, ?%any noclose) -> 0' 8 | RDL.type :Process, 'self.detach', '(Integer pid) -> Thread' 9 | RDL.type :Process, 'self.egid', '() -> Integer' 10 | RDL.type :Process, 'self.egid=', '(Integer) -> Integer' 11 | RDL.type :Process, 'self.euid', '() -> Integer' 12 | RDL.type :Process, 'self.euid=', '(Integer) -> Integer user' 13 | #RDL.type :Process, 'self.exec', '(env: ?Hash, command:String, args:*String) -> %any' # TODO: env 14 | RDL.type :Process, 'self.exit', '(?Integer status) -> %any' 15 | RDL.type :Process, 'self.exit!', '(?Integer status) -> %any' 16 | RDL.type :Process, 'self.fork', '() -> Integer or nil' 17 | RDL.type :Process, 'self.fork', '() { () -> %any } -> Integer or nil' 18 | RDL.type :Process, 'self.getpgid', '(Integer pid) -> Integer' 19 | RDL.type :Process, 'self.getpgrp', '() -> Integer' 20 | RDL.type :Process, 'self.getpriority', '(Integer kind, Integer) -> Integer' 21 | RDL.type :Process, 'self.getrlimit', '(Symbol or String or Integer resource) -> [Integer, Integer] cur_max_limit' 22 | RDL.type :Process, 'self.getsid', '(?Integer pid) -> Integer' 23 | RDL.type :Process, 'self.gid', '() -> Integer' 24 | RDL.type :Process, 'self.gid=', '(Integer) -> Integer' 25 | RDL.type :Process, 'self.groups', '() -> Array' 26 | RDL.type :Process, 'self.groups=', '(Array) -> Array' 27 | RDL.type :Process, 'self.initgroups', '(String username, Integer gid) -> Array' 28 | RDL.type :Process, 'self.kill', '(Integer or Symbol or String signal, *Integer pids) -> Integer' 29 | RDL.type :Process, 'self.maxgroups', '() -> Integer' 30 | RDL.type :Process, 'self.maxgroups=', '(Integer) -> Integer' 31 | RDL.type :Process, 'self.pid', '() -> Integer' 32 | RDL.type :Process, 'self.ppid', '() -> Integer' 33 | RDL.type :Process, 'self.pgid', '(Integer pid, Integer) -> Integer' 34 | RDL.type :Process, 'self.setpriority', '(Integer kind, Integer, Integer priority) -> 0' 35 | RDL.type :Process, 'self.setproctitle', '(String) -> String' 36 | RDL.type :Process, 'self.setrlimit', '(Symbol or String or Integer resource, Integer cur_limit, ?Integer max_limit) -> nil' 37 | RDL.type :Process, 'self.setsid', '() -> Integer' 38 | #RDL.type :Process, 'self.spawn', '(?Hash env, String command, *String args) -> %any' # TODO: env 39 | RDL.type :Process, 'self.times', '() -> Process::Tms' 40 | RDL.type :Process, 'self.uid', '() -> Integer' 41 | RDL.type :Process, 'self.uid=', '(Integer user) -> Integer' 42 | RDL.type :Process, 'self.wait', '(?Integer pid, ?Integer flags) -> Integer' 43 | RDL.type :Process, 'self.wait2', '(?Integer pid, ?Integer flags) -> [Integer, Integer] pid_and_status' 44 | RDL.type :Process, 'self.waitall', '() -> Array<[Integer, Integer]>' 45 | RDL.type :Process, 'self.waitpid', '(?Integer pid, ?Integer flags) -> Integer' 46 | RDL.type :Process, 'self.waitpid2', '(?Integer pid, ?Integer flags) -> [Integer, Integer] pid_and_status' 47 | 48 | RDL.nowrap :'Process::GID' 49 | RDL.type :'Process::GID', 'self.change_privilege', '(Integer group) -> Integer' 50 | RDL.type :'Process::GID', 'self.eid', '() -> Integer' 51 | RDL.type :'Process::GID', 'self.from_name', '(String name) -> Integer gid' 52 | RDL.type :'Process::GID', 'self.grant_privilege', '(Integer group) -> Integer' 53 | RDL.rdl_alias :'Process::GID', 'self.eid=', 'self.grant_privilege' 54 | RDL.type :'Process::GID', 'self.re_exchange', '() -> Integer' 55 | RDL.type :'Process::GID', 'self.re_exchangeable?', '() -> %bool' 56 | RDL.type :'Process::GID', 'self.rid', '() -> Integer' 57 | RDL.type :'Process::GID', 'self.sid_available?', '() -> %bool' 58 | RDL.type :'Process::GID', 'self.switch', '() -> Integer' 59 | RDL.type :'Process::GID', 'self.switch', '() { () -> t } -> t' 60 | 61 | RDL.nowrap :'Process::UID' 62 | RDL.type :'Process::UID', 'self.change_privilege', '(Integer user) -> Integer' 63 | RDL.type :'Process::UID', 'self.eid', '() -> Integer' 64 | RDL.type :'Process::UID', 'self.from_name', '(String name) -> Integer uid' 65 | RDL.type :'Process::UID', 'self.grant_privilege', '(Integer user) -> Integer' 66 | RDL.rdl_alias :'Process::UID', 'self.eid=', 'self.grant_privilege' 67 | RDL.type :'Process::UID', 'self.re_exchange', '() -> Integer' 68 | RDL.type :'Process::UID', 'self.re_exchangeable?', '() -> %bool' 69 | RDL.type :'Process::UID', 'self.rid', '() -> Integer' 70 | RDL.type :'Process::UID', 'self.sid_available?', '() -> %bool' 71 | RDL.type :'Process::UID', 'self.switch', '() -> Integer' 72 | RDL.type :'Process::UID', 'self.switch', '() { () -> t } -> t' 73 | 74 | RDL.nowrap :'Process::Status' 75 | RDL.type :'Process::Status', :&, '(Integer num) -> Integer' 76 | RDL.type :'Process::Status', :==, '(%any other) -> %bool' 77 | RDL.type :'Process::Status', :>>, '(Integer num) -> Integer' 78 | RDL.type :'Process::Status', :coredump?, '() -> %bool' 79 | RDL.type :'Process::Status', :exited?, '() -> %bool' 80 | RDL.type :'Process::Status', :exitstatus, '() -> Integer or nil' 81 | RDL.type :'Process::Status', :inspect, '() -> String' 82 | RDL.type :'Process::Status', :pid, '() -> Integer' 83 | RDL.type :'Process::Status', :signaled?, '() -> %bool' 84 | RDL.type :'Process::Status', :stopped?, '() -> %bool' 85 | RDL.type :'Process::Status', :stopsig, '() -> Integer or nil' 86 | RDL.type :'Process::Status', :success?, '() -> %bool' 87 | RDL.type :'Process::Status', :termsig, '() -> Integer or nil' 88 | RDL.type :'Process::Status', :to_i, '() -> Integer' 89 | RDL.rdl_alias :'Process::Status', :to_int, :to_i 90 | RDL.type :'Process::Status', :to_s, '() -> String' 91 | 92 | RDL.nowrap :'Process::Sys' 93 | RDL.type :'Process::Sys', 'self.geteid', '() -> Integer' 94 | RDL.type :'Process::Sys', 'self.geteuid', '() -> Integer' 95 | RDL.type :'Process::Sys', 'self.getgid', '() -> Integer' 96 | RDL.type :'Process::Sys', 'self.getuid', '() -> Integer' 97 | RDL.type :'Process::Sys', 'self.issetugid', '() -> %bool' 98 | RDL.type :'Process::Sys', 'self.setegid', '(Integer group) -> nil' 99 | RDL.type :'Process::Sys', 'self.seteuid', '(Integer user) -> nil' 100 | RDL.type :'Process::Sys', 'self.setgid', '(Integer group) -> nil' 101 | RDL.type :'Process::Sys', 'self.setregid', '(Integer rid, Integer eid) -> nil' 102 | RDL.type :'Process::Sys', 'self.setresgid', '(Integer rid, Integer eid, Integer sid) -> nil' 103 | RDL.type :'Process::Sys', 'self.setresuid', '(Integer rid, Integer eid, Integer sid) -> nil' 104 | RDL.type :'Process::Sys', 'self.setreuid', '(Integer rid, Integer eid) -> nil' 105 | RDL.type :'Process::Sys', 'self.setrgid', '(Integer group) -> nil' 106 | RDL.type :'Process::Sys', 'self.setruid', '(Integer user) -> nil' 107 | RDL.type :'Process::Sys', 'self.setuid', '(Integer user) -> nil' 108 | 109 | RDL.nowrap :'Process::Waiter' 110 | RDL.type :'Process::Waiter', 'pid', '() -> Integer' 111 | --------------------------------------------------------------------------------