from .sly import Lexer, Parser import logging logger = logging.getLogger(__name__) class TimedWordLexer(Lexer): tokens = {LPAREN, RPAREN, IDENTIFIER, NUMBER, ARGSEP, FUNCTIONSEP} ignore = " \t" LPAREN = r"\(" RPAREN = r"\)" IDENTIFIER = r"[a-zA-Z_][a-zA-Z0-9_]*" NUMBER = r"[0-9e.]+" ARGSEP = r"," FUNCTIONSEP = r";" class TimedSequenceLexer(Lexer): tokens = { LPAREN, RPAREN, LBRACE, RBRACE, CYCLE, IDENTIFIER, NUMBER, ARGSEP, FUNCTIONSEP, } ignore = " \t" LPAREN = r"\(" RPAREN = r"\)" LBRACE = r"\{" RBRACE = r"\}" CYCLE = r"cycle" IDENTIFIER = r"[a-zA-Z_][a-zA-Z0-9_]*" NUMBER = r"[0-9e.]+" ARGSEP = r"," FUNCTIONSEP = r";" def error(self, t): logger.error("Illegal character '%s'" % t.value[0]) if t.value[0] == "{" and t.value.find("}"): self.index += 1 + t.value.find("}") else: self.index += 1 class TimedWordParser(Parser): tokens = TimedWordLexer.tokens @_("timedSymbol FUNCTIONSEP timedWord") def timedWord(self, p): ret = [p.timedSymbol] ret.extend(p.timedWord) return ret @_("timedSymbol FUNCTIONSEP", "timedSymbol") def timedWord(self, p): return [p.timedSymbol] @_("IDENTIFIER", "IDENTIFIER LPAREN RPAREN") def timedSymbol(self, p): return (p.IDENTIFIER,) @_("IDENTIFIER LPAREN args RPAREN") def timedSymbol(self, p): return (p.IDENTIFIER, *p.args) @_("arg ARGSEP args") def args(self, p): ret = [p.arg] ret.extend(p.args) return ret @_("arg") def args(self, p): return [p.arg] @_("NUMBER") def arg(self, p): return float(p.NUMBER) @_("IDENTIFIER") def arg(self, p): return p.IDENTIFIER class TimedSequenceParser(Parser): tokens = TimedSequenceLexer.tokens @_("timedSequenceL", "timedSequenceW") def timedSequence(self, p): return p[0] @_("loop") def timedSequenceL(self, p): return [p.loop] @_("loop timedSequenceW") def timedSequenceL(self, p): ret = [p.loop] ret.extend(p.timedSequenceW) return ret @_("timedWord") def timedSequenceW(self, p): return [p.timedWord] @_("timedWord timedSequenceL") def timedSequenceW(self, p): ret = [p.timedWord] ret.extend(p.timedSequenceL) return ret @_("timedSymbol FUNCTIONSEP timedWord") def timedWord(self, p): p.timedWord.word.insert(0, p.timedSymbol) return p.timedWord @_("timedSymbol FUNCTIONSEP") def timedWord(self, p): return TimedWord(word=[p.timedSymbol]) @_("CYCLE LPAREN IDENTIFIER RPAREN LBRACE timedWord RBRACE") def loop(self, p): return Workload(p.IDENTIFIER, p.timedWord) @_("IDENTIFIER", "IDENTIFIER LPAREN RPAREN") def timedSymbol(self, p): return (p.IDENTIFIER,) @_("IDENTIFIER LPAREN args RPAREN") def timedSymbol(self, p): return (p.IDENTIFIER, *p.args) @_("arg ARGSEP args") def args(self, p): ret = [p.arg] ret.extend(p.args) return ret @_("arg") def args(self, p): return [p.arg] @_("NUMBER") def arg(self, p): return float(p.NUMBER) @_("IDENTIFIER") def arg(self, p): return p.IDENTIFIER def error(self, p): if p: logger.error("Syntax error at token", p.type) # Just discard the token and tell the parser it's okay. self.errok() else: logger.error("Syntax error at EOF") class TimedWord: def __init__(self, word_string=None, word=list()): if word_string is not None: lexer = TimedWordLexer() parser = TimedWordParser() self.word = parser.parse(lexer.tokenize(word_string)) else: self.word = word def __getitem__(self, item): return self.word[item] def __repr__(self): ret = list() for symbol in self.word: ret.append("{}({})".format(symbol[0], ", ".join(map(str, symbol[1:])))) return 'TimedWord<"{}">'.format("; ".join(ret)) class Workload: def __init__(self, name, word): self.name = name self.word = word def __getitem__(self, item): return self.word[item] def __repr__(self): return 'Workload("{}", {})'.format(self.name, self.word) class TimedSequence: def __init__(self, seq_string=None, seq=list()): if seq_string is not None: lexer = TimedSequenceLexer() parser = TimedSequenceParser() self.seq = parser.parse(lexer.tokenize(seq_string)) else: self.seq = seq def __getitem__(self, item): return self.seq[item] def __repr__(self): ret = list() for symbol in self.seq: ret.append("{}".format(symbol)) return "TimedSequence(seq=[{}])".format(", ".join(ret))