/*(( "Kopf" */
/* -----------------------------------------------------------------------------

   $Id: semantics_c.c,v 1.5 1997/07/17 00:24:10 mshopf Exp mshopf $

   GoldED API client, ©1995 Matthias Hopf.
   Compiled with SasC.

   Lisp style semantics parser

   ------------------------------------------------------------------------------
*/

/*)) */
#include "semantics.h"

/*(( "Private prototypes" */

FUNC (OUTSIDEBLOCK);
FUNC (BLOCK);
FUNC (COMMENT);
FUNC (STRING_DOUBLE);
FUNC (STRING_SINGLE);

/*)) */
/*(( "Indent_Lisp ()" */

/****** Main routine ******/
void    Indent_Lisp (sc_t *c)
{
    OUTSIDEBLOCK (c, 0);
    if (c->CurrentLine <= c->EndIndent)
	Error (c, UNMATCHED_BRACE_ERROR);
    debug (Dbug, ("\n\n"));             // Do it always...
}

/*)) */
/*(( "IsWord_Lisp ()" */

int IsWord_Lisp (sc_t *c, char *buf, int len, int maxlen)
{
    char *t;

    switch (len) {
    case 0:
	return MATCH_TRUE;

    case 1:
	switch (buf [0]) {
	case ';':
	case '\'':
	case '"':
	case '(':
	case ')':
	case '\\':
	    return MATCH_EXACT;
	}
	return MATCH_TRUE;
    }

    for (t = buf+1; t < & buf [len]; t++)
	if (*t == '\0' || *t == ' ' || *t == '\t' || *t == ';' ||
	    *t == '('  || *t == ')' || *t == '"'  || *t == '\'' || *t == '\\')
	    return MATCH_FALSE;

    return MATCH_TRUE;
}


/*)) */
/*(( "KeyPress_Lisp ()" */

void KeyPress_Lisp (sc_t *c, int key)
{
    int Line   = c->Edit->Line;
    int StartLine = -1, EndLine = -1;

    switch (key) {

    case ';':
	StartLine = EndLine = Line;
	break;

    case '(':
    case ')':
	StartLine = EndLine = Line;
	break;

    case '\n':
    case '\15':
	StartLine = Line > 0 ? Line-1 : 0;
	EndLine   = Line;
    }

    if (StartLine >= 0)
    {
	InitIndent (c, StartLine, EndLine, MODE_LINE | MODE_CURSOR);
	Indent_Lisp (c);
	CleanupIndent (c);
    }
}


/*)) */
/*(( "Semantics structure" */

/****** Method structure ******/
struct Semantic Lisp_Sem =
{
    "Lisp",
    "Lisp semantics parser",
    "V0.1 ©1995 Matthias Hopf",
    IsWord_Lisp,
    KeyPress_Lisp,
    Indent_Lisp,
    { 1, 9, 9, 9, 1, 4, 40 }            /* 9: not used here*/
} ;

/*)) */
/*(( "Parser specific errors" */

static const char *FUNCTION_AFTER_BRACE_EXPECTED_ERROR = "Expecting function invocation after brace in line %ld";

/*))*/

/*(( "OUTSIDEBLOCK ()" */

FUNC (OUTSIDEBLOCK)
{
    debug (D_PARSER, ("OUTSIDEBLOCK(%ld)\t", I));
    dcheck;

    DOGET
    {
	switch (W[0]) {                 // no test for length == 1 !
	case '(':
	    UPDATE (I);
	    c->BlockIndent = C;
	    CALL   (BLOCK, C + CONFIG.Block_Level);
	    break;

	case ')':
	    Error (c, UNMATCHED_BRACE_ERROR);
	    return;

	case ';':
	    if (BOL)
	    {
		if (C == 0)
		    INDENT (0);
		else
		    INDENT (I+CONFIG.Comment_Level);
	    }
	    else
		INDENT (CONFIG.LineComment_Abs);
	    CALL (COMMENT, C);
	    break;

	default:
	    Error (c, SYNTAX_ERROR);
	}
    }
}

/*))*/
/*(( "BLOCK ()" */

FUNC (BLOCK)
{
    int argnr = 0, lastlevel;
    debug (D_PARSER, ("BLOCK(%ld)\t", I));
    dcheck;

    lastlevel = c->BlockIndent;

    DOGET
    {
	PEEK;
	if (P[0] == ';')
	    SETEOL;
	switch (W[0]) {                 // no test for length == 1 !
	case '(':
	    INDENT (I);
	    switch (argnr++) {
	    case 0:
	    case 1:
		I = C;
	    }
	    c->BlockIndent = C;
	    CALL   (BLOCK, C + CONFIG.Block_Level);
	    c->BlockIndent = lastlevel;
	    break;

	case ')':
	    INDENT (lastlevel);
	    return;

	case ';':
	    if (BOL)
	    {
		if (C == 0)
		    INDENT (0);
		else
		    INDENT (I+CONFIG.Comment_Level);
	    }
	    else
		INDENT (CONFIG.LineComment_Abs);
	    CALL (COMMENT, C);
	    break;

	case '"':
	    switch (argnr++) {
	    case 0:
		Error (c, FUNCTION_AFTER_BRACE_EXPECTED_ERROR);
		break;
	    case 1:
		UPDATE (I);
		break;
	    default:
		INDENT (I);
	    }
	    CALL (STRING_DOUBLE, C+1);
	    break;

	case '\'':
	    switch (argnr++) {
	    case 0:
		Error (c, FUNCTION_AFTER_BRACE_EXPECTED_ERROR);
		break;
	    case 1:
		UPDATE (I);
		break;
	    default:
		INDENT (I);
	    }
	    CALL (STRING_SINGLE, C+1);
	    break;

	default:
	    switch (argnr++) {
	    case 0:
		INDENT (I);
		I = N;
		break;
	    case 1:
		UPDATE (I);
		break;
	    default:
		INDENT (I);
	    }

	}
    }
}

/*)) */
/*(( "COMMENT ()" */

FUNC (COMMENT)
{
    debug (D_PARSER, ("COMMENT(%ld)\t", I));
    dcheck;

    GET;
    while (*W == ';')
    {
	I = C;
	GET;
    }
    INDENT (I + 2);
    UNGET;

    DOGET
    {
	if (EOL)
	    return;
    }
}

/*)) */
/*(( "STRING_SINGLE ()" */

FUNC (STRING_SINGLE)
{
    debug (D_PARSER, ("STRING_SINGLE(%ld)\t", I));
    dcheck;

    if (EOL)
	ERROR (STRING_TERMINATION_ERROR);

    DOGET
    {
	if (W[1] == 0)
	{
	    switch (W[0]) {
	    case '\'':
		return;

	    case '\\':
		GET;                    /* skip next char (may be ' or \ ) */
	    }
	}
	if (EOL)
	    ERROR (STRING_TERMINATION_ERROR);
    }
}

/*)) */
/*(( "STRING_DOUBLE ()" */

FUNC (STRING_DOUBLE)
{
    debug (D_PARSER, ("STRING_DOUBLE(%ld)\t", I));
    dcheck;

    if (EOL)
	ERROR (STRING_TERMINATION_ERROR);

    DOGET
    {
	if (W[1] == 0)
	{
	    switch (W[0]) {
	    case '"':
		return;

	    case '\\':
		GET;                    /* skip next char (may be " or \ ) */
	    }
	}
	if (EOL)
	    ERROR (STRING_TERMINATION_ERROR);
    }
}

/*)) */

