Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 9376 → Rev 9377

/_tools/lib/tupfile_parser.py
1,153 → 1,74
# Copyright Magomed Kostoev
# Published under MIT license
 
class Rule:
pass
block_beginner2finisher = {
"(": ")",
"{": "}",
"\"": "\"",
}
 
def get_config(config_name):
if config_name == "KPACK_CMD":
# Just never pack the file for now
return ""
def get_to(src, ptr, c, backwards = False):
while src[ptr] != c:
if not backwards:
ptr += 1
else:
print(f"Unknown config name: {config_name}")
exit(-1)
ptr -= 1
return ptr
 
def skip_whitespaces(src, ptr):
while len(src) > ptr and src[ptr] == " ":
# Assuming we are at beginning of some block (string,
# parenthesed expression, {}-like thing), get to end
# of the block (also handles the blocks openned in the
# way to the block ending character. So it's not just
# stupid searching for block closing character.
def get_to_block_finisher(src, ptr):
assert(src[ptr] in block_beginner2finisher)
 
block_beginner = src[ptr]
ptr += 1
while src[ptr] != block_beginner2finisher[block_beginner]:
# If any block starts here - get to its end and then continue
if src[ptr] in block_beginner2finisher:
ptr = get_to_block_finisher(src, ptr)
ptr += 1
return ptr
 
# Returns True if @src has @string starting from @ptr index
def match_string(src, ptr, string):
if len(src) <= ptr + len(string):
return False
for i in range(len(string)):
if src[ptr + i] != string[i]:
return False
return True
def get_strnig(src, ptr):
# Strings starts with "\""
assert(src[ptr] == "\"")
 
def parse_tup_getconfig(src, ptr):
# Skip get straight to the argument
ptr += len("tup.getconfig(")
ptr = skip_whitespaces(src, ptr)
if src[ptr] != "\"":
print("Expected \"config name\" as tup.getconfig parameter")
exit()
(config_name, ptr) = parse_string(src, ptr)
ptr = skip_whitespaces(src, ptr)
# Skip closing parenthese of the tup.getconfig call
assert(src[ptr] == ")")
result = ""
# Skip first "\"" of the string
ptr += 1
return (get_config(config_name), ptr)
 
def parse_string(src, ptr):
ptr += 1
string = ""
while src[ptr] != "\"":
string += src[ptr]
result += src[ptr]
ptr += 1
# Skip the closing "\""
ptr += 1
ptr = skip_whitespaces(src, ptr)
# Check if we have concatination here
if match_string(src, ptr, ".."):
# Skip the ".."
ptr += 2
# The expression parsing should result in a string
(string_to_add, ptr) = parse_expression(src, ptr)
# Concat our string to the resulting string
string += string_to_add
return (string, ptr)
 
def parse_expression(src, ptr):
ptr = skip_whitespaces(src, ptr)
result = "WAT?!"
if src[ptr] == "\"":
(result, ptr) = parse_string(src, ptr)
elif match_string(src, ptr, "tup.getconfig("):
(result, ptr) = parse_tup_getconfig(src, ptr)
else:
print(f"Can't handle anything starting with '{src[ptr]}'")
exit(-1)
ptr = skip_whitespaces(src, ptr)
return (result, ptr)
 
def expect_comma(src, ptr):
comma_skept = False
ptr = skip_whitespaces(src, ptr)
if src[ptr] == ",":
ptr += 1
return (True, ptr)
else:
return (False, ptr)
 
def parse_arguments(src, ptr):
result = []
# Parse first argument
(argument, ptr) = parse_expression(src, ptr)
result.append(argument)
(comma_encoutered, ptr) = expect_comma(src, ptr)
# Parse the second argument if it's there
if comma_encoutered:
(argument, ptr) = parse_expression(src, ptr)
result.append(argument)
(comma_encoutered, ptr) = expect_comma(src, ptr)
# Parse third argument if it's there
if comma_encoutered:
(argument, ptr) = parse_expression(src, ptr)
result.append(argument)
return result
 
def parse_rule(src, ptr):
def parse_rule_output(src, ptr):
# Get straight to the first argument
ptr += len("tup.rule(")
# Parse the arguments
args = parse_arguments(src, ptr)
# Build the rule object
result = Rule()
if len(args) == 3:
result.input = args[0]
result.command = args[1]
result.output = args[2]
# Replace %f with input file in rule's command
if type(result.input == str):
result.command = result.command.replace("%f", result.input)
else:
print("Command building with non-string tup.rule's first argument"
+ " isn't implemented")
exit()
# Replace %o with output file in rule's command
if type(result.output == str):
result.command = result.command.replace("%o", result.output)
else:
print("Command building with non-string tup.rule's first argument"
+ " isn't implemented")
exit()
elif len(args) == 2:
result.input = []
result.command = args[0]
result.output = args[1]
else:
print(f"tup.rule can only take 2 or 3 arguments, not {len(args)}")
exit(-1)
# Unify the API - return arrays as input and output
if type(result.input) == str:
result.input = [ result.input ]
else:
assert(type(result.input) == list)
if type(result.output) == str:
result.output = [ result.output ]
else:
assert(type(result.output) == list)
return result
ptr += len("tup.rule")
# Get to parenthese
ptr = get_to(src, ptr, "(")
# Get to the closing parenthese
ptr = get_to_block_finisher(src, ptr)
# We are at closing parenthese of argument list
# And the last argument is always output file
# Let's get to closing "\"" of the output file name
ptr = get_to(src, ptr, "\"", backwards = True)
# Get into the string
ptr -= 1
# Then get to the beginning of the string
ptr = get_to(src, ptr, "\"", backwards = True)
# Now we can read the string
return get_strnig(src, ptr)
 
def parse(file_name):
rules = []
def parse_tupfile_outputs(file_name):
outputs = []
with open(file_name) as f:
tupfile = f.read()
rule_begin_index = tupfile.find("tup.rule(")
while (rule_begin_index != -1):
rules.append(parse_rule(tupfile, rule_begin_index))
outputs.append(parse_rule_output(tupfile, rule_begin_index))
# Find the next tup.rule call
rule_begin_index = tupfile.find("tup.rule(", rule_begin_index + len("tup.rule("))
return rules
return outputs