From d684e52c36ba48a21aa7d65d7a9c31e53079e217 Mon Sep 17 00:00:00 2001 From: Jean Privat Date: Thu, 19 Mar 2015 12:40:42 +0700 Subject: [PATCH] lib: add `meta` as a user-level empty shell for meta-classes Signed-off-by: Jean Privat --- lib/meta.nit | 99 +++++++++++++++++++++++++++++++++ tests/sav/nitg-e/test_meta.res | 14 +++++ tests/sav/nitg-g/fixme/test_meta.res | 1 + tests/sav/nitg-s/fixme/test_meta.res | 1 + tests/sav/nitg-sg/fixme/test_meta.res | 1 + tests/sav/test_meta.res | 14 +++++ tests/test_meta.nit | 56 +++++++++++++++++++ 7 files changed, 186 insertions(+) create mode 100644 lib/meta.nit create mode 100644 tests/sav/nitg-e/test_meta.res create mode 100644 tests/sav/nitg-g/fixme/test_meta.res create mode 100644 tests/sav/nitg-s/fixme/test_meta.res create mode 100644 tests/sav/nitg-sg/fixme/test_meta.res create mode 100644 tests/sav/test_meta.res create mode 100644 tests/test_meta.nit diff --git a/lib/meta.nit b/lib/meta.nit new file mode 100644 index 0000000..68ba9f4 --- /dev/null +++ b/lib/meta.nit @@ -0,0 +1,99 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Simple user-defined meta-level to manipulate types of instances as object. +# +# Unfortunately, since the meta-objects are user-defined they are provided without +# any pre-defined information or behavior. +# For the same reasons, the Nit OO mechanisms do not rely on this user-defined meta-level. +# +# However `meta` permits the definition of user-defined meta-classes at any level +# of meta, even with user-defined meta-loops. +# +# ## Meta-classes +# +# Meta-classes can be defined easily in 3 steps: +# +# * define a root for the class hierarchy (eg `XObject`) +# * define a meta-class (eq `XClass[E: XObject] super Class[E]`) +# * redefine `CLASS` and `class_factory` in the root +# +# ~~~nitish because broke with nitc, see Limitation bellow +# class XObject +# redef CLASS: XClass[SELF] +# redef class_factory(name) do return new XClass[SELF](name) +# end +# class XClass[E: XObject] super Class[E] end +# +# var x1 = new XObject +# var x2 = new XObject +# assert x1.get_class == x2.get_class +# assert x1.get_class isa XClass[XObject] +# assert x1.get_class.get_class isa Class[XClass[XObject]] +# ~~~ +# +# ## Limitation +# +# Currently works only with the interpreter `nit` and the compiler with `--erasure` (without `--rta`). +# +# `--rta` will try to detect all the runtime types, and will infinitely discover `Class[Class[Class[....]]]`. +# Unfortunately, `--separate` and `--global` require `--rta`. +# +# Moreover, the interpreter and `--erasure` have a different behavior with generics since +# with `--erasure` a single meta-instance is shared for all type variations of a same generic class. +# +# Class names are used as a primary key to identify classes. +# But name conflicts are not managed and will make the program crashes at runtime (on some cast error) +module meta + +redef class Object + # The meta-object representing the dynamic type of `self`. + # + # Specific meta-object can be used in subclasses + # by redefining `CLASS` and `class_factory`. + fun get_class: CLASS do + var class_pool = once new HashMap[String, Class[Object]] + var name = class_name + var res = class_pool.get_or_null(name) + if res != null then return res.as(CLASS) + res = class_factory(name) + assert res.name == name + class_pool[name] = res + return res + end + + # The type of the class of self. + # To be redefined in case of specific meta-class. + type CLASS: Class[SELF] + + # Implementation used by `get_class` to create the specific class. + # + # To be redefined to use specific meta-classes. + # + # Note: Do not forget to update the virtual type `CLASS`. + # + # REQUIRE: `result.name` == `name` + protected fun class_factory(name: String): CLASS + do + return new Class[SELF](name) + end +end + +# This meta-class is the root the meta-class hierarchy +class Class[E: Object] + # The name of the class + var name: String + + redef fun to_s do return name +end diff --git a/tests/sav/nitg-e/test_meta.res b/tests/sav/nitg-e/test_meta.res new file mode 100644 index 0000000..ad6cdbf --- /dev/null +++ b/tests/sav/nitg-e/test_meta.res @@ -0,0 +1,14 @@ +FlatString +FlatString +Class +Class + +XObject +XObject +XClass +Class + +YObject +YObject +YClass +YClass diff --git a/tests/sav/nitg-g/fixme/test_meta.res b/tests/sav/nitg-g/fixme/test_meta.res new file mode 100644 index 0000000..4ad3dc3 --- /dev/null +++ b/tests/sav/nitg-g/fixme/test_meta.res @@ -0,0 +1 @@ +UNDEFINED diff --git a/tests/sav/nitg-s/fixme/test_meta.res b/tests/sav/nitg-s/fixme/test_meta.res new file mode 100644 index 0000000..4ad3dc3 --- /dev/null +++ b/tests/sav/nitg-s/fixme/test_meta.res @@ -0,0 +1 @@ +UNDEFINED diff --git a/tests/sav/nitg-sg/fixme/test_meta.res b/tests/sav/nitg-sg/fixme/test_meta.res new file mode 100644 index 0000000..4ad3dc3 --- /dev/null +++ b/tests/sav/nitg-sg/fixme/test_meta.res @@ -0,0 +1 @@ +UNDEFINED diff --git a/tests/sav/test_meta.res b/tests/sav/test_meta.res new file mode 100644 index 0000000..6f23d37 --- /dev/null +++ b/tests/sav/test_meta.res @@ -0,0 +1,14 @@ +FlatString +FlatString +Class[FlatString] +Class[Class[FlatString]] + +XObject +XObject +XClass[XObject] +Class[XClass[XObject]] + +YObject +YObject +YClass[YObject] +YClass[YClass[YObject]] diff --git a/tests/test_meta.nit b/tests/test_meta.nit new file mode 100644 index 0000000..936982e --- /dev/null +++ b/tests/test_meta.nit @@ -0,0 +1,56 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import meta + +class XObject + redef type CLASS: XClass[SELF] + redef fun class_factory(name) do return new XClass[SELF](name) +end + +class XClass[E: XObject] + super Class[E] +end + +class YObject + redef type CLASS: YClass[SELF] + redef fun class_factory(name) do return new YClass[SELF](name) +end + +class YClass[E: YObject] + super Class[E] + super YObject # Yeah, a meta-loop! +end + +var s = "hello" +print s.class_name +print s.get_class +print s.get_class.get_class +print s.get_class.get_class.get_class + +print "" + +var x = new XObject +print x.class_name +print x.get_class +print x.get_class.get_class +print x.get_class.get_class.get_class + +print "" + +var y = new YObject +print y.class_name +print y.get_class +print y.get_class.get_class +print y.get_class.get_class.get_class -- 1.7.9.5