Rev 9367 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 9367 | Rev 9377 | ||
---|---|---|---|
Line 1... | Line 1... | ||
1 | # Copyright Magomed Kostoev |
1 | # Copyright Magomed Kostoev |
2 | # Published under MIT license |
2 | # Published under MIT license |
Line -... | Line 3... | ||
- | 3 | ||
3 | 4 | block_beginner2finisher = { |
|
4 | class Rule: |
5 | "(": ")", |
- | 6 | "{": "}", |
|
- | 7 | "\"": "\"", |
|
5 | pass |
8 | } |
6 | 9 | ||
7 | def get_config(config_name): |
10 | def get_to(src, ptr, c, backwards = False): |
8 | if config_name == "KPACK_CMD": |
11 | while src[ptr] != c: |
9 | # Just never pack the file for now |
12 | if not backwards: |
10 | return "" |
13 | ptr += 1 |
11 | else: |
14 | else: |
12 | print(f"Unknown config name: {config_name}") |
15 | ptr -= 1 |
Line -... | Line 16... | ||
- | 16 | return ptr |
|
- | 17 | ||
- | 18 | # Assuming we are at beginning of some block (string, |
|
- | 19 | # parenthesed expression, {}-like thing), get to end |
|
- | 20 | # of the block (also handles the blocks openned in the |
|
13 | exit(-1) |
21 | # way to the block ending character. So it's not just |
- | 22 | # stupid searching for block closing character. |
|
- | 23 | def get_to_block_finisher(src, ptr): |
|
14 | 24 | assert(src[ptr] in block_beginner2finisher) |
|
- | 25 | ||
- | 26 | block_beginner = src[ptr] |
|
- | 27 | ptr += 1 |
|
- | 28 | while src[ptr] != block_beginner2finisher[block_beginner]: |
|
- | 29 | # If any block starts here - get to its end and then continue |
|
15 | def skip_whitespaces(src, ptr): |
30 | if src[ptr] in block_beginner2finisher: |
16 | while len(src) > ptr and src[ptr] == " ": |
31 | ptr = get_to_block_finisher(src, ptr) |
Line 17... | Line -... | ||
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 |
32 | ptr += 1 |
27 | return True |
- | |
28 | - | ||
29 | def parse_tup_getconfig(src, ptr): |
- | |
30 | # Skip get straight to the argument |
33 | return ptr |
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) |
34 | |
37 | ptr = skip_whitespaces(src, ptr) |
- | |
38 | # Skip closing parenthese of the tup.getconfig call |
- | |
Line -... | Line 35... | ||
- | 35 | def get_strnig(src, ptr): |
|
39 | assert(src[ptr] == ")") |
36 | # Strings starts with "\"" |
40 | ptr += 1 |
37 | assert(src[ptr] == "\"") |
41 | return (get_config(config_name), ptr) |
- | |
42 | 38 | ||
43 | def parse_string(src, ptr): |
39 | result = "" |
44 | ptr += 1 |
40 | # Skip first "\"" of the string |
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 |
41 | ptr += 1 |
Line 96... | Line 42... | ||
96 | if comma_encoutered: |
42 | while src[ptr] != "\"": |
97 | (argument, ptr) = parse_expression(src, ptr) |
43 | result += src[ptr] |
98 | result.append(argument) |
44 | ptr += 1 |
99 | return result |
45 | return result |
100 | 46 | ||
101 | def parse_rule(src, ptr): |
47 | def parse_rule_output(src, ptr): |
102 | # Get straight to the first argument |
- | |
103 | ptr += len("tup.rule(") |
- | |
104 | # Parse the arguments |
48 | # Get straight to the first argument |
105 | args = parse_arguments(src, ptr) |
49 | ptr += len("tup.rule") |
106 | # Build the rule object |
- | |
107 | result = Rule() |
50 | # Get to parenthese |
108 | if len(args) == 3: |
- | |
109 | result.input = args[0] |
- | |
110 | result.command = args[1] |
- | |
111 | result.output = args[2] |
51 | ptr = get_to(src, ptr, "(") |
112 | # Replace %f with input file in rule's command |
52 | # Get to the closing parenthese |
113 | if type(result.input == str): |
53 | ptr = get_to_block_finisher(src, ptr) |
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") |
54 | # We are at closing parenthese of argument list |
118 | exit() |
- | |
119 | # Replace %o with output file in rule's command |
55 | # And the last argument is always output file |
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] |
56 | # Let's get to closing "\"" of the output file name |
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 |
57 | ptr = get_to(src, ptr, "\"", backwards = True) |
134 | if type(result.input) == str: |
- | |
135 | result.input = [ result.input ] |
- | |
136 | else: |
- | |
137 | assert(type(result.input) == list) |
58 | # Get into the string |
Line 138... | Line 59... | ||
138 | if type(result.output) == str: |
59 | ptr -= 1 |
139 | result.output = [ result.output ] |
60 | # Then get to the beginning of the string |
140 | else: |
61 | ptr = get_to(src, ptr, "\"", backwards = True) |
141 | assert(type(result.output) == list) |
62 | # Now we can read the string |
142 | return result |
63 | return get_strnig(src, ptr) |
143 | 64 | ||
144 | def parse(file_name): |
65 | def parse_tupfile_outputs(file_name): |
145 | rules = [] |
66 | outputs = [] |
146 | with open(file_name) as f: |
67 | with open(file_name) as f: |
147 | tupfile = f.read() |
68 | tupfile = f.read() |