def add_sheet(self, sheetname, cell_overwrite_ok=False): from arelle import Worksheet, Utils if not isinstance(sheetname, str): sheetname = sheetname.decode(self.encoding) if not Utils.valid_sheet_name(sheetname): raise Exception("invalid worksheet name %r" % sheetname) lower_name = sheetname.lower() if lower_name in self.__worksheet_idx_from_name: raise Exception("duplicate worksheet name %r" % sheetname) self.__worksheet_idx_from_name[lower_name] = len(self.__worksheets) self.__worksheets.append(Worksheet(sheetname, self, cell_overwrite_ok)) return self.__worksheets[-1]
def primary(self, arg_type ): str_tok = None int_tok = None num_tok = None ref2d_tok = None ref2d1_tok = None ref2d2_tok = None ref3d_ref2d = None ref3d_ref2d2 = None name_tok = None func_tok = None la1 = self.LA(1) if False: pass elif la1 and la1 in [TRUE_CONST]: pass self.match(TRUE_CONST) self.rpn += struct.pack("2B", ptgBool, 1) elif la1 and la1 in [FALSE_CONST]: pass self.match(FALSE_CONST) self.rpn += struct.pack("2B", ptgBool, 0) elif la1 and la1 in [STR_CONST]: pass str_tok = self.LT(1) self.match(STR_CONST) self.rpn += struct.pack("B", ptgStr) + upack1(str_tok.text[1:-1].replace("\"\"", "\"")) elif la1 and la1 in [NUM_CONST]: pass num_tok = self.LT(1) self.match(NUM_CONST) self.rpn += struct.pack("<Bd", ptgNum, float(num_tok.text)) elif la1 and la1 in [FUNC_IF]: pass self.match(FUNC_IF) self.match(LP) self.expr("V") la1 = self.LA(1) if False: pass elif la1 and la1 in [SEMICOLON]: pass self.match(SEMICOLON) elif la1 and la1 in [COMMA]: pass self.match(COMMA) else: raise antlr.NoViableAltException(self.LT(1), self.getFilename()) self.rpn += struct.pack("<BBH", ptgAttr, 0x02, 0) # tAttrIf pos0 = len(self.rpn) - 2 self.expr(arg_type) la1 = self.LA(1) if False: pass elif la1 and la1 in [SEMICOLON]: pass self.match(SEMICOLON) elif la1 and la1 in [COMMA]: pass self.match(COMMA) else: raise antlr.NoViableAltException(self.LT(1), self.getFilename()) self.rpn += struct.pack("<BBH", ptgAttr, 0x08, 0) # tAttrSkip pos1 = len(self.rpn) - 2 self.rpn = self.rpn[:pos0] + struct.pack("<H", pos1-pos0) + self.rpn[pos0+2:] self.expr(arg_type) self.match(RP) self.rpn += struct.pack("<BBH", ptgAttr, 0x08, 3) # tAttrSkip self.rpn += struct.pack("<BBH", ptgFuncVarR, 3, 1) # 3 = nargs, 1 = IF func pos2 = len(self.rpn) self.rpn = self.rpn[:pos1] + struct.pack("<H", pos2-(pos1+2)-1) + self.rpn[pos1+2:] elif la1 and la1 in [FUNC_CHOOSE]: pass self.match(FUNC_CHOOSE) arg_type = b"R" rpn_chunks = [] self.match(LP) self.expr("V") rpn_start = len(self.rpn) ref_markers = [len(self.sheet_references)] while True: if (self.LA(1)==COMMA or self.LA(1)==SEMICOLON): pass la1 = self.LA(1) if False: pass elif la1 and la1 in [SEMICOLON]: pass self.match(SEMICOLON) elif la1 and la1 in [COMMA]: pass self.match(COMMA) else: raise antlr.NoViableAltException(self.LT(1), self.getFilename()) mark = len(self.rpn) la1 = self.LA(1) if False: pass elif la1 and la1 in [TRUE_CONST,FALSE_CONST,STR_CONST,NUM_CONST,INT_CONST,FUNC_IF,FUNC_CHOOSE,NAME,QUOTENAME,SUB,LP,REF2D]: pass self.expr(arg_type) elif la1 and la1 in [RP,COMMA,SEMICOLON]: pass self.rpn += struct.pack("B", ptgMissArg) else: raise antlr.NoViableAltException(self.LT(1), self.getFilename()) rpn_chunks.append(self.rpn[mark:]) ref_markers.append(len(self.sheet_references)) else: break self.match(RP) self.rpn = self.rpn[:rpn_start] nc = len(rpn_chunks) chunklens = [len(chunk) for chunk in rpn_chunks] skiplens = [0] * nc skiplens[-1] = 3 for ic in range(nc-1, 0, -1): skiplens[ic-1] = skiplens[ic] + chunklens[ic] + 4 jump_pos = [2 * nc + 2] for ic in range(nc): jump_pos.append(jump_pos[-1] + chunklens[ic] + 4) chunk_shift = 2 * nc + 6 # size of tAttrChoose for ic in range(nc): for refx in range(ref_markers[ic], ref_markers[ic+1]): ref = self.sheet_references[refx] self.sheet_references[refx] = (ref[0], ref[1], ref[2] + chunk_shift) chunk_shift += 4 # size of tAttrSkip choose_rpn = [] choose_rpn.append(struct.pack("<BBH", ptgAttr, 0x04, nc)) # 0x04 is tAttrChoose choose_rpn.append(struct.pack("<%dH" % (nc+1), *jump_pos)) for ic in range(nc): choose_rpn.append(rpn_chunks[ic]) choose_rpn.append(struct.pack("<BBH", ptgAttr, 0x08, skiplens[ic])) # 0x08 is tAttrSkip choose_rpn.append(struct.pack("<BBH", ptgFuncVarV, nc+1, 100)) # 100 is CHOOSE fn self.rpn += b"".join(choose_rpn) elif la1 and la1 in [LP]: pass self.match(LP) self.expr(arg_type) self.match(RP) self.rpn += struct.pack("B", ptgParen) else: if (self.LA(1)==INT_CONST) and (_tokenSet_0.member(self.LA(2))): pass int_tok = self.LT(1) self.match(INT_CONST) # print "**int_const", int_tok.text int_value = int(int_tok.text) if int_value <= 65535: self.rpn += struct.pack("<BH", ptgInt, int_value) else: self.rpn += struct.pack("<Bd", ptgNum, float(int_value)) elif (self.LA(1)==REF2D) and (_tokenSet_0.member(self.LA(2))): pass ref2d_tok = self.LT(1) self.match(REF2D) # print "**ref2d %s %s" % (ref2d_tok.text, arg_type) r, c = Utils.cell_to_packed_rowcol(ref2d_tok.text) ptg = ptgRefR + _RVAdeltaRef[arg_type] self.rpn += struct.pack("<B2H", ptg, r, c) elif (self.LA(1)==REF2D) and (self.LA(2)==COLON): pass ref2d1_tok = self.LT(1) self.match(REF2D) self.match(COLON) ref2d2_tok = self.LT(1) self.match(REF2D) r1, c1 = Utils.cell_to_packed_rowcol(ref2d1_tok.text) r2, c2 = Utils.cell_to_packed_rowcol(ref2d2_tok.text) ptg = ptgAreaR + _RVAdeltaArea[arg_type] self.rpn += struct.pack("<B4H", ptg, r1, r2, c1, c2) elif (self.LA(1)==INT_CONST or self.LA(1)==NAME or self.LA(1)==QUOTENAME) and (self.LA(2)==COLON or self.LA(2)==BANG): pass sheet1=self.sheet() sheet2 = sheet1 la1 = self.LA(1) if False: pass elif la1 and la1 in [COLON]: pass self.match(COLON) sheet2=self.sheet() elif la1 and la1 in [BANG]: pass else: raise antlr.NoViableAltException(self.LT(1), self.getFilename()) self.match(BANG) ref3d_ref2d = self.LT(1) self.match(REF2D) ptg = ptgRef3dR + _RVAdeltaRef[arg_type] rpn_ref2d = b"" r1, c1 = Utils.cell_to_packed_rowcol(ref3d_ref2d.text) rpn_ref2d = struct.pack("<3H", 0x0000, r1, c1) la1 = self.LA(1) if False: pass elif la1 and la1 in [COLON]: pass self.match(COLON) ref3d_ref2d2 = self.LT(1) self.match(REF2D) ptg = ptgArea3dR + _RVAdeltaArea[arg_type] r2, c2 = Utils.cell_to_packed_rowcol(ref3d_ref2d2.text) rpn_ref2d = struct.pack("<5H", 0x0000, r1, r2, c1, c2) elif la1 and la1 in [EOF,EQ,NE,GT,LT,GE,LE,ADD,SUB,MUL,DIV,POWER,PERCENT,RP,COMMA,SEMICOLON,CONCAT]: pass else: raise antlr.NoViableAltException(self.LT(1), self.getFilename()) self.rpn += struct.pack("<B", ptg) self.sheet_references.append((sheet1, sheet2, len(self.rpn))) self.rpn += rpn_ref2d elif (self.LA(1)==NAME) and (_tokenSet_0.member(self.LA(2))): name_tok = self.LT(1) self.match(NAME) raise Exception("[formula] found unexpected NAME token (%r)" % name_tok.txt) # #### TODO: handle references to defined names here elif (self.LA(1)==NAME) and (self.LA(2)==LP): func_tok = self.LT(1) self.match(NAME) func_toku = func_tok.text.upper() if func_toku in all_funcs_by_name: (opcode, min_argc, max_argc, func_type, arg_type_str) = all_funcs_by_name[func_toku] arg_type_list = list(arg_type_str) else: raise Exception("[formula] unknown function (%s)" % func_tok.text) # print "**func_tok1 %s %s" % (func_toku, func_type) xcall = opcode < 0 if xcall: # The name of the add-in function is passed as the 1st arg # of the hidden XCALL function self.xcall_references.append((func_toku, len(self.rpn) + 1)) self.rpn += struct.pack("<BHHH", ptgNameXR, 0xadde, # ##PATCHME## index to REF entry in EXTERNSHEET record 0xefbe, # ##PATCHME## one-based index to EXTERNNAME record 0x0000) # unused self.match(LP) arg_count=self.expr_list(arg_type_list, min_argc, max_argc) self.match(RP) if arg_count > max_argc or arg_count < min_argc: raise Exception("%d parameters for function: %s" % (arg_count, func_tok.text)) if xcall: func_ptg = ptgFuncVarR + _RVAdelta[func_type] self.rpn += struct.pack("<2BH", func_ptg, arg_count + 1, 255) # 255 is magic XCALL function elif min_argc == max_argc: func_ptg = ptgFuncR + _RVAdelta[func_type] self.rpn += struct.pack("<BH", func_ptg, opcode) elif arg_count == 1 and func_tok.text.upper() == "SUM": self.rpn += struct.pack("<BBH", ptgAttr, 0x10, 0) # tAttrSum else: func_ptg = ptgFuncVarR + _RVAdelta[func_type] self.rpn += struct.pack("<2BH", func_ptg, arg_count, opcode) else: raise antlr.NoViableAltException(self.LT(1), self.getFilename())
def primary(self, arg_type): str_tok = None int_tok = None num_tok = None ref2d_tok = None ref2d1_tok = None ref2d2_tok = None ref3d_ref2d = None ref3d_ref2d2 = None name_tok = None func_tok = None la1 = self.LA(1) if False: pass elif la1 and la1 in [TRUE_CONST]: pass self.match(TRUE_CONST) self.rpn += struct.pack("2B", ptgBool, 1) elif la1 and la1 in [FALSE_CONST]: pass self.match(FALSE_CONST) self.rpn += struct.pack("2B", ptgBool, 0) elif la1 and la1 in [STR_CONST]: pass str_tok = self.LT(1) self.match(STR_CONST) self.rpn += struct.pack("B", ptgStr) + upack1( str_tok.text[1:-1].replace("\"\"", "\"")) elif la1 and la1 in [NUM_CONST]: pass num_tok = self.LT(1) self.match(NUM_CONST) self.rpn += struct.pack("<Bd", ptgNum, float(num_tok.text)) elif la1 and la1 in [FUNC_IF]: pass self.match(FUNC_IF) self.match(LP) self.expr("V") la1 = self.LA(1) if False: pass elif la1 and la1 in [SEMICOLON]: pass self.match(SEMICOLON) elif la1 and la1 in [COMMA]: pass self.match(COMMA) else: raise antlr.NoViableAltException(self.LT(1), self.getFilename()) self.rpn += struct.pack("<BBH", ptgAttr, 0x02, 0) # tAttrIf pos0 = len(self.rpn) - 2 self.expr(arg_type) la1 = self.LA(1) if False: pass elif la1 and la1 in [SEMICOLON]: pass self.match(SEMICOLON) elif la1 and la1 in [COMMA]: pass self.match(COMMA) else: raise antlr.NoViableAltException(self.LT(1), self.getFilename()) self.rpn += struct.pack("<BBH", ptgAttr, 0x08, 0) # tAttrSkip pos1 = len(self.rpn) - 2 self.rpn = self.rpn[:pos0] + struct.pack( "<H", pos1 - pos0) + self.rpn[pos0 + 2:] self.expr(arg_type) self.match(RP) self.rpn += struct.pack("<BBH", ptgAttr, 0x08, 3) # tAttrSkip self.rpn += struct.pack("<BBH", ptgFuncVarR, 3, 1) # 3 = nargs, 1 = IF func pos2 = len(self.rpn) self.rpn = self.rpn[:pos1] + struct.pack( "<H", pos2 - (pos1 + 2) - 1) + self.rpn[pos1 + 2:] elif la1 and la1 in [FUNC_CHOOSE]: pass self.match(FUNC_CHOOSE) arg_type = b"R" rpn_chunks = [] self.match(LP) self.expr("V") rpn_start = len(self.rpn) ref_markers = [len(self.sheet_references)] while True: if (self.LA(1) == COMMA or self.LA(1) == SEMICOLON): pass la1 = self.LA(1) if False: pass elif la1 and la1 in [SEMICOLON]: pass self.match(SEMICOLON) elif la1 and la1 in [COMMA]: pass self.match(COMMA) else: raise antlr.NoViableAltException( self.LT(1), self.getFilename()) mark = len(self.rpn) la1 = self.LA(1) if False: pass elif la1 and la1 in [ TRUE_CONST, FALSE_CONST, STR_CONST, NUM_CONST, INT_CONST, FUNC_IF, FUNC_CHOOSE, NAME, QUOTENAME, SUB, LP, REF2D ]: pass self.expr(arg_type) elif la1 and la1 in [RP, COMMA, SEMICOLON]: pass self.rpn += struct.pack("B", ptgMissArg) else: raise antlr.NoViableAltException( self.LT(1), self.getFilename()) rpn_chunks.append(self.rpn[mark:]) ref_markers.append(len(self.sheet_references)) else: break self.match(RP) self.rpn = self.rpn[:rpn_start] nc = len(rpn_chunks) chunklens = [len(chunk) for chunk in rpn_chunks] skiplens = [0] * nc skiplens[-1] = 3 for ic in range(nc - 1, 0, -1): skiplens[ic - 1] = skiplens[ic] + chunklens[ic] + 4 jump_pos = [2 * nc + 2] for ic in range(nc): jump_pos.append(jump_pos[-1] + chunklens[ic] + 4) chunk_shift = 2 * nc + 6 # size of tAttrChoose for ic in range(nc): for refx in range(ref_markers[ic], ref_markers[ic + 1]): ref = self.sheet_references[refx] self.sheet_references[refx] = (ref[0], ref[1], ref[2] + chunk_shift) chunk_shift += 4 # size of tAttrSkip choose_rpn = [] choose_rpn.append(struct.pack("<BBH", ptgAttr, 0x04, nc)) # 0x04 is tAttrChoose choose_rpn.append(struct.pack("<%dH" % (nc + 1), *jump_pos)) for ic in range(nc): choose_rpn.append(rpn_chunks[ic]) choose_rpn.append( struct.pack("<BBH", ptgAttr, 0x08, skiplens[ic])) # 0x08 is tAttrSkip choose_rpn.append(struct.pack("<BBH", ptgFuncVarV, nc + 1, 100)) # 100 is CHOOSE fn self.rpn += b"".join(choose_rpn) elif la1 and la1 in [LP]: pass self.match(LP) self.expr(arg_type) self.match(RP) self.rpn += struct.pack("B", ptgParen) else: if (self.LA(1) == INT_CONST) and (_tokenSet_0.member(self.LA(2))): pass int_tok = self.LT(1) self.match(INT_CONST) # print "**int_const", int_tok.text int_value = int(int_tok.text) if int_value <= 65535: self.rpn += struct.pack("<BH", ptgInt, int_value) else: self.rpn += struct.pack("<Bd", ptgNum, float(int_value)) elif (self.LA(1) == REF2D) and (_tokenSet_0.member(self.LA(2))): pass ref2d_tok = self.LT(1) self.match(REF2D) # print "**ref2d %s %s" % (ref2d_tok.text, arg_type) r, c = Utils.cell_to_packed_rowcol(ref2d_tok.text) ptg = ptgRefR + _RVAdeltaRef[arg_type] self.rpn += struct.pack("<B2H", ptg, r, c) elif (self.LA(1) == REF2D) and (self.LA(2) == COLON): pass ref2d1_tok = self.LT(1) self.match(REF2D) self.match(COLON) ref2d2_tok = self.LT(1) self.match(REF2D) r1, c1 = Utils.cell_to_packed_rowcol(ref2d1_tok.text) r2, c2 = Utils.cell_to_packed_rowcol(ref2d2_tok.text) ptg = ptgAreaR + _RVAdeltaArea[arg_type] self.rpn += struct.pack("<B4H", ptg, r1, r2, c1, c2) elif (self.LA(1) == INT_CONST or self.LA(1) == NAME or self.LA(1) == QUOTENAME) and (self.LA(2) == COLON or self.LA(2) == BANG): pass sheet1 = self.sheet() sheet2 = sheet1 la1 = self.LA(1) if False: pass elif la1 and la1 in [COLON]: pass self.match(COLON) sheet2 = self.sheet() elif la1 and la1 in [BANG]: pass else: raise antlr.NoViableAltException(self.LT(1), self.getFilename()) self.match(BANG) ref3d_ref2d = self.LT(1) self.match(REF2D) ptg = ptgRef3dR + _RVAdeltaRef[arg_type] rpn_ref2d = b"" r1, c1 = Utils.cell_to_packed_rowcol(ref3d_ref2d.text) rpn_ref2d = struct.pack("<3H", 0x0000, r1, c1) la1 = self.LA(1) if False: pass elif la1 and la1 in [COLON]: pass self.match(COLON) ref3d_ref2d2 = self.LT(1) self.match(REF2D) ptg = ptgArea3dR + _RVAdeltaArea[arg_type] r2, c2 = Utils.cell_to_packed_rowcol(ref3d_ref2d2.text) rpn_ref2d = struct.pack("<5H", 0x0000, r1, r2, c1, c2) elif la1 and la1 in [ EOF, EQ, NE, GT, LT, GE, LE, ADD, SUB, MUL, DIV, POWER, PERCENT, RP, COMMA, SEMICOLON, CONCAT ]: pass else: raise antlr.NoViableAltException(self.LT(1), self.getFilename()) self.rpn += struct.pack("<B", ptg) self.sheet_references.append((sheet1, sheet2, len(self.rpn))) self.rpn += rpn_ref2d elif (self.LA(1) == NAME) and (_tokenSet_0.member(self.LA(2))): name_tok = self.LT(1) self.match(NAME) raise Exception("[formula] found unexpected NAME token (%r)" % name_tok.txt) # #### TODO: handle references to defined names here elif (self.LA(1) == NAME) and (self.LA(2) == LP): func_tok = self.LT(1) self.match(NAME) func_toku = func_tok.text.upper() if func_toku in all_funcs_by_name: (opcode, min_argc, max_argc, func_type, arg_type_str) = all_funcs_by_name[func_toku] arg_type_list = list(arg_type_str) else: raise Exception("[formula] unknown function (%s)" % func_tok.text) # print "**func_tok1 %s %s" % (func_toku, func_type) xcall = opcode < 0 if xcall: # The name of the add-in function is passed as the 1st arg # of the hidden XCALL function self.xcall_references.append( (func_toku, len(self.rpn) + 1)) self.rpn += struct.pack( "<BHHH", ptgNameXR, 0xadde, # ##PATCHME## index to REF entry in EXTERNSHEET record 0xefbe, # ##PATCHME## one-based index to EXTERNNAME record 0x0000) # unused self.match(LP) arg_count = self.expr_list(arg_type_list, min_argc, max_argc) self.match(RP) if arg_count > max_argc or arg_count < min_argc: raise Exception("%d parameters for function: %s" % (arg_count, func_tok.text)) if xcall: func_ptg = ptgFuncVarR + _RVAdelta[func_type] self.rpn += struct.pack("<2BH", func_ptg, arg_count + 1, 255) # 255 is magic XCALL function elif min_argc == max_argc: func_ptg = ptgFuncR + _RVAdelta[func_type] self.rpn += struct.pack("<BH", func_ptg, opcode) elif arg_count == 1 and func_tok.text.upper() == "SUM": self.rpn += struct.pack("<BBH", ptgAttr, 0x10, 0) # tAttrSum else: func_ptg = ptgFuncVarR + _RVAdelta[func_type] self.rpn += struct.pack("<2BH", func_ptg, arg_count, opcode) else: raise antlr.NoViableAltException(self.LT(1), self.getFilename())