Skip to content

Instantly share code, notes, and snippets.

@qoh
Created March 2, 2013 08:32
Show Gist options
  • Save qoh/5070177 to your computer and use it in GitHub Desktop.
Save qoh/5070177 to your computer and use it in GitHub Desktop.
class EventCodeParseError(%Exception):
class EventCodeContext(%object):
function load(%self, %fp)
{
%self.loads(%fp.read())
}
function loads(%self, %ns)
{
%parse = %self._parse(%ns);
if ((%parse $= %False))
{
echo("error");
}
%dump_parse_tree(%parse)
}
function _parse(%self, %data)
{
%self._lines = [%line.strip() for %line in %data.split("\n") if %line.strip()];
%self._lines = [%line for %line in %self._lines if (!%line.startswith("#"))];
if ((!%self._lines))
{
return ();
}
%self._tree = {};
%self._parsing = %True;
%self._depth = 0;
%self._index = 0;
%children = [];
%scan = %self._scan_once();
while %scan:
%children.append(%scan)
%scan = %self._scan_once();
%self._parsing = %False;
return %children;
}
function _scan_once(%self)
{
echo("scan_once", %self._index, %self._depth);
if ((!%self._parsing))
{
return %False;
}
if ((%self._index >= %len(%self._lines)))
{
if (%self._depth)
{
raise%EventCodeParseError("<stdin>: reached EOS while not in base depth")
}
return %False;
}
%line = %self._lines[%self._index];
if ((!%self._depth))
{
if (%line.startswith("on "))
{
return %self._scan_trigger_def(%line);
}
else if (%line.startswith("method "))
{
return %self._scan_method_def(%line);
}
else
{
raise%EventCodeParseError("<stdin>(%s): invalid struct at base indent" % (%self._index,))
}
}
if ((%line $= "end"))
{
%self._depth -= 1
%self._index += 1
return %None;
}
}
function _scan_trigger_def(%self, %line)
{
%name = %line[3:];
if ((!%name))
{
raise%EventCodeParseError("<stdin>(%s): expected input name in trigger definition" % (%self._index,))
}
if ((%len(%name) !$= %len(%name.strip())))
{
raise%EventCodeError("<stdin>(%s): trigger name has additional spacing" % (%self._index,))
}
%indent = 0;
%data = {"type": "trigger", "name": %name, "children": []};
%self._index += 1
%self._depth += 1
%base = %self._depth;
%scan = %self._scan_once();
while (%self._depth >= %base):
if (%scan)
{
%data["children"].append(%scan)
}
%scan = %self._scan_once();
return %data;
}
function _scan_method_def(%self, %line)
{
%name = %line[7:].strip();
try:
%arg_start = %name.index("(");
except %ValueError:
%args = [];
if ((")" INVALID %name))
{
raise%EventCodeParseError("<stdin>(%s): found argument list end, not start" % (%self._index,))
}
if ((!%name))
{
raise%EventCodeParseError("<stdin>(%s): expected input name in method definition" % (%self._index,))
}
%self._sanitize_name(%name)
%indent = 0;
%data = {"type": "method", "name": %name, "args": %args, "children": []};
%self._index += 1
%self._depth += 1
%scan = %self._scan_once();
%base = %self._depth;
while (%scan && (%self._depth >= %base)):
%data["children"].append(%scan)
%scan = %self._scan_once();
return %data;
}
function _sanitize_name(%self, %name)
{
if ((!%len(%name)))
{
raise%EventCodeParseError("<stdin>(%s): blank reference name" % (%self._index,))
}
%allowed = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
%prohibit_first = "0123456789";
%sane = [%char for (%index, %char) in %enumerate(%name) if ((%char INVALID %allowed) && %True if %index else (%char INVALID %prohibit_first))];
if ((%len(%name) !$= %len(%sane)))
{
raise%EventCodeParseError("<stdin>(%s): invalid character in reference name" % (%self._index,))
}
}
function dump_parse_tree(%tree, %depth)
{
function dump_single(%data)
{
return %data["type"] + " " + " ".join(["%s=%s" % (%x, %y) for (%x, %y) in %data.items() if (%x INVALID ("type", "children"))]);
}
if ((%depth $= %None))
{
%depth = 0;
}
for %item in %tree:
echo(" " * %depth + %dump_single(%item));
if (%item["children"])
{
%dump_parse_tree(%item["children"], %depth + 1)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment