diff --git a/texla/Parser/Blocks/Block.py b/texla/Parser/Blocks/Block.py index 206d8b1..3c45e17 100644 --- a/texla/Parser/Blocks/Block.py +++ b/texla/Parser/Blocks/Block.py @@ -1,134 +1,133 @@ from .Utilities import * """Base Block definition""" class Block: """ Block general attributes: -block_name: the new of the "type" of the block -id: unique id for the block in the tree -parent_block: parent in the tree -attributes: a dictionary for description of the block. All useful parser data go into attributes -ch_blocks: a list of children_blocks -section_level: the position of the block compared to sectioning levels defined in utility.py Derived Block could add more attributes. """ @staticmethod def parse(parser, tex, parent_block, params): """ The method must return a tuple with the created Block and the last used index of tex string.""" pass def __init__(self, block_name, content, parent_block): """ Base constructor for Block. It saves the parent_block and block name and create the new id for the new block. It creates data structures like the attributed dictionary and children nodes list. It always saves a content variable. By default, it sets the section_level of the block to that of the parend_block. """ self.block_name = block_name self.content = content if not parent_block is None: self.parent_block = parent_block self.id = parent_block.id + '-' + utility.get_random_string(3) #Section level: #by default the level is the same of parent block self.section_level = self.parent_block.section_level #depth in the tree self.tree_depth = self.parent_block.tree_depth+1 else: #if this is the root block self.parent_block = None self.id = '@' self.section_level = -1 self.tree_depth = 0 #dictionary for attributes - self.attributes = {'N_chblocks' : 0} + self.attributes = {} #list for childrend blocks self.ch_blocks = [] self.N_chblocks = 0 def add_child_block(self, block): """ IMPORTANT: this function is called by the self.parse fuction. It MUST NOT be called from outside, expecially the parser """ self.ch_blocks.append(block) self.N_chblocks +=1 - self.attributes['N_chblocks']+=1 def add_children_blocks(self, blocks): """ IMPORTANT: this function is called by the self.parse fuction. It MUST NOT be called from outside, expecially the parser """ self.ch_blocks += blocks self.N_chblocks +=len(blocks) - self.attributes['N_chblocks']+=len(blocks) def change_parent_block(self, new_parent): """s function changes the parent of the block. It changes parent object, id, and tree_depth. The section level is not changes for consistency. All children are updated. - """ + """ self.parent_block = new_parent #rebuiding id self.id = new_parent.id + '-' + utility.get_random_string(3) #the section level is not changed, #but tree_depth is updated self.tree_depth = new_parent. tree_depth + 1 #now childrens are updated for ch in self.ch_blocks: ch.change_parent_block(self) def get_children(self, bl_name): """ This function return a list of children blocks corresponding to the requested type. If there are not children blocks of that type it returns a void list.""" result = [] for bl in self.ch_blocks: if bl.block_name == bl_name: result.append(bl) return result def __str__(self): return ''.format( self.block_name, self.id) def to_json(self, level=0): """ This functions create a json ouput that represents the tree of subblocks of the called block. """ json = '' levelb = level+3 json += (' '*level + '{\n') json += (' '*levelb + '"ID":"'+ self.id+'",\n') json += (' '*levelb + '"block_name":"'+ self.block_name+'",\n') + json += (' '*levelb + '"N. ch_blocks":"'+ str(self.N_chblocks)+'",\n') json += (' '*levelb + '"tree_depth":"'+ str(self.tree_depth)+'",\n') for k,v in self.attributes.items(): json += (' '*levelb + '"'+k+ '":"'+str(v)+ '",\n' ) json += (' '*levelb + '"children_blocks":[\n') for b in self.ch_blocks: json+= b.to_json(levelb+3) json += (' '*levelb+'],\n') json += (' '*level + '}\n') return json def n_blocks(self): """s function returns the - number of all children blocks recursively.""" + number of all children blocks recursively.""" n = len(self.ch_blocks) for c in self.ch_blocks: n+= c.n_blocks() return n diff --git a/texla/Parser/Blocks/DefaultBlock.py b/texla/Parser/Blocks/DefaultBlock.py index 0bdc4c8..90d4f20 100644 --- a/texla/Parser/Blocks/DefaultBlock.py +++ b/texla/Parser/Blocks/DefaultBlock.py @@ -1,49 +1,50 @@ '''Default Block''' import logging from .Utilities import * from .Block import Block class DefaultBlock(Block): ''' This Block is used when the parser doesn't find a proper parser_hook to call for a matched env or command''' @staticmethod def parse_env(parser ,tex, parent_block, params): #getting the name of env if 'env' in params: env_name = params['env'] else: env_name = 'no_env' if 'star' in params: env_name = env_name + '*' if params['star'] else env_name #default block is created block = DefaultBlock(tex, env_name, parent_block) #We cannot look inside tex, we don't know #what to parser. #we return the block return block @staticmethod def parse_cmd(parser ,tex, parent_block, params): cmd = params['cmd'] cmd = cmd + '*' if params['star'] else cmd #the options has to be matched from the tex match = CommandParser.get_command_options(tex) #match is (options string, left tex ptex = '\\'+cmd+match[0] #default block is created block = DefaultBlock(ptex, cmd, parent_block) #we return the block and the left tex to parse return (block, match[1]) def __init__(self, tex, block_name, parent_block): super().__init__('default', tex, parent_block) #the tex is added also as attribute self.type = block_name - self.attributes['content'] = tex + self.attributes["type"] = block_name + #the content is already saved by the base block parser_hooks = { 'default_env' : DefaultBlock.parse_env, 'default_cmd' : DefaultBlock.parse_cmd, } diff --git a/texla/Parser/Blocks/MathBlocks.py b/texla/Parser/Blocks/MathBlocks.py index 85e47a7..d00b7cc 100644 --- a/texla/Parser/Blocks/MathBlocks.py +++ b/texla/Parser/Blocks/MathBlocks.py @@ -1,83 +1,97 @@ import logging import re from .Utilities import * from .ReferenceBlocks import LabelBlock from .Block import Block class MathBlock(Block): @staticmethod def parse_math_env(parser, tex, parent_block, params): ''' This parse hook it's used for $$, $, \[ \( and general math environments''' env = params['env'] star = params.get('star',False) #getting labels and tex without labels tex, labels = MathBlock.parse_labels(tex) #the content of the math is stripped block = MathBlock(env, star, tex.strip(), parent_block) #creating and adding labels blocks for l in labels: lblock = LabelBlock(l, block) logging.debug('BLOCK @ %s%s', "\t"*lblock.tree_depth, str(lblock)) block.labels.append(lblock) return block @staticmethod def parse_ensure_math(parser, tex, parent_block, params): ''' The \ensuremath{} is a math command, not env''' options, left_tex = CommandParser.parse_options(tex, [('math','{','}')]) text = options['math'] block = MathBlock('ensuremath', False, text, parent_block) return (block, left_tex) + @staticmethod + def parse_empheq(parser, tex, parent_block, params): + '''We need to extract the right environment from the options ''' + options, content = CommandParser.parse_options(tex, + [("emph_opt","[","]"), ("env", "{","}")]) + env = options["env"] + star = False + if env.endswith("*"): + env = env[:-1] + star = True + block = MathBlock(env, star, content, parent_block) + return block + + @staticmethod def parse_labels(tex): ''' The function get labels from math. Multiple labels in math are allowed. It creates a list of Label mathced and removes them from the tex. It returns the modified tex and list of labels. ''' lre = re.compile(r'\\label\s*\{(?P