def _semantic_analysis(cls, prefixes, query): # no query if len(query) == 0: return None # analyse prefixes prefix_from = None save_files = 0 delete_files = 0 print_files = 0 prefixes_iter = iter(prefixes) for token in prefixes_iter: if type(token[0]) is not str: raise error.SyntaxError(token) token = token[0] # save files if token in Exp.FROM: prefix_from = next(prefixes_iter) prefix_from = Token.from_var(''.join(prefix_from)) elif token in Exp.SAVE: save_files += 1 # delete files elif token in Exp.DELETE: delete_files += 1 # print variables elif token in Exp.PRINT: print_files += 1 # check overlap if save_files + delete_files + print_files >= 2: raise error.SyntaxError(token) query = query.to_data() # (save, delete, print) files for op, test, func in zip( [Exp.SAVE[0], Exp.DELETE[0], Exp.PRINT[0]], [save_files, delete_files, print_files], [Token.from_save, Token.from_delete, Token.from_print]): if not test: continue if query.data_type == Token.TYPE_VARIABLE: return func(prefix_from, query) if query.data_type == Token.TYPE_TUPLE: return func(prefix_from, *query.args) else: raise error.SyntaxError(op) # just data return query
def check_sizeof(self): if self.head in [ Exp.NUMBER, Exp.VARIABLE, ]: pass elif self.head in Exp.Tokens_Shell: pass elif self.head in Exp.IDX: if 1 <= len(self) <= 3: pass else: raise error.SyntaxError(self.head) elif len(self) != 2: raise error.SyntaxError(self.head) for token in self: if type(token) is TokenTree: token.check_sizeof()
def append(self, target): super().append(target) if type(target) is TokenTree: self.pointer += 1 # check subject is numeric if self.head == Exp.VARIABLE and len(self) == 1: if type(target) is str: if len(self._is_number(self[0])[1]) > 0: raise error.SyntaxError(self[0])
def close(self, token_end: str): # make shell shape shell = self.head + token_end if shell not in Exp.Tokens_Shell: raise error.SyntaxError(token_end) if shell in Exp.SHELL_RR and not self.has_subject and len(self) == 1: item = self[0] # remove shell () if shell is tuple, and the only item is an operator or shells if item.head in Exp.Tokens_Operator + Exp.SHELL_RR + [ Exp.VARIABLE ]: last_object = self.pop() self.__iadd__(last_object) self.head = last_object.head self.has_subject = item.has_subject self.breakpoint = item.breakpoint return self.head = shell return
def _parser(cls, tokens): prefixes = TokenTree(None, Exp.SHELL_RR[0]) query = TokenTree(None, Exp.VARIABLE) object_attr = query for w in tokens: # comments if w == Exp.COMMENT: break # indents if w in Exp.INDENT: if object_attr.head == Exp.VARIABLE: # start with character if len(object_attr) > 0: object_attr.append(w) elif len(object_attr) > 0: # start with character if type(object_attr[-1]) is str: object_attr.append(w) continue # exp if w in Exp.ADD + Exp.SUB: if type(object_attr[-1]) is str: if object_attr[-1].endswith( 'e') and object_attr[-1][0].isdigit(): object_attr.append(w) continue # subjects # check operator overlap if len(object_attr) == 0: if w in Exp.Signs_All and w not in Exp.IDX: # not shell if object_attr.head in Exp.Tokens_Open and w in Exp.Tokens_Open + Exp.Tokens_Close: pass # not variable or shell elif object_attr.head in Exp.VARIABLE and w in Exp.Tokens_Open: pass # not unary operator (-) elif w in Exp.SUB: pass else: raise error.SyntaxError(w) # attribute if w == Exp.COMMA: # move to shell while object_attr.head not in Exp.Tokens_Open: object_attr.tokenize() last_object = object_attr.parent # indices if object_attr.head in Exp.IDX: if last_object is None: raise error.SyntaxError(object_attr.head) object_attr = last_object break # new tuple if last_object is None: # variable -> tuple if object_attr.head == Exp.VARIABLE: object_attr.head = Exp.SHELL_RR[0] break # = if object_attr.head in Exp.IS: if object_attr[-1].head not in Exp.SHELL_RR: object_attr = object_attr.insert_upper( Exp.SHELL_RR[0]) else: object_attr = object_attr[-1] break # is tuple object_attr.breakpoint = object_attr.pointer break # else : goto upper object_attr = last_object object_attr.tokenize() object_attr.breakpoint = object_attr.pointer # prefixes elif w in Exp.Tokens_Prefix: # not from- prefix if w not in Exp.FROM: if object_attr.parent is None and object_attr.head == Exp.VARIABLE: if len(query) > 0: prefixes.append(query) prefixes.append(w) prefixes.tokenize() query = TokenTree(None, Exp.SHELL_RR[0]) object_attr = query continue # from- prefix elif object_attr.parent is None and len(object_attr) == 0: prefixes.append(w) prefixes.tokenize() continue raise error.SyntaxError(w) # open shells elif w in Exp.Tokens_Open: object_attr.tokenize() # in () if object_attr.head in Exp.RBO: # if empty shell : tuple if len(object_attr) == 0: # only () if w not in Exp.RBO: raise error.SyntaxError(w) object_attr = object_attr.insert_inner(w) object_attr.has_subject = False continue # if comma ahead if len(object_attr) == object_attr.breakpoint: # only () if w not in Exp.RBO: raise error.SyntaxError(w) object_attr = object_attr.insert_inner(w) object_attr.has_subject = False continue # else : decorate subject object_attr = object_attr.insert_upper(w) object_attr.has_subject = True object_attr.breakpoint = object_attr.pointer continue # = if object_attr.head in Exp.IS + Exp.DIS: # tuple if len(object_attr) == 1: # only () if w not in Exp.RBO: raise error.SyntaxError(w) object_attr = object_attr.insert_inner(w) object_attr.has_subject = False continue # decorate object if len(object_attr) == 2: object_attr = object_attr.insert_upper(w) object_attr.has_subject = True object_attr.breakpoint = object_attr.pointer continue raise error.SyntaxError(w) # just operators if object_attr.head in Exp.Tokens_Operator: # parent is operator if len(object_attr ) == 2 and object_attr.head in Exp.Tokens_Operator: object_attr = object_attr.insert_upper(w) object_attr.has_subject = True continue # must be tuple if len(object_attr) != 1: raise error.SyntaxError(w) # only () if w not in Exp.RBO: raise error.SyntaxError(w) object_attr = object_attr.insert_inner(w) object_attr.has_subject = False continue # exception : null query if len(query) == 0: # only () if w not in Exp.RBO: raise error.SyntaxError(w) query = object_attr = object_attr.insert_inner(w) object_attr.has_subject = False continue raise error.SyntaxError(w) # close shells elif w in Exp.Tokens_Close: object_attr.tokenize() # move to shell pair find_shell = False while not find_shell: for shell_opens, shell_closes in Exp.Tokens_Shell_Pair.items( ): if object_attr.head in shell_opens: if w in shell_closes: find_shell = True break # opening not found if not find_shell: object_attr = object_attr.parent if object_attr is None: raise error.SyntaxError(w) object_attr.tokenize() # close shell object_attr.close(w) object_attr = object_attr.parent if object_attr is None: raise error.SyntaxError(w) # indices elif w in Exp.IDX: # move to indices shell '(' while object_attr.head not in Exp.RBO: # not other shells if object_attr.head in Exp.Tokens_Open: raise error.SyntaxError(w) object_attr.tokenize() object_attr = object_attr.parent if object_attr is None: raise error.SyntaxError(w) object_attr.tokenize() # no begin values if len(object_attr) == object_attr.breakpoint: object_attr = object_attr.insert_inner(w) last_object = TokenTree(object_attr, Exp.NUMBER) last_object += [False, Exp.BOOL] object_attr.append(last_object) continue # has start values if len(object_attr) == object_attr.breakpoint + 1: # has stop values last_object = object_attr[-1] if last_object.head == w: # not stop value defined if len(last_object) == 1: object_attr = object_attr[-1] last_object = TokenTree(object_attr, Exp.NUMBER) last_object += [False, Exp.BOOL] object_attr.append(last_object) continue if len(last_object) == 2: object_attr = last_object continue raise error.SyntaxError(w) # no stop values object_attr = object_attr.insert_upper(w) continue raise error.SyntaxError(w) # operators elif w in Exp.Tokens_Operator: # 'n'umber, 'v'ariable, 't'uple if w in Exp.ABSTRACT_TYPES: object_attr.append(w) continue object_attr.tokenize() # unary operators (-) if w in Exp.SUB: # = if len(object_attr) == 1: if object_attr.head in Exp.IS: object_attr.append(w) continue # if shell if len(object_attr) == 0: if object_attr.head in Exp.Tokens_Open: object_attr.append(w) continue # variable overlap if object_attr.head == Exp.VARIABLE and len(object_attr) == 1: new_object = object_attr[0] new_object.parent = object_attr.parent if new_object.parent is None: query = new_object object_attr = new_object # higher order if Exp.Tokens_Order[object_attr.head] < Exp.Tokens_Order[w]: object_attr = object_attr.insert_upper(w) continue # lower order # if in shell if object_attr.head in Exp.Tokens_Open: # put operators into shell object_attr = object_attr.insert_upper(w) continue last_object = object_attr.parent if last_object is None: query = object_attr = object_attr.insert_root(w) continue object_attr = last_object.insert_upper(w) if object_attr.parent is None: query = object_attr # not operators elif w[0] in Exp.Signs_DoubleSingle: raise error.SyntaxError(w) # append text elif object_attr.head == Exp.VARIABLE and len(object_attr) == 1: object_attr[0] += w # add content else: object_attr.append(w) prefixes.tokenize() object_attr.tokenize() # variable overlap if object_attr.head == Exp.VARIABLE and len(object_attr) == 1: last_object = object_attr.pop(0) object_attr += last_object object_attr.head = last_object.head # check size of operators prefixes.check_sizeof() query.check_sizeof() # check prefixes prefix_from_pair = True prefixes_new = TokenTree(None, Exp.SHELL_RR[0]) for token in prefixes: if token.head != Exp.VARIABLE: raise error.SyntaxError(token[0]) # has 'from' if token[0] in Exp.FROM: prefix_from_pair = False if len(prefixes_new) != 0: raise error.SyntaxError(token[0]) elif token[0] in Exp.Tokens_Prefix: prefix_from_pair = True if len(prefixes_new) != 0: if prefixes_new[-1][0] in Exp.Tokens_Prefix: raise error.SyntaxError(token[0]) if len(prefixes_new) > 3: raise error.SyntaxError(token[0]) prefixes_new.append(token) if not prefix_from_pair: raise error.SyntaxError(Exp.FROM[0]) prefixes = prefixes_new return prefixes, query