#!/usr/bin/env python
# Simple and indolent text processor to do inline go function calling

import sys, re


files = sys.argv
class inline(object):
  def __init__(self, name):
    self.name = name
    self.receiver = ""
    self.args = []
    self.contents = []
    self.file = ""
    self.original = ""

inlines = {}
for file in sorted(files, reverse=True):
  contents = open(file).read().splitlines()
  i = 0
  name  = ""
  while i < len(contents):
    line = contents[i]
    m = re.match(".*\/\/ \+inline-start", line)
    if m:
        # func (ls *LState) pushCallFrame(cf callFrame, fn LValue, meta bool) {
        m2 = re.match("^func\s*(\([\*\s\w]+\))?\s*(\w+)\(([^\)]*)\)", line)
        name = m2.group(2)
        tinline = inline(name)
        tinline.original = line.split("//")[0].strip().rstrip("{")
        tinline.file = file
        if m2.group(1):
          tinline.receiver = m2.group(1).split("(")[1].split(" ")[0]
        tinline.args = [arg.strip().split(" ")[0] for arg in m2.group(3).split(",")]
        inlines[name] = tinline
    else:
      if re.match(".*\/\/\s*\+inline-end", line):
        inlines[name].contents = "\n".join(inlines[name].contents)
        name = ""
      elif len(name) > 0:
        inlines[name].contents.append(line)
    i += 1

def do_inlining(text):
  contents = text.splitlines()
  buf = []
  i = 0
  while i < len(contents):
    line = contents[i]
    m = re.match("\s*\/\/\s*\+inline-call\s+([\w\.]+)\s+(.*)", line)
    if m:
      inlinet = inlines[m.group(1).split(".")[-1]]
      buf.append("// this section is inlined by go-inline")
      buf.append("//   source function 'is' {} in {}".format(inlinet.original, inlinet.file))
      buf.append("{")
      if len(inlinet.receiver) > 0 and inlinet.receiver != m.group(1).split(".")[0]:
          buf.append("{} := {}".format(inlinet.receiver, ".".join(m.group(1).split(".")[0:-1])))

      callargs = [arg.strip() for arg in m.group(2).split(" ")]
      for j in range(len(callargs)):
          if inlinet.args[j] != callargs[j]:
            buf.append("{} := {}".format(inlinet.args[j], callargs[j]))
      buf.append(do_inlining(inlinet.contents))
      buf.append("}")
    else:
      buf.append(line)
    i += 1
  return "\n".join(buf)

for file in files:
  if not file.startswith("_"):
    continue
  contents = open(file).read()
  with open(file.lstrip("_"), "w") as io:
    io.write("// This file was generated by go-inline.DO NOT EDIT.\n")
    io.write(do_inlining(contents))
    io.write("\n")
