forked from KolibriOS/kolibrios
* get_started.py sets up a new workspace in a project folder * build.py builds the project using info from Tupfile.lua * run.py moves compiled program into kolibri.img and boots qemu on it Only supports very simple programs for now (tested on few demos). Only tested on Windows for now. git-svn-id: svn://kolibrios.org@9357 a494cfbc-eb01-0410-851d-a64ba20cac60
154 lines
4.8 KiB
Python
154 lines
4.8 KiB
Python
# Copyright Magomed Kostoev
|
|
# Published under MIT license
|
|
|
|
class Rule:
|
|
pass
|
|
|
|
def get_config(config_name):
|
|
if config_name == "KPACK_CMD":
|
|
# Just never pack the file for now
|
|
return ""
|
|
else:
|
|
print(f"Unknown config name: {config_name}")
|
|
exit(-1)
|
|
|
|
def skip_whitespaces(src, ptr):
|
|
while len(src) > ptr and 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 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] == ")")
|
|
ptr += 1
|
|
return (get_config(config_name), ptr)
|
|
|
|
def parse_string(src, ptr):
|
|
ptr += 1
|
|
string = ""
|
|
while src[ptr] != "\"":
|
|
string += 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):
|
|
# 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
|
|
|
|
def parse(file_name):
|
|
rules = []
|
|
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))
|
|
# Find the next tup.rule call
|
|
rule_begin_index = tupfile.find("tup.rule(", rule_begin_index + len("tup.rule("))
|
|
return rules
|