def parse_from_lexer(lexer, symbol_table, engine, passed_token): rotated = False while True: if passed_token is None or rotated: token = utils.get_token_skipping_whitespace(lexer) else: token = passed_token rotated = True if token.token_type == TokenType.eof: return if token.token_type != TokenType.keyword or token.token_value != 'rule': raise ValueError("This error should not have occurred. rule keyword is expected, Sir") token = utils.get_token_skipping_whitespace(lexer) if token.token_type == TokenType.given_name: parsed_file = open(token.token_value) new_lexer = Lexer(parsed_file) parse_from_lexer(new_lexer, symbol_table, engine, None) elif token.token_type == TokenType.structure_operator_start: rid = get_id(lexer, symbol_table) prio = get_priority(lexer) condition = condParser.get_condition(lexer, symbol_table, engine) actions = get_actions(lexer, symbol_table, engine) utils.expect_otherchar(lexer, TokenType.structure_operator_end, '}') rule = Rule(rid, prio, condition, actions) symbol_table.add_rule_id(rid) engine.rules[rid] = rule else: raise ValueError("Either a given_name of a file containing a rule or { are expected, Sir") rotated = True
def get_condition(lexer, symbol_table, engine): token = utils.get_token_skipping_whitespace(lexer) if token.token_type != TokenType.keyword or token.token_value != 'condition': raise ValueError("Keyword condition expected Sir. Found: " + str(token.token_value)) token = utils.get_token_skipping_whitespace(lexer) if token.token_type != TokenType.definition_operator: raise ValueError('Expected : ,found ' + str(token.token_value), " Sir.") token = utils.get_token_skipping_whitespace(lexer) if token.token_type == TokenType.instr_end: return TrueCondition() elif token.token_type == TokenType.keyword or token.token_type == TokenType.list_start: return _build_conditions(token, lexer, symbol_table, engine, 0) else: raise ValueError("Inappropriate token found " + str(token.token_value))
def get_priority(lexer): token = utils.get_token_skipping_whitespace(lexer) if token.token_type != TokenType.keyword or token.token_value != 'priority': raise ValueError('Expected priority keyword, Sir. Found ' + str(token.token_value)) token = utils.get_token_skipping_whitespace(lexer) if token.token_type != TokenType.definition_operator: raise ValueError('Expected : ,found ' + str(token.token_value), " Sir.") token = utils.get_token_skipping_whitespace(lexer) if token.token_type != TokenType.number: raise ValueError('Rule id must be a number, found ' + str(token.token_value)) rule_id = token.token_value token = utils.get_token_skipping_whitespace(lexer) if token.token_type != TokenType.instr_end: raise ValueError('Expected ; found ' + str(token.token_value) + " ,Sir.") return rule_id
def _parse_comparison_cond(token, lexer, symbol_table, engine, is_negated): access_method1, symbol_id1, date_str1, num1 = _get_numeric_comparison_argument(token, lexer, symbol_table, engine) operator = _get_comparison_operator(lexer) token = utils.get_token_skipping_whitespace(lexer) access_method2, symbol_id2, date_str2, num2 = _get_numeric_comparison_argument(token, lexer, symbol_table, engine) return _build_comparison_condition(access_method1, symbol_id1, date_str1, num1, operator, access_method2, symbol_id2, date_str2, num2, is_negated)
def get_actions(lexer, symbol_table, engine): last_was_action = False actions = [] utils.expect_keyword(lexer, 'actions') utils.expect_otherchar(lexer, TokenType.definition_operator, ':') while True: if last_was_action: token = utils.get_token_skipping_whitespace(lexer) if token.token_type == TokenType.list_separator: last_was_action = False continue if token.token_type == TokenType.instr_end: break else: actions.append(parse_action(lexer, symbol_table, engine)) last_was_action = True return actions
def get_id(lexer, symbol_table): token = utils.get_token_skipping_whitespace(lexer) if token.token_type != TokenType.keyword or token.token_value != 'id': raise ValueError('Expected id keyword, Sir. Found ' + str(token.token_value)) token = utils.get_token_skipping_whitespace(lexer) if token.token_type != TokenType.definition_operator: raise ValueError('Expected : ,found ' + str(token.token_value), " Sir.") token = utils.get_token_skipping_whitespace(lexer) if token.token_type != TokenType.number: raise ValueError('Rule id must be a number, found ' + str(token.token_value)) rule_id = token.token_value if symbol_table.is_rule_id_busy(rule_id): raise ValueError('Id' + str(rule_id) + 'for rule is already taken, Sir') token = utils.get_token_skipping_whitespace(lexer) if token.token_type != TokenType.instr_end: raise ValueError('Expected ; found ' + str(token.token_value) + " ,Sir.") return rule_id
def parse(self): state = 0 # 0 - config, 1 - events, 2 - start, 3 - rules, 4 - done while True: token = ut.get_token_skipping_whitespace(self.lexer) state = self.change_state_on_token(token, state) if state == 0: file_name = ut.expect_given_name(self.lexer) parse_results = config_parser.parse_file( file_name, self.symbol_table) currencies = parse_results['currencies'] stocks = parse_results['stocks'] for curr in currencies: self.engine.add_currency(curr) for st in stocks: self.engine.add_stock(st) elif state == 1: file_name = ut.expect_given_name(self.lexer) parse_results = events_parser.parse_file( file_name, self.symbol_table) for event in parse_results: self.engine.add_event(event) elif state == 2: file_name = ut.expect_given_name(self.lexer) parse_results = start_parser.parse_file( file_name, self.symbol_table) currencies = parse_results['currencies'] stocks = parse_results['stocks'] for curr in currencies: self.engine.add_start_cond(curr) for st in stocks: self.engine.add_start_cond(st) elif state == 3: rule_parser.parse_from_lexer(self.lexer, self.symbol_table, self.engine, token) elif state == 4: return else: raise ValueError("Something went blood wrong, Sir")
def _get_date_arg(lexer, engine): token = lexer.get_token() if token.token_type != TokenType.list_start: if token.token_type == TokenType.whitespace: return dateConv.to_str(engine.world.current_day) else: raise ValueError( "Forbidden token found, expected whitespace or ( amount" + str(token.token_value) + " ,Sir.") else: token = utils.get_token_skipping_whitespace(lexer) if token.token_type == TokenType.number: result = dateConv.get_date_back_x(dateConv.to_str(engine.world.current_day), math.fabs(token.token_value)) token = utils.get_token_skipping_whitespace(lexer) if token.token_type != TokenType.list_end: raise ValueError("Expected ) , found: " + str(token.token_value) + " ,Sir.") return dateConv.to_str(result) if token.token_type == TokenType.date: result = token.token_value token = utils.get_token_skipping_whitespace(lexer) if token.token_type != TokenType.list_end: raise ValueError("Expected ) , found: " + str(token.token_value) + " ,Sir.") return dateConv.to_str(result) raise ValueError(" Expected Number or @date@, found neither, Sir")
def _build_conditions(token, lexer, symbol_table, engine, depth): master = MasterCondition() last_was_condition = False while True: is_negated = False if token.token_type == TokenType.logical_operator and token.token_value != '!': if last_was_condition: master.operators.append(token.token_value) last_was_condition = False token = utils.get_token_skipping_whitespace(lexer) continue else: raise ValueError("Logical operator was found not following a logical condition, Sir") if token.token_type == TokenType.keyword or token.token_type == TokenType.number or ( token.token_type == TokenType.logical_operator and token.token_value == '!') \ and not last_was_condition: if token.token_type == TokenType.logical_operator and token.token_value == '!': is_negated = True if token.token_value == 'currency' or token.token_value == 'stock' or token.token_type == TokenType.number: cond = _parse_comparison_cond(token, lexer, symbol_table, engine, is_negated) master.conditions.append(cond) last_was_condition = True token = utils.get_token_skipping_whitespace(lexer) continue if token.token_value == 'rule': cond = _parse_rule_cond(token, lexer, symbol_table, engine, is_negated) master.conditions.append(cond) last_was_condition = True token = utils.get_token_skipping_whitespace(lexer) continue if token.token_value == 'inc' or token.token_value == 'dec': cond = _parse_trend_cond(token, lexer, symbol_table, engine, is_negated) master.conditions.append(cond) last_was_condition = True token = utils.get_token_skipping_whitespace(lexer) continue if token.token_type == TokenType.list_end and last_was_condition: return master if token.token_type == TokenType.list_start and not last_was_condition: cond = _build_conditions(utils.get_token_skipping_whitespace(lexer), lexer, symbol_table, engine, depth + 1) last_was_condition = True master.conditions.append(cond) token = utils.get_token_skipping_whitespace(lexer) continue if token.token_type == TokenType.instr_end and last_was_condition: if depth == 0: break else: raise ValueError("Unclosed group is present, Sir") raise ValueError( "Condition should be build by alternating between condition " + "or condition groups and || or && symbols, please adhere, Sir. It must also end in a condition." " Please check for ; also") return master
def _parse_rule_cond(token, lexer, symbol_table, engine, is_negated): if token.token_type != TokenType.keyword and token.token_value != 'rule': raise ValueError('Rule keyword expected, found: ' + str(token.token_value) + " ,Sir.") utils.expect_access_operator(lexer) rule_id = int(utils.expect_given_name(lexer)) if not symbol_table.is_rule_id_busy(rule_id): raise ValueError("Trying to check execution or non existant rule: " + str(rule_id) + " ,Sir.") rule = engine.rules.get(rule_id) utils.expect_access_operator(lexer) token = utils.get_token_skipping_whitespace(lexer) if token.token_type != TokenType.keyword or token.token_value != 'executed': raise ValueError('Expected executed keyword, found: ' + str(token.token_value) + " ,Sir.") return RuleExecCondition(rule, is_negated)
def _get_numeric_comparison_argument(token, lexer, symbol_table, engine): if token.token_type == TokenType.number: return None, None, None, token.token_value if token.token_value == 'currency': utils.expect_access_operator(lexer) symbol_id = symbol_table.get_currency(utils.expect_given_name(lexer)) utils.expect_access_operator(lexer) token = lexer.get_token() if token.token_type == TokenType.keyword and token.token_value == 'rate': access_method = engine.world.get_currency_rate date_str = _get_date_arg(lexer, engine) return access_method, symbol_id, date_str, None elif token.token_type == TokenType.keyword and token.token_value == 'have': utils.expect_access_operator(lexer) token = lexer.get_token() if token.token_type == TokenType.keyword and token.token_value == 'amount': access_method = engine.investor.has_currency return access_method, symbol_id, None, None else: raise ValueError("Forbidden token found, expected keyword amount " + str(token.token_value) + " ,Sir.") else: raise ValueError( "Forbidden token found, expected keywords rate or have found: " + str(token.token_value) + " ,Sir.") else: utils.expect_access_operator(lexer) symbol_id = symbol_table.get_stock(utils.expect_given_name(lexer)) utils.expect_access_operator(lexer) token = lexer.get_token() if token.token_type == TokenType.keyword and token.token_value == 'value': access_method = engine.world.get_stock_price date_str = _get_date_arg(lexer, engine) return access_method, symbol_id, date_str, None elif token.token_type == TokenType.keyword and token.token_value == 'have': utils.expect_access_operator(lexer) token = lexer.get_token() if token.token_type == TokenType.keyword and token.token_value == 'amount': access_method = engine.investor.has_stock return access_method, symbol_id, None, None else: raise ValueError( "Forbidden token found, expected keyword amount not " + str(token.token_value) + " ,Sir.") else: raise ValueError("Forbidden token found, expected keyword value or have keywords not " + str( token.token_value) + " ,Sir.")
def _parse_trend_cond(token, lexer, symbol_table, engine, is_negated): is_inc = False symbol_id = None access_method = None if token.token_value != 'inc' and token.token_value != 'desc': raise ValueError('Either of [inc, desc] expected, none found, Sir') if token.token_value == 'inc': is_inc = True token = utils.get_token_skipping_whitespace(lexer) if token.token_type == TokenType.keyword and token.token_value == 'currency': utils.expect_access_operator(lexer) symbol_id = symbol_table.get_currency(utils.expect_given_name(lexer)) utils.expect_access_operator(lexer) utils.expect_keyword(lexer, 'rate') access_method = engine.world.get_currency_rate elif token.token_type == TokenType.keyword and token.token_value == 'stock': utils.expect_access_operator(lexer) symbol_id = symbol_table.get_stock(utils.expect_given_name(lexer)) utils.expect_access_operator(lexer) utils.expect_keyword(lexer, 'value') access_method = engine.world.get_stock_price else: raise ValueError('Either stock or currency keywords expected, found: ' + str(token.token_value) + " ,Sir.") utils.expect_keyword(lexer, 'by') percent_growth = utils.expect_number(lexer) utils.expect_keyword(lexer, 'in') days_num = utils.expect_number(lexer) trendCond = TrendCondition(engine.world) trendCond.accessor_method = access_method trendCond.growth_percent = percent_growth trendCond.number_of_days = days_num trendCond.is_inc = is_inc trendCond.is_negated = is_negated return trendCond
def _get_comparison_operator(lexer): token = utils.get_token_skipping_whitespace(lexer) if token.token_type != TokenType.relations_operator: raise ValueError("Relations operator expected, found: " + str(token.token_value) + " ,Sir.") return token.token_value
def parse_action(lexer, symbol_table, engine): is_buy = False is_stock = False token = utils.get_token_skipping_whitespace(lexer) if token.token_type != TokenType.keyword and token.token_value not in ['buy', 'sell']: raise ValueError('Buy or sell expected to start action, found something else, Sir') if token.token_value == 'buy': is_buy = True token = utils.get_token_skipping_whitespace(lexer) if token.token_type != TokenType.keyword and token.token_value not in ['stock', 'currency']: raise ValueError('An action requires you to choose either stock or currency, nothing else, Sir') if token.token_value == 'stock': is_stock = True utils.expect_access_operator(lexer) symbol_name = utils.expect_given_name(lexer) symbol_id = -1 if is_stock: symbol_id = symbol_table.get_stock(symbol_name) else: symbol_id = symbol_table.get_currency(symbol_name) if not is_buy: token = utils.get_token_skipping_whitespace(lexer) if token.token_type == TokenType.keyword and token.token_value == 'amount': token = utils.get_token_skipping_whitespace(lexer) if token.token_type == TokenType.number: if token.token_value < 0: raise ValueError("You can only sell a positive amount, Sir") return build_action(engine, is_buy, is_stock, symbol_id, amount=token.token_value) elif token.token_type == TokenType.keyword and token.token_value == 'ALL': return build_action(engine, is_buy, is_stock, symbol_id, amount='ALL') else: raise ValueError("Expecting a number or ALL keyword, found neither of them, Sir") elif token.token_type == TokenType.keyword and token.token_value == 'part': amount = utils.expect_number(lexer) if not 1 <= amount <= 100: raise ValueError("Part must be 1 to 100 no more no less, Sir") return build_action(engine, is_buy, is_stock, symbol_id, part=amount) elif token.token_type == TokenType.keyword and token.token_value == 'for': curr_amount = utils.expect_number(lexer) if curr_amount < 0: raise ValueError("You can only sell for a positive price, Sir") return build_action(engine, is_buy, is_stock, symbol_id, curr_amount=curr_amount) else: raise ValueError("Expecting either amount, part, for, none of those were found, Sir") else: token = utils.get_token_skipping_whitespace(lexer) if token.token_type != TokenType.keyword or token.token_value != 'amount': raise ValueError("Expecting keyword amount, Sir") token = utils.get_token_skipping_whitespace(lexer) buy_amount = 0 if token.token_type == TokenType.keyword or token.token_value == 'MAX': buy_amount = 'MAX' elif token.token_type == TokenType.number: buy_amount = token.token_value if buy_amount < 0: raise ValueError("You can only buy a positive amount, Sir") else: raise ValueError("Unexpected Token, Sir") utils.expect_keyword(lexer, 'for') currency_used_id = None token = utils.get_token_skipping_whitespace(lexer) if token.token_type == TokenType.keyword and token.token_value == 'OWN': currency_used_id = 'OWN' elif token.token_type == TokenType.keyword and token.token_value == 'ANY': currency_used_id = 'ANY' elif token.token_type == TokenType.keyword and token.token_value == 'currency': utils.expect_access_operator(lexer) currency_name = utils.expect_given_name(lexer) currency_used_id = symbol_table.get_currency(currency_name) else: raise ValueError("Unexpected token, Sir") return build_action(engine, is_buy, is_stock, symbol_id, buy_amount=buy_amount, curr_used=currency_used_id)