Permalink
Browse files

Merge branch 'inheritance1'

  • Loading branch information...
yhara committed Sep 8, 2018
2 parents 06f2e7d + 9c4af10 commit 8ef52b145cf2b6a32793abe3f264517aea7273b9
View
@@ -6,6 +6,10 @@ gem "thor"
gem "hashie"
gem "activesupport"
group :development do
gem "byebug"
end
group :test do
gem "simplecov"
end
View
@@ -6,6 +6,7 @@ GEM
i18n (>= 0.7, < 2)
minitest (~> 5.1)
tzinfo (~> 1.1)
byebug (10.0.2)
concurrent-ruby (1.0.5)
diff-lcs (1.3)
docile (1.1.5)
@@ -44,6 +45,7 @@ PLATFORMS
DEPENDENCIES
activesupport
byebug
hashie
racc
rake
View
@@ -66,7 +66,12 @@ def to_program
end
class DefClass < Node
props :name, :typarams, :defmethods
props :name, :typarams, :superclass_template, :defmethods
# Example of superclass_template:
# # class B extends A
# ["A", []]
# # class C extends Array<Array<Int>>
# ["Array", ["Array", ["Int"]]]
# return [sk_class, meta_class]
def to_program
@@ -80,7 +85,7 @@ def to_program
sk_methods["initialize"] ||= Program::SkInitializer.new([], [])
return Program::SkClass.build(
name: name,
parent_name: "Object",
superclass_template: superclass_template,
sk_ivars: sk_methods["initialize"].ivars,
class_methods: sk_class_methods,
sk_methods: sk_methods,
View
@@ -68,10 +68,11 @@ rule
<%= repeat1 'top_statement', sep: ['sep'] %>
defclass:
'class' CONST opt_type_parameters sep
'class' CONST opt_type_parameters opt_superclass_template sep
opt_defmethods
'end'
{ Ast::DefClass.new(name: val[1], typarams: val[2], defmethods: val[4]) }
{ Ast::DefClass.new(name: val[1], typarams: val[2], superclass_template: val[3],
defmethods: val[5]) }
opt_type_parameters:
/* NONE */
@@ -85,6 +86,13 @@ rule
{ Ast::TypeParameter.new(name: val[0]) }
<%= repeat1 'type_parameter', sep: ["_nl", "','", "_nl"] %>
opt_superclass_template:
/* NONE (set default superclass) */
{ Shiika::Type::TyRaw['Object'] }
|
'extends' type
{ val[1] }
defmethod:
definitialize
| 'def' opt_self_dot method_name opt_paramlist opt_ret_type sep
@@ -309,7 +317,7 @@ require 'strscan'
require 'shiika/ast'
---- inner
KEYWORDS = /class|def|initialize|do|end|if|elsif|else|return|var|self|true|false/
KEYWORDS = /class|extends|def|initialize|do|end|if|elsif|else|return|var|self|true|false/
SYMBOLS = Regexp.union(*"
... >= <= == != && || -> < > ( ) [ ] { } . + - * / % = , ; :
View
@@ -272,7 +272,7 @@ def ivars
class SkClass < Element
props name: String,
parent_name: String, # or '__noparent__'
superclass_template: Type::ConcreteType, # or TyRaw['__noparent__']
sk_ivars: {String => SkIvar},
class_methods: {String => SkMethod},
sk_methods: {String => SkMethod}
@@ -286,16 +286,16 @@ def self.build(hash)
end
meta_name = "Meta:#{sk_class.name}"
meta_parent = if sk_class.parent_name == '__noparent__'
'__noparent__'
else
"Meta:#{sk_class.parent_name}"
end
meta_super = if sk_class.name == 'Object'
TyRaw['__noparent__']
else
sk_class.superclass_template.meta_type
end
sk_new = typarams.empty? && make_sk_new(sk_class)
meta_attrs = {
name: meta_name,
parent_name: meta_parent,
superclass_template: meta_super,
sk_ivars: {},
class_methods: {},
sk_methods: (typarams.empty? ? {"new" => sk_new} : {}).merge(sk_class.class_methods)
@@ -336,6 +336,26 @@ def meta_type
TyMeta[name]
end
def superclass_name
superclass_template.name
end
# Return true if this class is a (maybe indirect) subclass of `other`
def subclass_of?(other, env)
if self == other
false
elsif self.superclass_template == TyRaw['__noparent__']
false
else
parent = env.find_class(self.superclass_name)
if parent == other
true
else
parent.subclass_of?(other, env)
end
end
end
def find_method(name)
if (ret = @sk_methods[name])
ret
@@ -364,6 +384,7 @@ def init
end
attr_reader :specialized_classes
# type_arguments: [Type]
def specialized_class(type_arguments, env, cls=SkSpecializedClass)
key = type_arguments.map(&:to_key).join(', ')
@specialized_classes[key] ||= begin
@@ -377,6 +398,10 @@ def meta_type
TyGenMeta[name, typarams.map(&:name)]
end
def superclass_name
raise "SkGenericClass does not have a `superclass'"
end
private
def methods_env(env)
@@ -405,6 +430,20 @@ def calc_type!(env)
return env, TySpe[sk_generic_class.name, type_arguments]
end
# Return true if this class is a (maybe indirect) subclass of `other`
def subclass_of?(other, env)
if self == other
false
else
parent = env.find_class(self.superclass_name)
if parent == other
true
else
parent.subclass_of?(other, env)
end
end
end
# Lazy method creation (create when first called)
def find_method(name)
@methods[name] ||= begin
@@ -416,6 +455,11 @@ def find_method(name)
end
end
# eg. `"A<Int>"` for `B<Int>`, where `class B<T> extends A<T>`
def superclass_name
generic_class.superclass_template.substitute(type_mapping).name
end
private
def type_mapping
@@ -451,6 +495,10 @@ def specialized_class(type_arguments, env)
super(type_arguments, env, SkSpecializedMetaClass)
end
def superclass_name
raise "SkGenericMetaClass does not have a `superclass'"
end
def to_type
TyGenMeta[name, typarams.map(&:name)]
end
@@ -610,42 +658,43 @@ def check_nonvar_arg_types(sk_method)
class AssignmentExpr < Expression
def calc_type!(env)
expr.add_type!(env)
newenv = expr.add_type!(env)
raise SkProgramError, "cannot assign Void value" if expr.type == TyRaw["Void"]
return newenv
end
end
class AssignLvar < AssignmentExpr
props varname: String, expr: Expression, isvar: :boolean
def calc_type!(env)
super
newenv = super
lvar = env.find_lvar(varname, allow_missing: true)
if lvar
if lvar.kind == :let
raise SkProgramError, "lvar #{varname} is read-only (missing `var`)"
end
unless lvar.type.conforms?(expr.type, env)
unless newenv.conforms_to?(expr.type, lvar.type)
raise SkTypeError, "the type of expr (#{expr.type}) does not conform to the type of lvar #{varname} (#{lvar.type})"
end
else
lvar = Lvar.new(varname, expr.type, (isvar ? :var : :let))
end
newenv = env.merge(:local_vars, {varname => lvar})
return newenv, expr.type
retenv = newenv.merge(:local_vars, {varname => lvar})
return retenv, expr.type
end
end
class AssignIvar < AssignmentExpr
props varname: String, expr: Expression
def calc_type!(env)
super
newenv = super
ivar = env.find_ivar(varname)
if ivar.type != expr.type # TODO: subtypes
raise SkTypeError, "ivar #{varname} of class #{env.sk_self} is #{ivar.type} but expr is #{expr.type}"
end
return env, expr.type
return newenv, expr.type
end
end
@@ -685,7 +734,7 @@ def calc_type!(env)
end
class ClassSpecialization < Expression
props class_expr: Expression, type_arg_exprs: [Expression]
props class_expr: ConstRef, type_arg_exprs: [ConstRef]
def calc_type!(env)
class_expr.add_type!(env)
@@ -699,8 +748,12 @@ def calc_type!(env)
raise SkTypeError, "not a class: #{expr.inspect}" unless expr.type.is_a?(TyMeta)
expr.type.instance_type
}
create_specialized_class(env, base_class_name, type_args)
return env, TySpeMeta[base_class_name, type_args]
sp_cls, sp_meta = create_specialized_class(env, base_class_name, type_args)
newenv = env.merge(:sk_classes, {
sp_cls.name => sp_cls,
sp_meta.name => sp_meta.name,
})
return newenv, TySpeMeta[base_class_name, type_args]
end
private
@@ -710,9 +763,10 @@ def create_specialized_class(env, base_class_name, type_args)
gen_cls = env.find_class(base_class_name)
raise if !(SkGenericClass === gen_cls) &&
!(SkGenericMetaClass === gen_cls)
gen_cls.specialized_class(type_args, env)
sp_cls = gen_cls.specialized_class(type_args, env)
gen_meta = env.find_meta_class(base_class_name)
gen_meta.specialized_class(type_args, env)
sp_meta = gen_meta.specialized_class(type_args, env)
return sp_cls, sp_meta
end
end
View
@@ -118,6 +118,19 @@ def find_method(receiver_type, name)
def sk_self
@data[:sk_self]
end
# Return true if type1 conforms to type2 (eg. TyRaw['Int'] conforms to TyRaw['Object'])
def conforms_to?(type1, type2)
get_cls = ->(type){
if type.is_a?(TyParam)
find_class('Object')
else
find_class(type.name)
end
}
cls1, cls2 = get_cls[type1], get_cls[type2]
return cls1 == cls2 || cls1.subclass_of?(cls2, self)
end
end
end
end
View
@@ -18,7 +18,7 @@ def self.object_new_body_stmts
CLASSES = [
{
name: "Object",
parent: '__noparent__',
superclass_template: TyRaw['__noparent__'],
typarams: [],
ivars: {},
class_methods: [
@@ -54,7 +54,7 @@ def self.object_new_body_stmts
},
{
name: "Bool",
parent: "Object",
superclass_template: TyRaw["Object"],
typarams: [],
ivars: {},
class_methods: [],
@@ -68,7 +68,7 @@ def self.object_new_body_stmts
},
{
name: "Int",
parent: "Object",
superclass_template: TyRaw["Object"],
typarams: [],
ivars: {
'@rb_val' => TyRaw['Int']
@@ -115,7 +115,7 @@ def self.object_new_body_stmts
},
{
name: 'Array',
parent: 'Object',
superclass_template: TyRaw["Object"],
typarams: ['ELEM'],
ivars: {
'@items' => TyRaw['Void']
@@ -174,7 +174,7 @@ def self.sk_classes
[name, Program::SkIvar.new(name: name, type_spec: type)]
}.to_h
sk_class, meta_class = Program::SkClass.build(
name: spec[:name], parent_name: spec[:parent],
name: spec[:name], superclass_template: spec[:superclass_template],
sk_ivars: sk_ivars, class_methods: sk_class_methods, sk_methods: sk_methods,
typarams: spec[:typarams].map{|x|
Program::TypeParameter.new(name: x)
View
@@ -6,14 +6,6 @@ class Base; end
# Type for classes which can have an instance
# eg. Array<Array<Int>> is OK but Array<Array> is NG
class ConcreteType < Base
# Return true if this type conforms to `other` type
def conforms_to?(other, env)
if other.is_a?(TyParam)
self == TyRaw["Object"]
else
self == other
end
end
end
# Type for normal (i.e. non-generic, non-meta) class
@@ -39,6 +31,10 @@ def substitute(mapping)
mapping[name] || self
end
def meta_type
TyMeta[name]
end
def inspect
"#<TyRaw #{name}>"
end
@@ -175,11 +171,6 @@ def upper_bound
TyRaw["Object"]
end
def conforms?(other)
# TODO: subtypes
TyRaw["Object"].conforms?(other)
end
def inspect
"#<TyParam #{name}>"
end
Oops, something went wrong.

0 comments on commit 8ef52b1

Please sign in to comment.