gambas-source-code/main/lib/eval/eval_analyze.c
Benoît Minisini 0ac184012a [DEVELOPMENT ENVIRONMENT]
* NEW: Database manager integration continues. You can create, edit and 
  remove tables now. You cannot rename them yet, nor modify their contents.
* BUG: Fix popup menu activation in text editor.
* NEW: Almost any character is allowed now in the name of directories 
  storing source files.

[GB.DB.FORM]
* NEW: DataSource.Reset() is a new method that clears the internal 
  metadata cache. That method is dynamic because it is intended to only
  reset the metadata associated with the DataSource. At the moment all the
  metadata is dropped.

[GB.FORM]
* NEW: TableView.Save() now returns a boolean that will tell you if the 
  Save event has been cancelled.
* BUG: TableView should manage arrow keys correctly if the current editor 
  is a read-only ComboBox.

[GB.FORM.MDI]
* OPT: Toolbars do no useless layout anymore when in design mode.

[GB.QT4]
* BUG: The Message class has been fixed.
* BUG: Fix the behaviour of TabStrip when all its page are hidden.


git-svn-id: svn://localhost/gambas/trunk@2115 867c0c6c-44f3-4631-809d-bfa615b0a4ec
2009-07-14 02:24:54 +00:00

501 lines
10 KiB
C

/***************************************************************************
eval_analyze.c
Syntax highlighting
(c) 2000-2007 Benoit Minisini <gambas@users.sourceforge.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
***************************************************************************/
#define __EVAL_ANALYZE_C
#include "gambas.h"
#include "gb_common.h"
#include "eval_analyze.h"
#include "CSystem.h"
/*#define DEBUG*/
static EVAL_COLOR colors[EVAL_MAX_COLOR];
static int colors_len;
static int get_type(PATTERN *pattern)
{
int type = PATTERN_type(*pattern);
int index = PATTERN_index(*pattern);
if (type == EVAL_TYPE_RESERVED)
{
if (index >= RS_COLON)
{
if (!((index == RS_AND || index == RS_OR) && PATTERN_is(pattern[1], RS_IF)))
type = EVAL_TYPE_OPERATOR;
}
else if (RES_is_type(index))
type = EVAL_TYPE_DATATYPE;
}
return type;
}
static int is_me_last(PATTERN pattern)
{
return PATTERN_is(pattern, RS_ME)
|| PATTERN_is(pattern, RS_SUPER)
|| PATTERN_is(pattern, RS_LAST)
|| PATTERN_is(pattern, RS_OPTIONAL)
|| PATTERN_is(pattern, RS_TRUE)
|| PATTERN_is(pattern, RS_FALSE)
|| PATTERN_is(pattern, RS_NULL)
|| PATTERN_is(pattern, RS_BYREF);
}
static void get_symbol(PATTERN pattern, const char **symbol, int *len)
{
static char keyword[16];
int i;
SYMBOL *sym;
int type = PATTERN_type(pattern);
int index = PATTERN_index(pattern);
switch(type)
{
case RT_RESERVED:
sym = TABLE_get_symbol(COMP_res_table, index);
break;
case RT_NUMBER:
case RT_IDENTIFIER:
case RT_CLASS:
sym = TABLE_get_symbol(EVAL->table, index);
break;
case RT_STRING:
case RT_TSTRING:
case RT_COMMENT:
case EVAL_TYPE_ERROR:
sym = TABLE_get_symbol(EVAL->string, index);
break;
case RT_SUBR:
*symbol = COMP_subr_info[index].name;
*len = strlen(*symbol);
return;
default:
*symbol = NULL;
*len = 0;
return;
}
*symbol = sym->name;
*len = sym->len;
if (*len > EVAL_COLOR_MAX_LEN)
*len = EVAL_COLOR_MAX_LEN;
if (type == RT_RESERVED && !EVAL->rewrite)
{
memcpy(keyword, sym->name, sym->len);
for (i = 0; i < sym->len; i++)
keyword[i] = toupper(keyword[i]);
*symbol = keyword;
}
}
static void add_data(int state, int len)
{
EVAL_COLOR *color;
if (colors_len >= EVAL_MAX_COLOR || len == 0)
return;
//printf("[%d] %d %d\n", colors_len, state, len);
color = &colors[colors_len];
color->state = state;
color->len = len;
color->alternate = FALSE;
colors_len++;
}
static int is_proc(void)
{
PATTERN pattern;
int i;
if (!EVAL->pattern)
return FALSE;
for (i = 0;; i++)
{
pattern = EVAL->pattern[i];
if (PATTERN_is_end(pattern))
return FALSE;
if (PATTERN_is(pattern, RS_PRIVATE) || PATTERN_is(pattern, RS_PUBLIC) || PATTERN_is(pattern, RS_STATIC))
continue;
return (PATTERN_is(pattern, RS_SUB) || PATTERN_is(pattern, RS_PROCEDURE) || PATTERN_is(pattern, RS_FUNCTION));
}
}
static int get_indent(bool *empty)
{
int i;
unsigned char c;
*empty = TRUE;
for (i = 0; i < (int)EVAL->len; i++)
{
c = EVAL->source[i];
if (c > ' ')
{
*empty = FALSE;
break;
}
}
return i;
}
static int get_utf8_length(const char *s, int l)
{
int len;
int i;
for (i = 0, len = 0; i < l; i++)
{
if ((s[i] & 0xC0) != 0x80)
len++;
}
return len;
}
static void analyze(EVAL_ANALYZE *result)
{
PATTERN *pattern;
const char *src;
int nspace;
bool empty;
int type, old_type, next_type;
const char *symbol;
bool space_before, space_after, in_quote;
//bool me = FALSE;
int len;
pattern = EVAL->pattern;
src = EVAL->source;
colors_len = 0;
if (EVAL->len <= 0)
return;
if (!EVAL->comment)
{
nspace = get_indent(&empty);
add_data(EVAL_TYPE_END, nspace);
}
if (empty)
return;
if (!EVAL->pattern)
return;
if (nspace)
GB.AddString(&result->str, EVAL->source, nspace);
type = EVAL->comment ? EVAL_TYPE_COMMENT : EVAL_TYPE_END;
next_type = EVAL_TYPE_END;
space_after = FALSE;
in_quote = FALSE;
for(;;)
{
old_type = next_type;
type = get_type(pattern);
next_type = type;
get_symbol(*pattern, &symbol, &len);
space_before = space_after;
space_after = FALSE;
if (type == EVAL_TYPE_END)
break;
if (in_quote && (type == EVAL_TYPE_RESERVED || type == EVAL_TYPE_DATATYPE || type == EVAL_TYPE_SUBR))
type = EVAL_TYPE_IDENTIFIER;
switch(type)
{
case EVAL_TYPE_RESERVED:
//state = Keyword;
//if (old_type != EVAL_TYPE_OPERATOR)
//me = is_me_last(*pattern);
if (!is_me_last(*pattern))
space_before = TRUE;
else
{
next_type = EVAL_TYPE_IDENTIFIER;
if (old_type != EVAL_TYPE_OPERATOR)
space_before = TRUE;
}
/*if (PATTERN_index(*pattern) >= RS_COLON)
{
int i;
for (i = 0; i < len; i++)
usym[i] = GB.toupper(symbol[i]);
usym[len] = 0;
symbol = usym;
}*/
break;
case EVAL_TYPE_DATATYPE:
//state = Datatype;
if (old_type != EVAL_TYPE_OPERATOR)
space_before = TRUE;
break;
case EVAL_TYPE_IDENTIFIER:
case EVAL_TYPE_CLASS:
//state = Symbol;
if (old_type != EVAL_TYPE_OPERATOR)
space_before = TRUE;
break;
case EVAL_TYPE_NUMBER:
//state = Number;
if (old_type != EVAL_TYPE_OPERATOR)
space_before = TRUE;
break;
case EVAL_TYPE_STRING:
//state = String;
if (old_type != EVAL_TYPE_OPERATOR)
space_before = TRUE;
break;
case EVAL_TYPE_SUBR:
//state = Subr;
if (old_type != EVAL_TYPE_OPERATOR)
space_before = TRUE;
break;
case EVAL_TYPE_COMMENT:
//state = Commentary;
space_before = *symbol != ' ';
break;
case EVAL_TYPE_OPERATOR:
if (index("([)]@", *symbol))
{
space_after = FALSE;
}
else if (index(":;,", *symbol))
{
space_before = FALSE;
space_after = TRUE;
}
else if (index("#{", *symbol))
{
if (old_type != EVAL_TYPE_OPERATOR)
space_before = TRUE;
space_after = FALSE;
in_quote = *symbol == '{';
}
else if (index("}", *symbol))
{
space_before = FALSE;
space_after = FALSE;
in_quote = FALSE;
}
else if (index(".!", *symbol)) //symbol[0] == '.' && symbol[1] == 0)
{
//space_before = FALSE;
space_after = FALSE;
}
else if (PATTERN_is(*pattern, RS_NOT))
{
space_after = TRUE;
}
else if (*symbol == '-')
{
if (old_type == EVAL_TYPE_OPERATOR && (PATTERN_is(pattern[-1], RS_LBRA) || PATTERN_is(pattern[-1],RS_LSQR)))
space_before = FALSE;
else
space_before = TRUE;
space_after = TRUE;
}
else
{
space_before = TRUE;
space_after = TRUE;
}
if (old_type == EVAL_TYPE_RESERVED)
space_before = TRUE;
break;
case EVAL_TYPE_ERROR:
space_before = TRUE;
break;
}
if (space_before && old_type != EVAL_TYPE_END)
{
GB.AddString(&result->str, " ", 1);
add_data(EVAL_TYPE_END, 1);
}
if (type == EVAL_TYPE_STRING)
GB.AddString(&result->str, "\"", 1);
//len = strlen(symbol);
/*if (type == EVAL_TYPE_IDENTIFIER && len >= 2 &&
islower(symbol[0]) && islower(symbol[1]))
{
char c = toupper(symbol[0]);
GB.AddString(&result->str, &c, 1);
GB.AddString(&result->str, &symbol[1], len - 1);
}
else*/
if (len)
{
GB.AddString(&result->str, symbol, len);
//printf("add: %.*s\n", len, symbol);
len = get_utf8_length(symbol, len);
}
if (type == EVAL_TYPE_STRING)
{
GB.AddString(&result->str, "\"", 1);
len += 2;
}
add_data(type, len);
//printf("add_data: %.d (%d)\n", type, len);
pattern++;
}
result->color = colors;
result->len = colors_len;
//fprintf(stderr, "analyze: %d %s\n", strlen(result->str), result->str);
}
#define add_pattern(_type, _index) EVAL->pattern[EVAL->pattern_count++] = PATTERN_make((_type), (_index));
static void add_end_pattern(void)
{
int index;
int len;
len = EVAL->len - (READ_source_ptr - EVAL->source);
if (len > 0)
{
TABLE_add_symbol(EVAL->string, READ_source_ptr, len, NULL, &index);
add_pattern(EVAL_TYPE_ERROR, index);
}
add_pattern(EVAL_TYPE_END, 0);
//get_symbol(PATTERN_make(EVAL_TYPE_ERROR, index), &sym, &len);
}
PUBLIC void EVAL_analyze(const char *src, int len, int state, EVAL_ANALYZE *result, bool rewrite)
{
int nspace = 0;
#ifdef DEBUG
printf("EVAL: %*.s\n", expr->len, expr->source);
#endif
CLEAR(result);
while (len > 0 && src[len - 1] == ' ')
{
len--;
nspace++;
}
result->len = 0;
result->str = NULL;
if (len > 0)
{
EVAL = &EVAL_read_expr;
EVAL_clear(EVAL);
GB.NewString(&EVAL->source, src, len);
GB.AddString(&EVAL->source, "\0\0", 2);
EVAL->len = len;
EVAL->analyze = TRUE;
EVAL->rewrite = rewrite;
EVAL->comment = state == EVAL_TYPE_COMMENT;
//fprintf(stderr, "EVAL_analyze: [%d] %.*s\n", EVAL->comment, len, src);
EVAL_start(EVAL);
TRY
{
EVAL_read();
}
CATCH
{
add_end_pattern();
}
END_TRY
analyze(result);
result->proc = is_proc();
result->state = EVAL->comment ? EVAL_TYPE_COMMENT : EVAL_TYPE_END;
//fprintf(stderr, "--> [%d]\n", EVAL->comment);
GB.FreeString(&EVAL->source);
}
else
{
result->proc = FALSE;
}
while (nspace > 0)
{
GB.AddString(&result->str, " ", nspace > 8 ? 8 : nspace);
nspace -= 8;
}
}