Exemple #1
0
    def parse_project_attr(self):
        l = self.lex.next()
        name = l.data
        attr_loc = l.loc

        self.lex.expect('=')

        rhs = []
        while True:
            l = self.lex.expect('LIST_ELT')
            rhs.append(l.data)
            if not self.lex.next_if(','):
                break

        def expect_one_value(loc, name, vals):
            error_if(
                len(vals) != 1, loc,
                f"too many values for attribute '{name}': " + ', '.join(vals))

        if name in {'name', 'tracker_link', 'pr_link'}:
            expect_one_value(l.loc, name, rhs)
            val = rhs[0]
        elif name in {'start', 'finish'}:
            expect_one_value(l.loc, name, rhs)
            val, _ = PA.read_date(rhs[0], attr_loc)
        elif name == 'members':
            val = []
            for rc_info in rhs:
                if not M.match(r'([A-Za-z][A-Za-z0-9_]*)\s*(?:\(([^\)]*)\))?',
                               rc_info):
                    error(attr_loc,
                          f"failed to parse resource declaration: {rc_info}")
                rc_name, attrs = M.groups()
                rc = project.Resource(rc_name, attr_loc)
                if attrs:
                    rc.add_attrs(re.split(r'\s*,\s*', attrs), attr_loc)
                val.append(rc)
        elif name == 'teams':
            val = []
            for team_info in rhs:
                if not M.match(r'\s*([A-Za-z][A-Za-z0-9_]*)\s*\(([^)]*)\)$',
                               team_info):
                    error(attr_loc, f"invalid team declaration: {team_info}")
                team_name = M.group(1)
                rc_names = re.split(r'\s*,\s*', M.group(2).strip())
                val.append(project.Team(team_name, rc_names, attr_loc))
        elif name == 'holidays':
            val = []
            for s in rhs:
                iv = PA.read_date2(s, attr_loc)
                val.append(iv)
        else:
            error(attr_loc, f"unknown project attribute: {name}")

        self.project_attrs[name] = val
Exemple #2
0
def read_alloc(a, loc):
    """Parse allocation directive e.g. "@dev1/dev2 (dev3)"."""
    aa = a.split('(')
    if len(aa) > 2 or not M.search(r'^@\s*(.*)', aa[0]):
        error(loc, f"unexpected allocation syntax: {a}")
    alloc = M.group(1).strip().split('/')
    if len(aa) <= 1:
        real_alloc = []
    else:
        if not M.search(r'^([^)]*)\)', a):
            error(loc, f"unexpected allocation syntax: {a}")
        real_alloc = M.group(1).strip().split('/')
    return alloc, real_alloc
Exemple #3
0
def read_fraction(s, loc):
    if M.search(r'^[0-9.]+$', s):
        return float(s)
    if M.search(r'^([0-9]+)%$', s):
        return int(M.group(1)) / 100
    error(loc, f"unexpected fraction syntax: {s}")
    raise ValueError("silly Pylint fails to understand NoReturn")
Exemple #4
0
def add_common_attrs(loc, obj, attrs):
  """Adds attributes that are common for goals, checks and activities."""

  other_attrs = []
  for a in attrs:
    if M.search(r'^([A-Za-z][A-Za-z0-9_]*)\s*(.*)', a):
      k = M.group(1).strip()
      #v = M.group(2).strip()
      if k == 'task':
        obj.tracker.tasks = set(M.group(1).split('/'))
        continue
      if k == 'PR':
        obj.tracker.prs = set(M.group(1).split('/'))
        continue

    other_attrs.append(a)

  return other_attrs
Exemple #5
0
 def add_attrs(self, attrs, loc):
   for a in attrs:
     if a[0].isdigit():
       self.efficiency = P.read_fraction(a, loc)
     elif M.search(r'vacations?\s+(.*)', a):
       duration = P.read_date2(M.group(1), loc)
       self.vacations.append(duration)
     else:
       error(loc, f"unexpected resource attribute: {a}")
Exemple #6
0
  def add_attrs(self, attrs, loc):
    attrs = add_common_attrs(loc, self, attrs)

    for a in attrs:
      if re.search(r'^[0-9.]+[hdwmy]', a):
        # Parse estimate
        self.effort = PA.read_eta(a, loc)
        continue

      if a.startswith('@'):
        self.alloc, self.real_alloc = PA.read_alloc(a, loc)
        continue

      # TODO: specify in effort attribute?
      if M.search(r'^[0-9]{4}-', a):
        self.duration = PA.read_date2(a, loc)
        continue

      if M.match(r'^id\s+(.*)', a):
        self.id = M.group(1)

      if M.match(r'over\s+(\S+)\s+(.*)', a):
        other_id = M.group(1)
        overlap, a = PA.read_float(M.group(2), loc)
        if a == '%':
          overlap /= 100
        self.overlaps[other_id] = overlap

      if a.startswith('||'):
        self.parallel = PA.read_par(a)
        continue

      if not M.search(r'^([a-z_0-9]+)\s*(.*)', a):
        error(loc, f"failed to parse attribute: {a}")
      k = M.group(1).strip()
      #v = M.group(2).strip()

      if k == 'global':
        self.globl = True
        continue

      error(loc, f"unknown activity attribute: '{k}'")
Exemple #7
0
def read_eta(s, loc):
    """Parse effort estimate e.g. "1h", "1h-3d" or "1h-3d (1d)"."""

    min, rest = read_effort(s, loc)

    max = min
    if rest and rest[0] == '-':
        max, rest = read_effort(rest[1:], loc)

    real = None
    completion = 0
    if M.search(r'^\s*\((.*)\)\s*$', rest):
        for a in re.split(r'\s*,\s*', M.group(1)):
            if re.search(r'^[0-9.]+[hdwmy]', a):
                real, _ = read_effort(a, loc)
            elif M.search(r'^([0-9]+)%', a):
                completion = float(M.group(1)) / 100
            else:
                error(loc, f"unknown ETA attribute: {a}")

    return ETA(min, max, real, completion)
Exemple #8
0
  def add_attrs(self, attrs, loc):
    attrs = add_common_attrs(loc, self, attrs)

    for a in attrs:
      if a.find('!') == 0:
        try:
          self.prio = Priority(int(a[1:]))
        except ValueError:
          error(loc, f"invalid priority value: {a}")
        continue

      if a.find('?') == 0:
        try:
          self.risk = Risk(int(a[1:]))
        except ValueError:
          error(loc, f"invalid risk value: {a}")
        continue

      if M.search(r'^I[0-9]+$', a):
        self.iter = int(a[1:])
        continue

      if M.search(r'^[0-9]{4}-', a):
        self.completion_date, _ = PA.read_date(a, loc)
        continue

      if not M.search(r'^([a-z_0-9]+)\s*(.*)', a):
        error(loc, f"failed to parse goal attribute: {a}")
      k = M.group(1).strip()
      v = M.group(2).strip()

      if k == 'deadline':
        self.deadline, _ = PA.read_date(v, loc)
        continue

      if k == 'id':
        self.id = v
        continue

      error(loc, f"unknown goal attribute '{k}'")
Exemple #9
0
    def add_attrs(self, attrs, loc):
        for a in attrs:
            if a.startswith('@'):
                self.alloc, _ = PA.read_alloc(a, loc)
                continue

            if M.search(r'^[0-9]{4}-', a):
                self.duration = PA.read_date2(a, loc)
                continue

            if a.startswith('||'):
                self.parallel = PA.read_par(a)
                continue

            if not M.search(r'^([a-z_0-9]+)\s*(.*)', a):
                error(loc, f"failed to parse block attribute: {a}")
            k = M.group(1).strip()
            v = M.group(2).strip()

            if k == 'deadline':
                self.deadline, _ = PA.read_date(v, loc)
                continue

            error(loc, f"unknown block attribute '{k}'")
Exemple #10
0
 def next_internal(self):
     if self.line == '':
         # File exhausted
         type = LexemeType.EOF
         data = text = ''
     elif self.mode == LexerMode.ATTR:
         nest = 0
         self.line = self.line.lstrip()
         if self.line[0] == ',':
             type = ','
             i = 1
         else:
             type = LexemeType.LIST_ELT
             for i, c in enumerate(self.line):
                 if c == ',' and not nest:
                     break
                 if c == '(':
                     nest += 1
                 elif c == ')':
                     nest -= 1
             else:
                 i += 1
                 self.mode = LexerMode.NORMAL
         text = self.line[:i]
         data = text.rstrip()
         self.line = self.line[i:]
     else:
         data = None
         if M.match(r'( *)\|([<>])-', self.line):
             type = LexemeType.LARROW if M.group(
                 2) == '<' else LexemeType.RARROW
             data = len(M.group(1))
         elif M.match(r'( *)\|\[([^\]]*)\]\s*(.*?)(?=(//|$))', self.line):
             type = LexemeType.CHECK
             data = len(M.group(1)), M.group(2), M.group(3).strip()
         elif M.match(r'^(\s*)(--|\|\|)\s*', self.line):
             type = LexemeType.SCHED
             data = len(M.group(1)), M.group(2)
         elif M.match(r'( *)\|(.*?)(?=//|$)', self.line):
             type = LexemeType.GOAL
             data = len(M.group(1)), M.group(2).strip()
         elif M.match(r'\s*//', self.line):
             type = LexemeType.ATTR_START
             self.mode = LexerMode.ATTR
         elif M.match(r'([A-Za-z][A-Za-z0-9_]*)(?=\s*=)', self.line):
             type = LexemeType.PRJ_ATTR
             data = M.group(1)
         elif M.match(r'\s*=\s*', self.line):
             type = LexemeType.ASSIGN
             self.mode = LexerMode.ATTR
         else:
             error(self._loc(), f"unexpected syntax: {self.line}")
         self.line = self.line[len(M.group(0)):]
         text = M.group(0)
     self.lexemes.append(PA.Lexeme(type, data, text, self._loc()))