parse.py 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. """
  2. The module for parsing the basics of an orx file.
  3. This just lifts the information from the syntax - this module is not responsible
  4. for processing the actual data (that's where manifest comes in).
  5. """
  6. def parse_expr(expr):
  7. """
  8. Parse Expression.
  9. Parses a single expression.
  10. """
  11. t1 = expr.split('=')
  12. t2 = list(map(lambda t: t.strip().rsplit(maxsplit=1), t1[:-1]))
  13. lex = (t2[0][0] if t2 else expr).split()
  14. head, args = (lex[0], lex[1:]) if lex else (None, [])
  15. keys = map(lambda t: t[1].strip(), t2)
  16. vals = list(map((lambda t: t[0].strip()), t2[1:])) + [t1[-1].strip()]
  17. for idx, val in enumerate(vals):
  18. if val == '!':
  19. vals[idx] = ''
  20. kwargs = dict(zip(keys, vals))
  21. return head, args, kwargs
  22. def subst_consts(expr, consts):
  23. """
  24. Substitute Constants.
  25. Finds all of the constants from `define` expressions and fills
  26. in their actual value.
  27. parse_expr() takes the result of this function.
  28. """
  29. res = expr
  30. idx = 0
  31. while idx < len(res):
  32. idx = res.find('$', idx)
  33. if idx == -1:
  34. break
  35. if len(res) == idx + 1:
  36. raise ValueError('Missing constant name')
  37. if res[idx + 1] == '(':
  38. const_name_start = idx + 2
  39. const_name_end = res.find(')', idx + 2)
  40. const_token_end = const_name_end + 1
  41. else:
  42. const_name_start = idx + 1
  43. for const_name_end in range(idx + 1, len(res)):
  44. if res[const_name_end].isspace():
  45. break
  46. else:
  47. const_name_end = len(res)
  48. const_token_end = const_name_end
  49. if const_name_end == -1:
  50. raise ValueError('Unterminated constant name')
  51. if const_name_start == const_name_end:
  52. raise ValueError('Missing constant name')
  53. const_name = res[const_name_start:const_name_end]
  54. if const_name not in consts:
  55. raise ValueError('Undefined constant: ' + const_name)
  56. res = res[:idx] + consts[const_name] + res[const_token_end:]
  57. idx += 1
  58. return res
  59. def get_exprs(stream):
  60. """
  61. Get Expressions.
  62. An iterator that detects and retrieves single expressions.
  63. (whether they are single-line or multi-line expressions)
  64. """
  65. expr = ''
  66. expr_line_num = 1
  67. for line_num, line in enumerate(stream, 1):
  68. if not line:
  69. continue
  70. if line.lstrip().startswith('#'):
  71. continue
  72. if expr and not line[0].isspace():
  73. yield expr, expr_line_num
  74. expr = ''
  75. if not expr:
  76. expr_line_num = line_num
  77. expr += line
  78. if expr:
  79. yield expr, expr_line_num
  80. # expr: the expression itself.
  81. # expr_line_num: the line number where that expression is
  82. # (for error messaging)