lpc4/lib/
lpc4/lib/doc/efun/
lpc4/lib/doc/lfun/
lpc4/lib/doc/operators/
lpc4/lib/doc/simul_efuns/
lpc4/lib/doc/types/
lpc4/lib/etc/
lpc4/lib/include/
lpc4/lib/include/arpa/
lpc4/lib/obj/d/
lpc4/lib/save/
lpc4/lib/secure/
lpc4/lib/std/
lpc4/lib/std/living/
#!/usr/local/bin/lpc -Cstay

/* Hubbes inkrementella lpc frontend - hilfe */

/* todo:
 *  return (void)1; will give me problems.
 *  strstr(string,string *) -> return first occurance of first string...
 *
 */

#!define catch(X) ((X),0)

#pragma all_inline

/* #define DEBUG */

mapping variables=([]);
string *functions=({});
string *function_names=({});
mapping query_variables() { return variables; }
/* do nothing */

object eval(string f)
{
  string program,file;
  object o;
  program="#pragma unpragma_strict_types\n#pragma all_inline\n"+
  "void create() { expunge(); }\n"+
  "static object ___hilfe=previous_object();\n"+
  "void write(mixed s) { efun::write(stringp(s)?s:sprintf(\"%O\",s)); }\n"+
  "static mapping ___variables=___hilfe->query_variables();\n"+
  implode(map_array(m_indices(variables),lambda(string f)
      { return sprintf("mixed %s=___variables[\"%s\"];",f,f); }),"\n")+
  "\nmapping query_variables() { return ([\n"+
  implode(map_array(m_indices(variables),lambda(string f)
      { return sprintf("    \"%s\":%s,",f,f); }),"\n")+
  "\n  ]);\n}\n"+
    implode(functions,"\n")+"\n"+ f+"\n";

#ifdef DEBUG
  write("program:"+program);
#endif
  if(catch(file=make_object(program))) return 0;
  o=clone_object(file);
  update(file);
  return o;
}

string input="";

string skipwhite(string f)
{
  while(sscanf(f,"%*[ \r\n\t]%s",f) && sscanf(f,"/*%*s*/%s",f));
  return f;
}

int find_next_comma(string s)
{
  int e, p, q;

  for(e=0;e<strlen(s);e++)
  {
    switch(s[e])
    {
    case '"':
      for(e++;s[e]!='"';e++)
      {
        switch(s[e])
        {
	case 0: return 0;
	case '\\': e++; break;
        }
      }
      break;

    case '{':
    case '(':
    case '[':
      p++;
      break;

    case ',':
      if(!p) return e;
      break;

    case '/':
      if(s[e+1]=='*')
	while(s[e-1..e]!="*/" && e<strlen(s)) e++;
      break;

    case '}':
    case ')':
    case ']':
      p--;
      if(p<0)
      {
	write("Syntax errror.\n");
	input="";
	return 0;
      }
      break;

    }
  }
  return 0;
}

string get_name(string f)
{
  int e,d;
  
  f=skipwhite(f);
  if(sscanf(f,"*%s",f)) f=skipwhite(f);
  sscanf(f,"%[a-zA-Z0-9_]",f);
  return f;
}

string first_word=0;
int pos=0;
int parenthese_level=0;
int in_comment=0;
int in_string=0;
int in_quote=0;
int eq_pos=-1;
int do_parse();
mixed parse_function(string s);
mixed parse_statement(string s);

void set_buffer(string s,int parsing)
{
  input=s;
  first_word=0;
  pos=-1;
  parenthese_level=0;
  in_comment=0;
  in_quote=0;
  in_string=0;
  eq_pos=-1;
  if(!parsing) do_parse();
}

void clean_buffer() { set_buffer("",0);  }

void add_buffer(string s)
{
  input+=s;
  do_parse();
}

void cut_buffer(int where)
{
  int old,new;
  old=strlen(input);
  input=skipwhite(input[where..old-1]);
  new=strlen(input);
  if(where>1) first_word=0;
  pos-=old-new; if(pos<0) pos=0;
  eq_pos-=old-new; if(eq_pos<0) eq_pos=-1;
#ifdef DEBUG
  write("CUT input = "+code_value(input,1)+"  pos="+pos+"\n");
#endif
}

int do_parse()
{
  string tmp;
  if(pos<0) pos=0;
  for(;pos<strlen(input);pos++)
  {
    if(in_quote) { in_quote=0; continue; }
    if(!first_word)
    {
      int d;
      d=input[pos];
      if(d==' ' && !pos)
      {
	cut_buffer(1);
	continue;
      }
      if((d<'a' || d>'z') && (d<'A' || d>'Z') && (d<'0' || d>'9') && d!='_')
      {
	first_word=input[0..pos-1];
#ifdef DEBUG
	write("First = "+code_value(first_word)+"  pos="+pos+"\n");
	write("input = "+code_value(input)+"\n");
#endif
	switch(first_word)
	{
	case "quit":
	  write("Exiting.\n");
	  exit(1);
	case ".":
	  clean_buffer();
	  write("Input buffer flushed.\n");
	  break;


	case "new":
	  this_object()->__INIT();
	  break;

	case "dump":
	  sum_arrays(lambda(string var,mixed foo)
		   {
		     write(sprintf("%-15s:%s\n",var,sprintf("%O",foo)));
		   },
		     m_indices(variables),
		     m_values(variables));
	  cut_buffer(4);

	}
      }
    }
    
    switch(input[pos])
    {
    case '\\':
      in_quote=1;
      break;
	
    case '=':
      if(in_string || in_comment  || parenthese_level || eq_pos!=-1) break;
      eq_pos=pos;
      break;
      
    case '"':
      if(in_comment) break;
      in_string=!in_string;
      break;

    case '{':
    case '(':
    case '[':
      if(in_string || in_comment) break;
      parenthese_level++;
      break;

    case '}':
    case ')':
    case ']':
      if(in_string || in_comment) break;
      if(--parenthese_level<0)
      {
	write("Syntax error.\n");
	clean_buffer();
	return 0;
      }
      if(!parenthese_level && input[pos]=='}')
      {
	if(tmp=parse_function(input[0..pos]))
	{
	  cut_buffer(pos+1);
	  if(stringp(tmp))
	    set_buffer(tmp+input,1);
	}
      }
      break;

    case ';':
      if(in_string || in_comment || parenthese_level) break;
      if(tmp=parse_statement(input[0..pos]))
      {
	cut_buffer(pos+1);
	if(stringp(tmp))
	  set_buffer(tmp+input,1);
      }
      break;
      
    case '*':
      if(in_string || in_comment) break;
      if(input[pos-1]=='/') in_comment=1;
      break;

    case '/':
      if(in_string) break;
      if(input[pos-1]=='*') in_comment=0;
      break;
    }
  }
  if(pos>strlen(input)) pos=strlen(input);
  return -1;
}


mixed parse_function(string fun)
{
  string name,a,b;
  object foo;
  mixed c;
#ifdef DEBUG
  write("Parsing block ("+first_word+")\n");
#endif

  switch(first_word)
  {
  case "if":
  case "for":
  case "do":
  case "while":
  case "foreach":
    /* parse loop */
    if(foo=eval("___Foo4711() { "+fun+" ; }\n"))
    {
      if(c=catch(foo->___Foo4711()))
      {
	write("error during evaluation: "+c);
      }else{
	write("Ok.\n");
	variables=foo->query_variables();
      }
    }
    return 1;

  case "int":
  case "void":
  case "object":
  case "mapping":
  case "string":
  case "list":
  case "float":
  case "mixed":
    /* parse function */
    if(eq_pos!=-1) break;  /* it's a variable */
    sscanf(fun,first_word+"%s",name);
    name=get_name(name);
    
    if(sscanf(fun,"%s"+name+"%s(",c,c) && skipwhite(c)=="")
    {
      int i;
      if((i=member_array(name,function_names))!=-1)
      {
	b=functions[i];
	functions[i]=fun;
	if(!eval(""))
	  functions[i]=b;
      }else{
	if(eval(fun))
	{
	  functions+=({fun});
	  function_names+=({name});
	}
      }
      return 1;
    }
  }
}

mixed parse_statement(string ex)
{
  string a,b,name;
  mixed c;
  object foo;
  int e;
#ifdef DEBUG
  write("Parsing statement ("+first_word+")\n");
#endif
  switch(first_word)
  {
  case "if":
  case "for":
  case "do":
  case "while":
  case "foreach":
    /* parse loop */
    if(foo=eval("___Foo4711() { "+ex+" ; }\n"))
    {
      if(c=catch(foo->___Foo4711()))
      {
	write("error during evaluation: "+c);
      }else{
	write("Ok.\n");
	variables=foo->query_variables();
      }
    }
    return 1;

  case "int":
  case "void":
  case "object":
  case "mapping":
  case "string":
  case "list":
  case "float":
  case "mixed":
    /* parse variable def. */
    sscanf(ex,first_word+"%s",b);
    b=skipwhite(b);
    name=get_name(b);

#ifdef DEBUG
    write("Variable def.\n");
#endif
    if(name=="") 
    {
      return 1;
    }else{
      string f;
      variables[name]=0;

      if(sscanf(ex,"%s"+name+"%s=%s",c,f,c)==3 && skipwhite(f)=="")
      {
#ifdef DEBUG
	write("Variable def. with assign. ("+name+")\n");
#endif
	if(e=find_next_comma(c))
	  return name+"="+c[0..e-1]+";\n"+
		     first_word+" "+c[e+1..strlen(c)-1];
	else
	  return name+"="+c;
#ifdef DEBUG
	write("Input buffer = '"+input+"'\n");
#endif

      }else{
	sscanf(b,"%s"+name+"%s",b,b);
	sscanf(b,",%s",b);
	return first_word+" "+b;
      }
    }
    
    return 1;

  default:
    /* parse expressions */
    a="___Foo4711() { return (mixed)("+ex[0..strlen(ex)-2]+"); }\n";
    if(foo=eval(a))
    {
      if(c=catch(a=sprintf("%O",foo->___Foo4711())))
      {
	write("error during evaluation: "+c);
      }else{
	write("Result: "+a+"\n");
	variables=foo->query_variables();
      }
    }
    return 1;
  }
}

void stdin(string s)
{
  string *tmp,a,b,c,f,name;
  int e,d;
  object foo;

#ifdef DEBUG
  write(save_object());
  write("input: "+code_value(s,1)+"\n");
#endif
  s=skipwhite(s);

  if(s[0..1]==".\n")
  {
    clean_buffer();
    write("Input buffer flushed.\n");
    s=s[2..strlen(s)-1];
  }
  add_buffer(s);
  if(!strlen(input))
    write("> ");
}

void main(int argc,string *argv)
{
  write("LPC"+version()+
	" Running Hilfe v1.1 (Hubbe's Incremental LPC FrontEnd)\n");
  write("> ");
}

int signal(int s)
{
  if(s==4)
  {
    clean_buffer();
    if(sizeof(previous_objects())>1)
      throw("**Break");
    else
      write("**Break\n");
  }
  return 1;
}