You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tvm.apache.org by GitBox <gi...@apache.org> on 2020/10/28 00:47:24 UTC

[GitHub] [incubator-tvm] ZihengJiang opened a new pull request #6779: [WIP] Object Schema

ZihengJiang opened a new pull request #6779:
URL: https://github.com/apache/incubator-tvm/pull/6779


   See RFC: https://discuss.tvm.apache.org/t/rfc-tvm-object-schema-dsl/7930


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-tvm] mbrookhart commented on pull request #6779: [WIP] Object Schema

Posted by GitBox <gi...@apache.org>.
mbrookhart commented on pull request #6779:
URL: https://github.com/apache/incubator-tvm/pull/6779#issuecomment-722132927


   A lot of this discussion seems to be more appropriate for the RFC instead of the PR, I added some thoughts here: https://discuss.tvm.apache.org/t/rfc-tvm-object-schema-dsl/7930/12
   
   I think I agree with @jroesch, I'm not sure I fully understand the goal of the object schema, and it doesn't seem to quite fit in the places I imagine using it.


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-tvm] jroesch commented on pull request #6779: [WIP] Object Schema

Posted by GitBox <gi...@apache.org>.
jroesch commented on pull request #6779:
URL: https://github.com/apache/incubator-tvm/pull/6779#issuecomment-720685479


   I have been super busy so I can't remember if I also commented on the RFC, but I have argued this point before as well with @tqchen and others. I am also unsure if having Python be the source of truth is the right approach as well. 
   
   I echo @tkonolige's concern.
   
   I think having a completely external format like LLVM's TableGen is conceptually simpler and more flexible as well. I feely strongly if we are going to generate code we should never check the generated files in, but by requiring Python it means to even build the C++ bindings I need to be able to run the generation step on my platform. I know there are some challenges running Python on more resource constrained devices does this pose build risks as well? cc @areusch 
   
   Having been one of the only people to bind 1000s of lines of TVM code all at once (in the implementation of the Rust bindings) I have found that structs are not the largest amount of work and the bigger challenge is actually method bindings per language. How do we handle these correctly in the Python set up? I feel like trying to cram them into the Python AST is awkward. 
   
   Even writing a Rust macro for them is not ideal and Rust has significantly better and more flexible macro facilities. 
   
   See below for example of binding the IRModule API.
   
   ```
   #[repr(C)]
   #[derive(Object)]
   #[ref_name = "IRModule"]
   #[type_key = "IRModule"]
   pub struct IRModuleNode {
       pub base: Object,
       pub functions: Map<GlobalVar, BaseFunc>,
       pub type_definitions: Map<GlobalTypeVar, TypeData>,
       pub source_map: SourceMap,
       // TODO(@jroesch): this is missing some fields
   }
   
   external! {
       // Parser functions
       #[name("parser.ParseModule")]
       fn parse_module(file_name: TVMString, source: TVMString) -> IRModule;
       #[name("parser.ParseExpr")]
       fn parse_expression(file_name: TVMString, source: TVMString) -> IRModule;
       #[name("ir.IRModule")]
       fn module_new(funcs: Map<GlobalVar, BaseFunc>, types: Map<GlobalTypeVar, TypeData>) -> IRModule;
       // Module methods
       #[name("ir.Module_Add")]
       fn module_add(module: IRModule, type_name: GlobalVar, expr: BaseFunc, update: bool) -> IRModule;
       #[name("ir.Module_AddDef")]
       fn module_add_def(module: IRModule, type_name: GlobalTypeVar, type_data: TypeData, update: bool) -> ();
       #[name("ir.Module_GetGlobalVar")]
       fn module_get_global_var(module: IRModule, name: TVMString) -> GlobalVar;
       #[name("ir.Module_GetGlobalVars")]
       fn module_get_global_vars(module: IRModule) -> Array<GlobalVar>;
       #[name("ir.Module_Lookup")]
       fn module_lookup(module: IRModule, var: GlobalVar) -> BaseFunc;
       #[name("ir.Module_Lookup_str")]
       fn module_lookup_str(module: IRModule, name: TVMString) -> BaseFunc;
       #[name("ir.Module_GetGlobalTypeVars")]
       fn module_get_global_type_vars(module: IRModule) -> Array<GlobalTypeVar>;
       #[name("ir.Module_ContainGlobalVar")]
       fn module_contains_global_var(module: IRModule, name: TVMString) -> bool;
       #[name("ir.Module_ContainGlobalTypeVar")]
       fn module_contains_global_type_var(module: IRModule, name: TVMString) -> bool;
       #[name("ir.Module_LookupDef")]
       fn module_lookup_def(module: IRModule, global: GlobalTypeVar) -> TypeData;
       #[name("ir.Module_LookupDef_str")]
       fn module_lookup_def_str(module: IRModule, global: GlobalTypeVar) -> TypeData;
       #[name("ir.Module_LookupTag")]
       fn module_lookup_tag(module: IRModule, tag: i32) -> relay::Constructor;
       #[name("ir.Module_FromExpr")]
       fn module_from_expr(expr: relay::Expr, funcs: Map<GlobalVar, BaseFunc>, types: Map<GlobalTypeVar, TypeData>) -> IRModule;
       #[name("ir.Module_Import")]
       fn module_import(module: IRModule, path: TVMString);
       #[name("ir.Module_ImportFromStd")]
       fn module_import_from_std(module: IRModule, path: TVMString);
   }
   ```


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-tvm] tqchen commented on pull request #6779: [WIP] Object Schema

Posted by GitBox <gi...@apache.org>.
tqchen commented on pull request #6779:
URL: https://github.com/apache/incubator-tvm/pull/6779#issuecomment-720692796


   We acknowledged that it is not ideal to elaborate everything in the schema(e.g. describe the member function). So the main goal of the schema serves as a way to facilitate the data layout generation, while still allowing users to fill out the necessary content(e.g. member functions) in the corresponding backend language. 
   
   That means the schema is an auxiliary tool that developer can run, but the generated code is always checked in and generation step is not invoked part of the build (like clang-format), resulting lightweight commitment and transition from developers. 
   
   The layout information alone is very useful for cross language enablement, like rust access binding etc and build code generators for accessing the data structure.
   
   Given that first class python support is one of our design goal, and as we start to evolve TVMScript I think we want to think about the possibility of supporting custom ADT as part of the type system and input. I do think it makes sense to have a python frontend to the schema itself, which provides convenience to specify the data layout.
   
   
   
   


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-tvm] jroesch commented on pull request #6779: [WIP] Object Schema

Posted by GitBox <gi...@apache.org>.
jroesch commented on pull request #6779:
URL: https://github.com/apache/incubator-tvm/pull/6779#issuecomment-719239288


   cc @tkonolige @mwillsey 


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-tvm] tqchen edited a comment on pull request #6779: [WIP] Object Schema

Posted by GitBox <gi...@apache.org>.
tqchen edited a comment on pull request #6779:
URL: https://github.com/apache/incubator-tvm/pull/6779#issuecomment-720692796






----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-tvm] tkonolige commented on pull request #6779: [WIP] Object Schema

Posted by GitBox <gi...@apache.org>.
tkonolige commented on pull request #6779:
URL: https://github.com/apache/incubator-tvm/pull/6779#issuecomment-720644993


   It seems like we could cut out a step in the `Object Schema Definition (Python) -> JSON Format Schema (language-agnostic) -> Backend (can be any language like Python or Rust)` process and just do `JSON Format Schema (language-agnostic) -> Backend (can be any language like Python or Rust)`. If we have to do `Python -> JSON -> Python`, what is the point of having the first python? I can understand that writing object definitions in python is a nice user experience, but this isn't a user facing feature (unless I'm missing something?). It just seems like we could avoid all the hassle of manually parsing the python ast (and all the issues that come with it) by using the json format.


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-tvm] ZihengJiang commented on pull request #6779: [WIP] Object Schema

Posted by GitBox <gi...@apache.org>.
ZihengJiang commented on pull request #6779:
URL: https://github.com/apache/incubator-tvm/pull/6779#issuecomment-720671623


   @tkonolige 
   The point of first Python is to provide a user-friendly schema frontend like ProtoBuf. **It can be used as schema but with Python-like syntax**. This principle is discussed in the RFC and with @tqchen offline. The designed behavior of `default_fhash_reduce` also comes from this point. We definitely can write JSON directly, but: 1. not friendly to use especially when the class is complicated; 2. may require backend languages to verify its correctness. After all, JSON is designed as an interexchange format instead of user interface.


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-tvm] mwillsey commented on pull request #6779: [WIP] Object Schema

Posted by GitBox <gi...@apache.org>.
mwillsey commented on pull request #6779:
URL: https://github.com/apache/incubator-tvm/pull/6779#issuecomment-720690753


   I could go either way on having the object schema in Python:
   + Pro: it's probably less verbose and it could also provide reasonable "defaults" and output very verbose JSON, rather than having each backend agree on how to interpret missing field of the JSON
   - Con: it's another build step, and ultimately writing a little bit of JSON one time isn't that bad. We could use something like YAML or TOML if we wanted to make it more user friendly
   
   I would like to echo @jroesch's concern that methods are a big part of this, as that what takes a lot of effort to get right. Also, I agree with folks above that checking-in generated code should be avoided if at all possible.
   
   If we go the route of just writing the schema by hand, we should consider not using strict JSON, as we will definitely want to support comments, trailing comma, etc in the schema.
   
   If we go python generated route, I agree with many of @tkonolige's comments above regarding simplicity. I think we should strive to keep the schema-generation code as slim as possible.


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-tvm] areusch commented on a change in pull request #6779: [WIP] Object Schema

Posted by GitBox <gi...@apache.org>.
areusch commented on a change in pull request #6779:
URL: https://github.com/apache/incubator-tvm/pull/6779#discussion_r516259261



##########
File path: schema/python/schema/parser.py
##########
@@ -0,0 +1,123 @@
+from .registry import register, lookup
+from .ir import ObjectDef, ObjectRefDef, FieldDef
+from .codegen import generate
+from . import typing as ty
+
+import re
+import ast
+import inspect
+
+
+# root class
+class Object:
+    pass
+
+class ObjectRef:
+    pass
+
+_ObjectBaseDef = ObjectDef("Object", "ObjectRef", base=None)
+register(_ObjectBaseDef)
+
+_ObjectRefBaseDef = ObjectRefDef("ObjectRef", base=None,
+    internal=_ObjectBaseDef)
+register(_ObjectRefBaseDef)
+
+
+class Parser(ast.NodeVisitor):
+    def __init__(self):
+        self.type_key = None
+        self.default_visit_attrs = True
+        self.default_sequal_reduce = True
+        self.default_shash_reduce = True
+        self.fields = []
+
+    def visit_Assign(self, node):
+        target = node.targets[0]
+        value = node.value
+        if target.id == 'type_key':
+            self.type_key = value.s
+        elif target.id == 'default_visit_attrs':
+            self.default_visit_attrs = value.value
+        elif target.id == 'default_sequal_reduce':
+            self.default_sequal_reduce = value.value
+        elif target.id == 'default_shash_reduce':
+            self.default_shash_reduce = value.value
+        self.generic_visit(node)
+
+    def visit_AnnAssign(self, node):
+        name = node.target.id
+        type_name = node.annotation.attr
+        type_ = ty.get_type(type_name)
+        self.fields.append(FieldDef(name, type_))
+        self.generic_visit(node)
+
+
+def parse_comment(text):
+    ret = {}
+    lines = text.split('\n')
+    block_delimiter = [0]
+    for lnum, line in enumerate(lines):
+        result = re.match(r"\s*-+", line)
+        if result:
+            block_delimiter.append(lnum - 1)
+    block_delimiter.append(len(lines))
+    ret['Root'] = lines[block_delimiter[0]: block_delimiter[1]]
+    for idx in range(1, len(block_delimiter) - 1):
+        key = lines[block_delimiter[idx]].strip()
+        ret[key] = lines[block_delimiter[idx]+2: block_delimiter[idx+1]]
+
+    for key in ret:
+        lines = [line.strip() for line in ret[key]]
+        # remove space lines at beginning and the end
+        while lines and not lines[0]:
+            lines.pop(0)
+        while lines and not lines[-1]:
+            lines.pop()
+        ret[key] = lines
+
+    return ret
+
+from json import JSONEncoder
+
+
+def declare(cls):
+    print('\n\n')

Review comment:
       is the plan to delete these prints because they are debug, or ?

##########
File path: schema/python/schema/parser.py
##########
@@ -0,0 +1,123 @@
+from .registry import register, lookup
+from .ir import ObjectDef, ObjectRefDef, FieldDef
+from .codegen import generate
+from . import typing as ty
+
+import re
+import ast
+import inspect
+
+
+# root class
+class Object:
+    pass
+
+class ObjectRef:
+    pass
+
+_ObjectBaseDef = ObjectDef("Object", "ObjectRef", base=None)
+register(_ObjectBaseDef)
+
+_ObjectRefBaseDef = ObjectRefDef("ObjectRef", base=None,
+    internal=_ObjectBaseDef)
+register(_ObjectRefBaseDef)
+
+
+class Parser(ast.NodeVisitor):

Review comment:
       it does seem like Python AST leaves open multiple ways to declare class members. we'll need to continue extending this parser as they are added. any reason to keep the definitions in Python? e.g. here is a perfectly legal way to add some annotations:
   
   ```
   class PrimExprNode(BaseExprNode):
     type_key = 'PrimExprNode'
   
   for field in dir(RelayExprNode):
     setattr(PrimExprNode, field, ty.int64_t)
   ```
   
   it'll be hard to catch uses of this without using AST, but it'll also be confusing to debug from a user perspective.

##########
File path: schema/python/schema/parser.py
##########
@@ -0,0 +1,123 @@
+from .registry import register, lookup
+from .ir import ObjectDef, ObjectRefDef, FieldDef
+from .codegen import generate
+from . import typing as ty
+
+import re
+import ast
+import inspect
+
+
+# root class
+class Object:
+    pass
+
+class ObjectRef:
+    pass
+
+_ObjectBaseDef = ObjectDef("Object", "ObjectRef", base=None)
+register(_ObjectBaseDef)
+
+_ObjectRefBaseDef = ObjectRefDef("ObjectRef", base=None,
+    internal=_ObjectBaseDef)
+register(_ObjectRefBaseDef)
+
+
+class Parser(ast.NodeVisitor):
+    def __init__(self):
+        self.type_key = None
+        self.default_visit_attrs = True
+        self.default_sequal_reduce = True
+        self.default_shash_reduce = True
+        self.fields = []
+
+    def visit_Assign(self, node):
+        target = node.targets[0]
+        value = node.value
+        if target.id == 'type_key':
+            self.type_key = value.s
+        elif target.id == 'default_visit_attrs':
+            self.default_visit_attrs = value.value
+        elif target.id == 'default_sequal_reduce':
+            self.default_sequal_reduce = value.value
+        elif target.id == 'default_shash_reduce':
+            self.default_shash_reduce = value.value
+        self.generic_visit(node)
+
+    def visit_AnnAssign(self, node):
+        name = node.target.id
+        type_name = node.annotation.attr
+        type_ = ty.get_type(type_name)
+        self.fields.append(FieldDef(name, type_))
+        self.generic_visit(node)
+
+
+def parse_comment(text):
+    ret = {}
+    lines = text.split('\n')
+    block_delimiter = [0]
+    for lnum, line in enumerate(lines):
+        result = re.match(r"\s*-+", line)
+        if result:
+            block_delimiter.append(lnum - 1)
+    block_delimiter.append(len(lines))
+    ret['Root'] = lines[block_delimiter[0]: block_delimiter[1]]
+    for idx in range(1, len(block_delimiter) - 1):
+        key = lines[block_delimiter[idx]].strip()
+        ret[key] = lines[block_delimiter[idx]+2: block_delimiter[idx+1]]
+
+    for key in ret:
+        lines = [line.strip() for line in ret[key]]
+        # remove space lines at beginning and the end
+        while lines and not lines[0]:
+            lines.pop(0)
+        while lines and not lines[-1]:
+            lines.pop()
+        ret[key] = lines
+
+    return ret
+
+from json import JSONEncoder

Review comment:
       move to the top of the file




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-tvm] jroesch edited a comment on pull request #6779: [WIP] Object Schema

Posted by GitBox <gi...@apache.org>.
jroesch edited a comment on pull request #6779:
URL: https://github.com/apache/incubator-tvm/pull/6779#issuecomment-720685479






----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-tvm] tqchen commented on a change in pull request #6779: [WIP] Object Schema

Posted by GitBox <gi...@apache.org>.
tqchen commented on a change in pull request #6779:
URL: https://github.com/apache/incubator-tvm/pull/6779#discussion_r516295521



##########
File path: schema/python/schema/parser.py
##########
@@ -0,0 +1,123 @@
+from .registry import register, lookup
+from .ir import ObjectDef, ObjectRefDef, FieldDef
+from .codegen import generate
+from . import typing as ty
+
+import re
+import ast
+import inspect
+
+
+# root class
+class Object:
+    pass
+
+class ObjectRef:
+    pass
+
+_ObjectBaseDef = ObjectDef("Object", "ObjectRef", base=None)
+register(_ObjectBaseDef)
+
+_ObjectRefBaseDef = ObjectRefDef("ObjectRef", base=None,
+    internal=_ObjectBaseDef)
+register(_ObjectRefBaseDef)
+
+
+class Parser(ast.NodeVisitor):

Review comment:
       In this case we do only prefer a canonical way, as oppose to multiple ways




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-tvm] tkonolige commented on a change in pull request #6779: [WIP] Object Schema

Posted by GitBox <gi...@apache.org>.
tkonolige commented on a change in pull request #6779:
URL: https://github.com/apache/incubator-tvm/pull/6779#discussion_r516161496



##########
File path: schema/python/schema/parser.py
##########
@@ -0,0 +1,123 @@
+from .registry import register, lookup
+from .ir import ObjectDef, ObjectRefDef, FieldDef
+from .codegen import generate
+from . import typing as ty
+
+import re
+import ast
+import inspect
+
+
+# root class
+class Object:
+    pass
+
+class ObjectRef:
+    pass
+
+_ObjectBaseDef = ObjectDef("Object", "ObjectRef", base=None)
+register(_ObjectBaseDef)
+
+_ObjectRefBaseDef = ObjectRefDef("ObjectRef", base=None,
+    internal=_ObjectBaseDef)
+register(_ObjectRefBaseDef)
+
+
+class Parser(ast.NodeVisitor):

Review comment:
       You actually can grab the dtype without parsing (this is what I was saying above):
   ```
   In [3]: class PrimExprNode():
      ...:     dtype: int
      ...:
   
   In [4]: PrimExprNode.__annotations__
   Out[4]: {'dtype': int}
   ```
   
   Having `default_sequal_reduce` be `True` when its base class has it `False` is a little confusing. Is there a reason for this? It seems like it breaks them assumptions people have when using inheritance.

##########
File path: schema/python/schema/ir.py
##########
@@ -0,0 +1,54 @@
+import json
+from . import typing as ty
+
+class SchemaIR(object):

Review comment:
       Personally, I cannot see a use case for having a base class here. Maybe we can add it in later if it is needed?

##########
File path: schema/python/schema/codegen.py
##########
@@ -0,0 +1,318 @@
+import re
+import subprocess
+from collections import namedtuple
+from .ir import *
+from .registry import lookup
+from . import typing as ty
+import json
+
+class ExprFunctor:

Review comment:
       It just seems that every place you call visit you know exactly what you are visiting (because there is no subclassing). For example, in
   ```
   for field in obj.fields:
       fields.append(fields_comment[field.name])
       fields.append(self.visit(field))
   ```
   we could just replace `self.visit(field)` with `self.visit_field_def(field)`. I believe the same is true of every other place `self.visit` is used.




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-tvm] ZihengJiang commented on a change in pull request #6779: [WIP] Object Schema

Posted by GitBox <gi...@apache.org>.
ZihengJiang commented on a change in pull request #6779:
URL: https://github.com/apache/incubator-tvm/pull/6779#discussion_r516311228



##########
File path: schema/python/schema/parser.py
##########
@@ -0,0 +1,123 @@
+from .registry import register, lookup
+from .ir import ObjectDef, ObjectRefDef, FieldDef
+from .codegen import generate
+from . import typing as ty
+
+import re
+import ast
+import inspect
+
+
+# root class
+class Object:
+    pass
+
+class ObjectRef:
+    pass
+
+_ObjectBaseDef = ObjectDef("Object", "ObjectRef", base=None)
+register(_ObjectBaseDef)
+
+_ObjectRefBaseDef = ObjectRefDef("ObjectRef", base=None,
+    internal=_ObjectBaseDef)
+register(_ObjectRefBaseDef)
+
+
+class Parser(ast.NodeVisitor):
+    def __init__(self):
+        self.type_key = None
+        self.default_visit_attrs = True
+        self.default_sequal_reduce = True
+        self.default_shash_reduce = True
+        self.fields = []
+
+    def visit_Assign(self, node):
+        target = node.targets[0]
+        value = node.value
+        if target.id == 'type_key':
+            self.type_key = value.s
+        elif target.id == 'default_visit_attrs':
+            self.default_visit_attrs = value.value
+        elif target.id == 'default_sequal_reduce':
+            self.default_sequal_reduce = value.value
+        elif target.id == 'default_shash_reduce':
+            self.default_shash_reduce = value.value
+        self.generic_visit(node)
+
+    def visit_AnnAssign(self, node):
+        name = node.target.id
+        type_name = node.annotation.attr
+        type_ = ty.get_type(type_name)
+        self.fields.append(FieldDef(name, type_))
+        self.generic_visit(node)
+
+
+def parse_comment(text):
+    ret = {}
+    lines = text.split('\n')
+    block_delimiter = [0]
+    for lnum, line in enumerate(lines):
+        result = re.match(r"\s*-+", line)
+        if result:
+            block_delimiter.append(lnum - 1)
+    block_delimiter.append(len(lines))
+    ret['Root'] = lines[block_delimiter[0]: block_delimiter[1]]
+    for idx in range(1, len(block_delimiter) - 1):
+        key = lines[block_delimiter[idx]].strip()
+        ret[key] = lines[block_delimiter[idx]+2: block_delimiter[idx+1]]
+
+    for key in ret:
+        lines = [line.strip() for line in ret[key]]
+        # remove space lines at beginning and the end
+        while lines and not lines[0]:
+            lines.pop(0)
+        while lines and not lines[-1]:
+            lines.pop()
+        ret[key] = lines
+
+    return ret
+
+from json import JSONEncoder
+
+
+def declare(cls):
+    print('\n\n')

Review comment:
       This will be deleted. Current code is still WIP.




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org