mesecode/mesecode.py
2014-10-13 16:19:20 +00:00

198 lines
5.0 KiB
Python

import re, sys, os
# How many spaces in a tab.
# -1 disables support for spaces as tabs (recommended)
# There are usually 4 spaces in a tab
SPACES_PER_TAB = -1
def throwParseError(msg):
print("\033[91mParse Error: " + msg + "\033[0m")
sys.exit(-1)
def checkMkDir(directory):
if not os.path.exists(directory):
os.makedirs(directory)
class MeseCodeParser:
class Node:
def __init__(self, parent, name, value, line, lineno):
self.line = line
self.lineno = lineno
self.name = name
self.value = value
self.children = []
def get(self, name):
for item in self.children:
if item.name == name:
return item
return None
def as_list(self):
retval = []
for item in self.value.split(","):
item = item.strip()
if item != "":
retval.append(item)
for item in self.children:
if item.line != "":
retval.append(item.line)
return retval
def parse(self, filename):
file = open(filename, "r")
self.objects = []
lineno = 0
for line in file.readlines():
lineno += 1
# Remove comments
if line.find("--") != -1:
line = line[:line.find("--")]
if line.strip() == "":
continue
# Find indentation level
if SPACES_PER_TAB != -1:
line = line.replace(SPACES_PER_TAB * " ", "\t")
indented = 0
m = re.search('([\\t]+)', line)
if m:
indented = len(m.group(1))
# Strip redundant symbols
line = line.strip()
if indented == 0:
# Is top level
self.objects.append(self.createNode(None, line, lineno))
else:
count = 1
if len(self.objects) == 0:
throwParseError("Unexpected level of indentation on line " + str(lineno))
node = self.objects[len(self.objects) - 1]
while count < indented:
if len(node.children) == 0:
throwParseError("Unexpected level of indentation on line " + str(lineno))
node = node.children[len(node.children) - 1]
count += 1
node.children.append(self.createNode(node, line, lineno))
return self
def __iter__(self):
return self.objects.__iter__()
def printOut(self, l, objs):
for obj in objs:
print((l*" ") + obj.name + ": " + obj.value)
self.printOut(l + 1, obj.children)
def createNode(self, parent, line, lineno):
return self.Node(parent, line.split(" ")[0], line[len(line.split(" ")[0]) + 1:], line, lineno)
class LuaBuilder:
class Node:
def __init__(self, name, value):
self.name = name
self.value = value
def __init__(self):
self.data = []
def set(self, name, value):
for item in self.data:
if item.name == name:
del item
break
self.data.append(self.Node(name, value))
def append(self, name, value):
for item in self.data:
if item.name == name:
item.value.append(value)
return
self.data.append(self.Node(name, [value]))
def build(self, header, indentation):
retval = header + "{\n"
for item in self.data:
retval += (indentation * "\t") + item.name + " = "
if isinstance(item.value, list):
retval += "{"
for i in item.value:
retval += i + ", "
retval += "}"
else:
retval += "\"" + item.value + "\""
retval += ",\n"
retval += "})\n"
return retval
def getCode(filename):
parser = MeseCodeParser().parse(filename)
modname = None
index = {}
for item in parser:
if item.name == "mod":
if modname is not None:
throwParseError("Mod namespace was redefined on line " + str(item.lineno))
modname = item.value
elif modname is None:
throwParseError("Mod namespace was not defined (You missed out 'mod nameofmod' at the beginning of the file)")
if item.name == "node":
index[item.value] = item
retval = ""
for item in parser:
if item.name == "node":
lb = LuaBuilder()
lb.set("description", item.value)
groups = item.get("is")
if groups is not None:
for group in groups.as_list():
if group.find("=") == -1:
lb.append("groups", group + " = 1")
else:
lb.append("groups", group)
drops = item.get("drops")
if drops is not None:
for drop in drops.as_list():
try:
element = index[drop]
if element.get("name") is not None:
lb.append("drops", "\"" + element.get("name").value + "\"")
else:
lb.append("drops", "\"" + element.value.lower().replace(" ", "_") + "\"")
except KeyError:
pass
name = item.get("name")
if name is None:
name = item.value.lower().replace(" ", "_")
else:
name = name.value
retval += lb.build("minetest.register_node(\"" + name + "\", ", 1) + "\n"
elif item.name == "script":
retval += "dofile(minetest.get_modpath(\"" + modname + "\") .. \"" + item.value + "\")\n\n"
if modname is None:
throwParseError("Mod namespace was not defined (You missed out 'mod nameofmod' at the beginning of the file)")
print(retval)
return retval
if __name__ == "__main__":
if len(sys.argv) == 2:
Project(sys.argv[1]).write("output")
elif len(sys.argv) == 3:
Project(sys.argv[1]).write(sys.argv[2])
else:
print("Usage: mesecode.py path/to/file.mese output/directory")