Rev 9357 | Rev 9377 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
9367 | Boppan | 1 | # Copyright Magomed Kostoev |
2 | # Published under MIT license |
||
3 | |||
4 | class Rule: |
||
5 | pass |
||
6 | |||
7 | def get_config(config_name): |
||
8 | if config_name == "KPACK_CMD": |
||
9 | # Just never pack the file for now |
||
10 | return "" |
||
11 | else: |
||
12 | print(f"Unknown config name: {config_name}") |
||
13 | exit(-1) |
||
14 | |||
15 | def skip_whitespaces(src, ptr): |
||
16 | while len(src) > ptr and src[ptr] == " ": |
||
17 | ptr += 1 |
||
18 | return ptr |
||
19 | |||
20 | # Returns True if @src has @string starting from @ptr index |
||
21 | def match_string(src, ptr, string): |
||
22 | if len(src) <= ptr + len(string): |
||
23 | return False |
||
24 | for i in range(len(string)): |
||
25 | if src[ptr + i] != string[i]: |
||
26 | return False |
||
27 | return True |
||
28 | |||
29 | def parse_tup_getconfig(src, ptr): |
||
30 | # Skip get straight to the argument |
||
31 | ptr += len("tup.getconfig(") |
||
32 | ptr = skip_whitespaces(src, ptr) |
||
33 | if src[ptr] != "\"": |
||
34 | print("Expected \"config name\" as tup.getconfig parameter") |
||
35 | exit() |
||
36 | (config_name, ptr) = parse_string(src, ptr) |
||
37 | ptr = skip_whitespaces(src, ptr) |
||
38 | # Skip closing parenthese of the tup.getconfig call |
||
39 | assert(src[ptr] == ")") |
||
40 | ptr += 1 |
||
41 | return (get_config(config_name), ptr) |
||
42 | |||
43 | def parse_string(src, ptr): |
||
44 | ptr += 1 |
||
45 | string = "" |
||
46 | while src[ptr] != "\"": |
||
47 | string += src[ptr] |
||
48 | ptr += 1 |
||
49 | # Skip the closing "\"" |
||
50 | ptr += 1 |
||
51 | ptr = skip_whitespaces(src, ptr) |
||
52 | # Check if we have concatination here |
||
53 | if match_string(src, ptr, ".."): |
||
54 | # Skip the ".." |
||
55 | ptr += 2 |
||
56 | # The expression parsing should result in a string |
||
57 | (string_to_add, ptr) = parse_expression(src, ptr) |
||
58 | # Concat our string to the resulting string |
||
59 | string += string_to_add |
||
60 | return (string, ptr) |
||
61 | |||
62 | def parse_expression(src, ptr): |
||
63 | ptr = skip_whitespaces(src, ptr) |
||
64 | result = "WAT?!" |
||
65 | if src[ptr] == "\"": |
||
66 | (result, ptr) = parse_string(src, ptr) |
||
67 | elif match_string(src, ptr, "tup.getconfig("): |
||
68 | (result, ptr) = parse_tup_getconfig(src, ptr) |
||
69 | else: |
||
70 | print(f"Can't handle anything starting with '{src[ptr]}'") |
||
71 | exit(-1) |
||
72 | ptr = skip_whitespaces(src, ptr) |
||
73 | return (result, ptr) |
||
74 | |||
75 | def expect_comma(src, ptr): |
||
76 | comma_skept = False |
||
77 | ptr = skip_whitespaces(src, ptr) |
||
78 | if src[ptr] == ",": |
||
79 | ptr += 1 |
||
80 | return (True, ptr) |
||
81 | else: |
||
82 | return (False, ptr) |
||
83 | |||
84 | def parse_arguments(src, ptr): |
||
85 | result = [] |
||
86 | # Parse first argument |
||
87 | (argument, ptr) = parse_expression(src, ptr) |
||
88 | result.append(argument) |
||
89 | (comma_encoutered, ptr) = expect_comma(src, ptr) |
||
90 | # Parse the second argument if it's there |
||
91 | if comma_encoutered: |
||
92 | (argument, ptr) = parse_expression(src, ptr) |
||
93 | result.append(argument) |
||
94 | (comma_encoutered, ptr) = expect_comma(src, ptr) |
||
95 | # Parse third argument if it's there |
||
96 | if comma_encoutered: |
||
97 | (argument, ptr) = parse_expression(src, ptr) |
||
98 | result.append(argument) |
||
99 | return result |
||
100 | |||
101 | def parse_rule(src, ptr): |
||
102 | # Get straight to the first argument |
||
103 | ptr += len("tup.rule(") |
||
104 | # Parse the arguments |
||
105 | args = parse_arguments(src, ptr) |
||
106 | # Build the rule object |
||
107 | result = Rule() |
||
108 | if len(args) == 3: |
||
109 | result.input = args[0] |
||
110 | result.command = args[1] |
||
111 | result.output = args[2] |
||
112 | # Replace %f with input file in rule's command |
||
113 | if type(result.input == str): |
||
114 | result.command = result.command.replace("%f", result.input) |
||
115 | else: |
||
116 | print("Command building with non-string tup.rule's first argument" |
||
117 | + " isn't implemented") |
||
118 | exit() |
||
119 | # Replace %o with output file in rule's command |
||
120 | if type(result.output == str): |
||
121 | result.command = result.command.replace("%o", result.output) |
||
122 | else: |
||
123 | print("Command building with non-string tup.rule's first argument" |
||
124 | + " isn't implemented") |
||
125 | exit() |
||
126 | elif len(args) == 2: |
||
127 | result.input = [] |
||
128 | result.command = args[0] |
||
129 | result.output = args[1] |
||
130 | else: |
||
131 | print(f"tup.rule can only take 2 or 3 arguments, not {len(args)}") |
||
132 | exit(-1) |
||
133 | # Unify the API - return arrays as input and output |
||
134 | if type(result.input) == str: |
||
135 | result.input = [ result.input ] |
||
136 | else: |
||
137 | assert(type(result.input) == list) |
||
138 | if type(result.output) == str: |
||
139 | result.output = [ result.output ] |
||
140 | else: |
||
141 | assert(type(result.output) == list) |
||
142 | return result |
||
143 | |||
144 | def parse(file_name): |
||
145 | rules = [] |
||
146 | with open(file_name) as f: |
||
147 | tupfile = f.read() |
||
148 | rule_begin_index = tupfile.find("tup.rule(") |
||
149 | while (rule_begin_index != -1): |
||
150 | rules.append(parse_rule(tupfile, rule_begin_index)) |
||
151 | # Find the next tup.rule call |
||
152 | rule_begin_index = tupfile.find("tup.rule(", rule_begin_index + len("tup.rule(")) |
||
153 | return rules=> |