5f4f12acf3
* NEW: UNSAFE is a new keyword used in conjunction with FAST. It tells the JIT compiler not to do any safety check (null objects, division by zero, out of array bounds...). It makes the code a bit faster, but prone to segmentation fault. [INTERPRETER] * NEW: Support for the UNSAFE keyword. [GB.JIT] * NEW: Support for the UNSAFE keyword. * NEW: Check validity of objects that can be invalid.
1147 lines
22 KiB
C
1147 lines
22 KiB
C
/***************************************************************************
|
|
|
|
gbc_header.c
|
|
|
|
(c) 2000-2017 Benoît Minisini <g4mba5@gmail.com>
|
|
|
|
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 2, 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., 51 Franklin Street, Fifth Floor, Boston,
|
|
MA 02110-1301, USA.
|
|
|
|
***************************************************************************/
|
|
|
|
#define _TRANS_HEADER_C
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
|
|
#include "gb_common.h"
|
|
#include "gb_error.h"
|
|
#include "gb_str.h"
|
|
#include "gb_file.h"
|
|
#include "gb_table.h"
|
|
|
|
#include "gbc_compile.h"
|
|
#include "gbc_trans.h"
|
|
#include "gbc_header.h"
|
|
#include "gb_code.h"
|
|
|
|
/*#define DEBUG*/
|
|
|
|
|
|
static void check_public_private(PATTERN **look, bool *is_public)
|
|
{
|
|
*is_public = JOB->is_module && JOB->public_module;
|
|
|
|
if (PATTERN_is(**look, RS_PUBLIC))
|
|
{
|
|
*is_public = TRUE;
|
|
(*look)++;
|
|
}
|
|
else if (PATTERN_is(**look, RS_PRIVATE))
|
|
{
|
|
*is_public = FALSE;
|
|
(*look)++;
|
|
}
|
|
}
|
|
|
|
static PATTERN *jump_expression(PATTERN *look)
|
|
{
|
|
int niv = 0;
|
|
|
|
for(;;)
|
|
{
|
|
if (PATTERN_is_newline(*look))
|
|
break;
|
|
|
|
if (PATTERN_is(*look, RS_LBRA) || PATTERN_is(*look, RS_LSQR))
|
|
{
|
|
niv++;
|
|
}
|
|
else if (PATTERN_is(*look, RS_RBRA) || PATTERN_is(*look, RS_RSQR))
|
|
{
|
|
if (niv > 0)
|
|
niv--;
|
|
else
|
|
break;
|
|
}
|
|
else if (niv == 0)
|
|
{
|
|
if (PATTERN_is(*look, RS_COMMA))
|
|
break;
|
|
}
|
|
|
|
look++;
|
|
}
|
|
|
|
return look;
|
|
}
|
|
|
|
static void analyze_function_desc(TRANS_FUNC *func, int flag)
|
|
{
|
|
PATTERN *look = JOB->current;
|
|
TRANS_PARAM *param;
|
|
//bool is_output;
|
|
bool is_optional = FALSE;
|
|
TRANS_DECL ttyp;
|
|
uint64_t byref_mask = 1;
|
|
|
|
if (!PATTERN_is_identifier(*look))
|
|
THROW("Syntax error. Invalid identifier in function name");
|
|
|
|
func->index = PATTERN_index(*look);
|
|
TYPE_clear(&func->type);
|
|
look++;
|
|
|
|
if (flag & HF_EVENT)
|
|
TABLE_copy_symbol_with_prefix(JOB->class->table, func->index, ':', &func->index);
|
|
|
|
func->nparam = 0;
|
|
func->byref = 0;
|
|
func->vararg = FALSE;
|
|
|
|
if ((flag & HF_VOID) && PATTERN_is_newline(*look))
|
|
{
|
|
JOB->current = ++look;
|
|
return;
|
|
}
|
|
|
|
if (!PATTERN_is(*look, RS_LBRA))
|
|
THROW_UNEXPECTED(look);
|
|
look++;
|
|
|
|
for(;;)
|
|
{
|
|
if (func->nparam >= MAX_PARAM_FUNC)
|
|
THROW("Too many arguments");
|
|
|
|
param = &func->param[func->nparam];
|
|
CLEAR(param);
|
|
|
|
if (PATTERN_is(*look, RS_RBRA))
|
|
{
|
|
look++;
|
|
break;
|
|
}
|
|
|
|
if (func->nparam > 0)
|
|
{
|
|
if (!PATTERN_is(*look, RS_COMMA))
|
|
THROW(E_SYNTAX_MISSING, "',' or ')'");
|
|
look++;
|
|
}
|
|
|
|
if (PATTERN_is(*look, RS_3PTS) && !(flag & HF_NO_3PTS))
|
|
{
|
|
look++;
|
|
if (!PATTERN_is(*look, RS_RBRA))
|
|
THROW("Syntax error. '...' must be the last argument"); //, get_num_desc(func->nparam + 1));
|
|
look++;
|
|
func->vararg = TRUE;
|
|
break;
|
|
}
|
|
|
|
//is_output = FALSE;
|
|
|
|
if (!(flag & HF_NO_OPT))
|
|
{
|
|
if (PATTERN_is(*look, RS_OPTIONAL))
|
|
{
|
|
look++;
|
|
is_optional = TRUE;
|
|
}
|
|
}
|
|
|
|
if (PATTERN_is(*look, RS_AT) || PATTERN_is(*look, RS_BYREF))
|
|
{
|
|
func->byref |= byref_mask;
|
|
look++;
|
|
}
|
|
|
|
if (PATTERN_is(*look, RS_LBRA))
|
|
{
|
|
param->ignore = TRUE;
|
|
look++;
|
|
}
|
|
|
|
if (!PATTERN_is_identifier(*look))
|
|
THROW("Syntax error. The &1 argument is not a valid identifier", TRANS_get_num_desc(func->nparam + 1));
|
|
|
|
param->index = PATTERN_index(*look);
|
|
look++;
|
|
|
|
if (param->ignore)
|
|
{
|
|
if (!PATTERN_is(*look, RS_RBRA))
|
|
THROW(E_MISSING, "')'");
|
|
look++;
|
|
}
|
|
|
|
JOB->current = look;
|
|
|
|
if (!TRANS_type(TT_NOTHING, &ttyp))
|
|
THROW("Syntax error. Invalid type description of &1 argument", TRANS_get_num_desc(func->nparam + 1));
|
|
|
|
param->type = ttyp.type;
|
|
|
|
/*
|
|
if (is_output)
|
|
TYPE_set_flag(¶m->type, TF_OUTPUT);
|
|
*/
|
|
|
|
look = JOB->current;
|
|
|
|
if (is_optional)
|
|
{
|
|
param->optional = look;
|
|
look = jump_expression(look);
|
|
JOB->current = look;
|
|
}
|
|
|
|
func->nparam++;
|
|
byref_mask <<= 1;
|
|
}
|
|
|
|
JOB->current = look;
|
|
}
|
|
|
|
|
|
static void header_module_type(void)
|
|
{
|
|
const char *ext;
|
|
const FORM_FAMILY *p;
|
|
|
|
/*JOB->class->name = STR_copy(FILE_get_name(JOB->name));*/
|
|
|
|
ext = FILE_get_ext(JOB->name);
|
|
|
|
if (strcasecmp(ext, "module") == 0)
|
|
{
|
|
JOB->is_module = TRUE;
|
|
JOB->is_form = FALSE;
|
|
}
|
|
else if (strcasecmp(ext, "class") == 0)
|
|
{
|
|
JOB->is_module = FALSE;
|
|
JOB->is_form = FALSE;
|
|
}
|
|
else
|
|
{
|
|
p = COMP_form_families;
|
|
while (p->ext)
|
|
{
|
|
if (strcasecmp(ext, p->ext) == 0)
|
|
{
|
|
JOB->is_module = FALSE;
|
|
JOB->is_form = TRUE;
|
|
break;
|
|
}
|
|
p++;
|
|
}
|
|
|
|
if (!p->ext)
|
|
THROW("Unknown file extension");
|
|
}
|
|
|
|
JOB->declared = TRUE;
|
|
}
|
|
|
|
|
|
static bool header_event(TRANS_EVENT *event)
|
|
{
|
|
PATTERN *look = JOB->current;
|
|
//TRANS_DECL ttyp;
|
|
|
|
if (!PATTERN_is(*look, RS_EVENT))
|
|
return FALSE;
|
|
|
|
CLEAR(event);
|
|
|
|
if (JOB->is_module)
|
|
THROW("A module cannot raise events");
|
|
|
|
JOB->current++;
|
|
analyze_function_desc((TRANS_FUNC *)event, HF_VOID + HF_NO_BYREF + HF_NO_3PTS + HF_NO_OPT);
|
|
|
|
/*if (PATTERN_is(*JOB->current, RS_AS))
|
|
{
|
|
if (!TRANS_type(TT_CAN_SQUARE, &ttyp))
|
|
THROW("Syntax error in return type");
|
|
event->type = ttyp.type;
|
|
}*/
|
|
|
|
TYPE_set_kind(&event->type, TK_EVENT);
|
|
TYPE_set_flag(&event->type, TF_PUBLIC);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
static bool header_property(TRANS_PROPERTY *prop)
|
|
{
|
|
TRANS_DECL ptype;
|
|
PATTERN *look = JOB->current;
|
|
bool is_static = FALSE;
|
|
bool is_public = TRUE;
|
|
|
|
CLEAR(prop);
|
|
|
|
/* static */
|
|
|
|
if (JOB->is_module)
|
|
{
|
|
is_static = TRUE;
|
|
}
|
|
else if (PATTERN_is(*look, RS_STATIC))
|
|
{
|
|
is_static = TRUE;
|
|
look++;
|
|
}
|
|
|
|
/* public */
|
|
|
|
if (PATTERN_is(*look, RS_PUBLIC) || PATTERN_is(*look, RS_PRIVATE))
|
|
{
|
|
is_public = PATTERN_is(*look, RS_PUBLIC);
|
|
look++;
|
|
}
|
|
|
|
if (!PATTERN_is(*look, RS_PROPERTY))
|
|
return FALSE;
|
|
look++;
|
|
JOB->current = look;
|
|
|
|
if (!is_public)
|
|
THROW("A property must be public");
|
|
|
|
/* read-only property */
|
|
|
|
if (PATTERN_is(*JOB->current, RS_READ))
|
|
{
|
|
prop->read = TRUE;
|
|
JOB->current++;
|
|
}
|
|
else
|
|
prop->read = FALSE;
|
|
|
|
/* property name */
|
|
|
|
if (!PATTERN_is_identifier(*JOB->current))
|
|
THROW("Syntax error. Invalid identifier in property name");
|
|
|
|
prop->index = PATTERN_index(*JOB->current);
|
|
JOB->current++;
|
|
|
|
prop->nsynonymous = 0;
|
|
|
|
while (TRANS_is(RS_COMMA))
|
|
{
|
|
if (prop->nsynonymous == 3)
|
|
THROW("Too many property synonymous");
|
|
if (!PATTERN_is_identifier(*JOB->current))
|
|
THROW("Syntax error. Invalid identifier in property name");
|
|
prop->synonymous[prop->nsynonymous++] = PATTERN_index(*JOB->current);
|
|
JOB->current++;
|
|
}
|
|
|
|
if (!TRANS_type(TT_NOTHING, &ptype))
|
|
THROW("Syntax error. Bad property type");
|
|
|
|
prop->type = ptype.type;
|
|
prop->line = JOB->line;
|
|
|
|
TYPE_set_kind(&prop->type, TK_PROPERTY);
|
|
if (is_static)
|
|
TYPE_set_flag(&prop->type, TF_STATIC);
|
|
TYPE_set_flag(&prop->type, TF_PUBLIC);
|
|
|
|
if (PATTERN_is_string(*JOB->current))
|
|
{
|
|
prop->comment = PATTERN_index(*JOB->current);
|
|
JOB->current++;
|
|
}
|
|
else
|
|
prop->comment = NO_SYMBOL;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static bool header_extern(TRANS_EXTERN *trans)
|
|
{
|
|
PATTERN *look = JOB->current;
|
|
TRANS_DECL ttyp;
|
|
int index;
|
|
bool is_public;
|
|
|
|
check_public_private(&look, &is_public);
|
|
|
|
if (!PATTERN_is(*look, RS_EXTERN))
|
|
return FALSE;
|
|
look++;
|
|
|
|
CLEAR(trans);
|
|
|
|
JOB->current = look;
|
|
analyze_function_desc((TRANS_FUNC *)trans, HF_NO_BYREF);
|
|
|
|
if (PATTERN_is(*JOB->current, RS_AS))
|
|
{
|
|
if (!TRANS_type(TT_NOTHING, &ttyp))
|
|
THROW("Syntax error in return type");
|
|
trans->type = ttyp.type;
|
|
}
|
|
|
|
if (TRANS_is(RS_IN))
|
|
{
|
|
if (!PATTERN_is_string(*JOB->current))
|
|
THROW("Library name must be a string");
|
|
|
|
index = PATTERN_index(*JOB->current);
|
|
JOB->current++;
|
|
}
|
|
else
|
|
{
|
|
if (JOB->default_library == NO_SYMBOL)
|
|
THROW(E_MISSING, "IN");
|
|
|
|
index = JOB->default_library;
|
|
}
|
|
|
|
trans->library = index;
|
|
|
|
if (TRANS_is(RS_EXEC))
|
|
{
|
|
if (!PATTERN_is_string(*JOB->current))
|
|
THROW("Alias name must be a string");
|
|
|
|
trans->alias = PATTERN_index(*JOB->current);
|
|
JOB->current++;
|
|
}
|
|
else
|
|
trans->alias = NO_SYMBOL;
|
|
|
|
TYPE_set_kind(&trans->type, TK_EXTERN);
|
|
TYPE_set_flag(&trans->type, TF_STATIC);
|
|
if (is_public) TYPE_set_flag(&trans->type, TF_PUBLIC);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static bool header_class(TRANS_DECL *decl)
|
|
{
|
|
if (!TRANS_is(RS_CLASS))
|
|
return FALSE;
|
|
|
|
if (!PATTERN_is_identifier(*JOB->current))
|
|
THROW("Syntax error. CLASS needs an identifier");
|
|
|
|
CLEAR(decl);
|
|
decl->index = PATTERN_index(*JOB->current);
|
|
JOB->current++;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static bool header_declaration(TRANS_DECL *decl)
|
|
{
|
|
PATTERN *look = JOB->current;
|
|
PATTERN *save;
|
|
bool is_static = FALSE;
|
|
bool is_public = FALSE;
|
|
bool is_const = FALSE;
|
|
bool no_warning = FALSE;
|
|
|
|
/* static ! */
|
|
|
|
if (JOB->is_module)
|
|
{
|
|
is_static = TRUE;
|
|
}
|
|
else if (PATTERN_is(*look, RS_STATIC))
|
|
{
|
|
is_static = TRUE;
|
|
//has_static = TRUE;
|
|
look++;
|
|
}
|
|
|
|
check_public_private(&look, &is_public);
|
|
|
|
/* const ? */
|
|
|
|
is_const = FALSE;
|
|
|
|
if (PATTERN_is(*look, RS_CONST))
|
|
{
|
|
//if (has_static)
|
|
// THROW("Unexpected &1", "STATIC");
|
|
|
|
is_const = TRUE;
|
|
look++;
|
|
}
|
|
|
|
if (PATTERN_is(*look, RS_LBRA))
|
|
{
|
|
no_warning = TRUE;
|
|
look++;
|
|
}
|
|
|
|
if (!PATTERN_is_identifier(*look))
|
|
return FALSE;
|
|
|
|
CLEAR(decl);
|
|
|
|
decl->index = PATTERN_index(*look);
|
|
look++;
|
|
|
|
if (no_warning)
|
|
{
|
|
if (!PATTERN_is(*look, RS_RBRA))
|
|
return FALSE;
|
|
look++;
|
|
decl->no_warning = TRUE;
|
|
}
|
|
|
|
save = JOB->current;
|
|
JOB->current = look;
|
|
|
|
if (!TRANS_type((!is_const ? TT_CAN_ARRAY | TT_CAN_EMBED : 0) | TT_CAN_NEW, decl))
|
|
{
|
|
JOB->current = save;
|
|
return FALSE;
|
|
}
|
|
|
|
if (is_static) TYPE_set_flag(&decl->type, TF_STATIC);
|
|
if (is_public) TYPE_set_flag(&decl->type, TF_PUBLIC);
|
|
if (is_const)
|
|
TYPE_set_kind(&decl->type, TK_CONST);
|
|
else
|
|
TYPE_set_kind(&decl->type, TK_VARIABLE);
|
|
|
|
if (is_const)
|
|
{
|
|
if (!decl->init)
|
|
THROW(E_SYNTAX_MISSING, "'='");
|
|
|
|
JOB->current = decl->init;
|
|
JOB->current = TRANS_get_constant_value(decl, JOB->current);
|
|
}
|
|
|
|
//JOB->current = look;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
static bool header_enumeration(TRANS_DECL *decl)
|
|
{
|
|
PATTERN *look = JOB->current;
|
|
bool is_public;
|
|
int value = 0;
|
|
|
|
check_public_private(&look, &is_public);
|
|
|
|
if (!PATTERN_is(*look, RS_ENUM))
|
|
return FALSE;
|
|
look++;
|
|
|
|
JOB->current = look;
|
|
|
|
for(;;)
|
|
{
|
|
TRANS_newline();
|
|
|
|
if (!PATTERN_is_identifier(*JOB->current))
|
|
THROW("Syntax error. Identifier expected.");
|
|
|
|
CLEAR(decl);
|
|
|
|
decl->index = PATTERN_index(*JOB->current);
|
|
JOB->current++;
|
|
|
|
decl->type = TYPE_make_simple(T_INTEGER);
|
|
|
|
if (is_public) TYPE_set_flag(&decl->type, TF_PUBLIC);
|
|
TYPE_set_kind(&decl->type, TK_CONST);
|
|
|
|
if (TRANS_is(RS_EQUAL))
|
|
{
|
|
JOB->current = TRANS_get_constant_value(decl, JOB->current);
|
|
value = decl->value + 1;
|
|
}
|
|
else
|
|
{
|
|
decl->value = value;
|
|
value++;
|
|
}
|
|
|
|
CLASS_add_declaration(JOB->class, decl);
|
|
|
|
if (TRANS_newline())
|
|
break;
|
|
|
|
if (!PATTERN_is(*JOB->current, RS_COMMA))
|
|
THROW_UNEXPECTED(JOB->current);
|
|
JOB->current++;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
static bool header_function(TRANS_FUNC *func)
|
|
{
|
|
static HEADER_SPECIAL spec[] =
|
|
{
|
|
{ "_init", HS_PUBLIC + HS_STATIC + HS_PROCEDURE + HS_NOPARAM },
|
|
{ "_exit", HS_PUBLIC + HS_STATIC + HS_PROCEDURE + HS_NOPARAM},
|
|
{ "_new", HS_PUBLIC + HS_DYNAMIC + HS_PROCEDURE },
|
|
{ "_free", HS_PUBLIC + HS_DYNAMIC + HS_PROCEDURE + HS_NOPARAM },
|
|
{ "_call", HS_PUBLIC },
|
|
{ "_get", HS_PUBLIC + HS_FUNCTION },
|
|
{ "_put", HS_PUBLIC + HS_PROCEDURE + HS_PUT },
|
|
{ "_next", HS_PUBLIC + HS_NOPARAM },
|
|
{ "_property", HS_PUBLIC + HS_NOPARAM + HS_FUNCTION + HS_PROPERTY },
|
|
{ "_unknown", HS_PUBLIC + HS_UNKNOWN },
|
|
{ "_compare", HS_PUBLIC + HS_DYNAMIC + HS_FUNCTION + HS_COMPARE },
|
|
{ "_attach", HS_PUBLIC + HS_DYNAMIC + HS_PROCEDURE + HS_ATTACH },
|
|
{ NULL, 0 }
|
|
};
|
|
|
|
PATTERN *look = JOB->current;
|
|
PATTERN pat;
|
|
TRANS_DECL ttyp;
|
|
SYMBOL *sym;
|
|
HEADER_SPECIAL *hsp;
|
|
|
|
bool is_proc = FALSE;
|
|
bool is_static = FALSE;
|
|
bool is_public = FALSE;
|
|
bool is_fast = FALSE;
|
|
bool is_unsafe = FALSE;
|
|
|
|
// fast ?
|
|
|
|
if (PATTERN_is(*look, RS_FAST))
|
|
{
|
|
is_fast = TRUE;
|
|
look++;
|
|
|
|
if (PATTERN_is(*look, RS_UNSAFE))
|
|
{
|
|
is_unsafe = TRUE;
|
|
look++;
|
|
}
|
|
}
|
|
|
|
// static ?
|
|
|
|
if (JOB->is_module)
|
|
{
|
|
is_static = TRUE;
|
|
}
|
|
else if (PATTERN_is(*look, RS_STATIC))
|
|
{
|
|
is_static = TRUE;
|
|
look++;
|
|
}
|
|
|
|
// public ou static ?
|
|
|
|
is_public = JOB->is_module && JOB->public_module;
|
|
|
|
if (PATTERN_is(*look, RS_PUBLIC))
|
|
{
|
|
is_public = TRUE;
|
|
look++;
|
|
}
|
|
else if (PATTERN_is(*look, RS_PRIVATE))
|
|
{
|
|
is_public = FALSE;
|
|
look++;
|
|
}
|
|
|
|
if (PATTERN_is(*look, RS_PROCEDURE) || PATTERN_is(*look, RS_SUB))
|
|
is_proc = TRUE;
|
|
else if (!PATTERN_is(*look, RS_FUNCTION))
|
|
return FALSE;
|
|
look++;
|
|
|
|
//CLEAR(func);
|
|
|
|
JOB->current = look;
|
|
analyze_function_desc(func, HF_NORMAL);
|
|
|
|
if (PATTERN_is(*JOB->current, RS_AS))
|
|
{
|
|
if (!TRANS_type(TT_NOTHING, &ttyp))
|
|
THROW("Syntax error. Invalid return type");
|
|
func->type = ttyp.type;
|
|
is_proc = FALSE;
|
|
}
|
|
|
|
TYPE_set_kind(&func->type, TK_FUNCTION);
|
|
if (is_static) TYPE_set_flag(&func->type, TF_STATIC);
|
|
if (is_public) TYPE_set_flag(&func->type, TF_PUBLIC);
|
|
|
|
func->fast = is_fast || JOB->class->all_fast;
|
|
if (func->fast)
|
|
JOB->class->has_fast = TRUE;
|
|
|
|
func->unsafe = is_unsafe || JOB->class->all_unsafe;
|
|
|
|
// Check special methods
|
|
|
|
sym = TABLE_get_symbol(JOB->class->table, func->index);
|
|
|
|
if (*sym->name == '_')
|
|
{
|
|
for (hsp = spec; hsp->name; hsp++)
|
|
{
|
|
if (sym->len != strlen(hsp->name))
|
|
continue;
|
|
if (strncmp(sym->name, hsp->name, sym->len))
|
|
continue;
|
|
|
|
if (hsp->flag == HS_ERROR)
|
|
THROW("The special method &1 cannot be implemented", hsp->name);
|
|
|
|
if ((hsp->flag & HS_PUBLIC) && !is_public)
|
|
THROW("The special method &1 must be public", hsp->name);
|
|
|
|
if ((hsp->flag & HS_STATIC) && !is_static)
|
|
THROW("The special method &1 must be static", hsp->name);
|
|
|
|
if ((hsp->flag & HS_DYNAMIC) && is_static)
|
|
THROW("The special method &1 cannot be static", hsp->name);
|
|
|
|
if ((hsp->flag & HS_PROCEDURE) && !is_proc)
|
|
THROW("The special method &1 cannot be a function", hsp->name);
|
|
|
|
if ((hsp->flag & HS_FUNCTION) && is_proc)
|
|
THROW("The special method &1 must be a function", hsp->name);
|
|
|
|
if ((hsp->flag & HS_NOPARAM) && func->nparam > 0)
|
|
THROW("The special method &1 takes no arguments", hsp->name);
|
|
|
|
if (hsp->flag & HS_PUT)
|
|
{
|
|
if (func->nparam < 1)
|
|
THROW("The special method &1 must take at least one argument", hsp->name);
|
|
}
|
|
|
|
if (hsp->flag & HS_UNKNOWN)
|
|
{
|
|
if (func->nparam > 0 || !func->vararg)
|
|
THROW("The special method &1 must take a variable number of arguments only", hsp->name);
|
|
}
|
|
|
|
if (hsp->flag & HS_PROPERTY)
|
|
{
|
|
if (TYPE_get_id(func->type) != T_BOOLEAN)
|
|
THROW("The special method &1 must return a boolean", hsp->name);
|
|
}
|
|
|
|
if (hsp->flag & HS_COMPARE)
|
|
{
|
|
if (func->type.t.id != T_INTEGER)
|
|
THROW("The special method must return an integer");
|
|
if (func->nparam != 1)
|
|
THROW("The special method must take exactly one argument");
|
|
}
|
|
|
|
if (hsp->flag & HS_ATTACH)
|
|
{
|
|
if (func->nparam != 2)
|
|
THROW("The special method must take exactly two arguments");
|
|
if (func->param[0].type.t.id != T_OBJECT || func->param[1].type.t.id != T_STRING)
|
|
THROW("The special method signature is incorrect");
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
// We ignore function body
|
|
|
|
if (!PATTERN_is_newline(*(JOB->current)))
|
|
THROW("Syntax error at function declaration");
|
|
|
|
func->line = PATTERN_index(*(JOB->current)) + 1;
|
|
func->start = JOB->current + 1;
|
|
|
|
look = JOB->current;
|
|
for(;;)
|
|
{
|
|
pat = *look;
|
|
|
|
if (PATTERN_is_newline(pat))
|
|
{
|
|
JOB->line = PATTERN_index(pat) + 1;
|
|
pat = look[1];
|
|
|
|
if (PATTERN_is(pat, RS_END))
|
|
{
|
|
if (PATTERN_is_newline(look[2]))
|
|
{
|
|
look += 2;
|
|
break;
|
|
}
|
|
if (TRANS_is_end_function(is_proc, &look[2]))
|
|
{
|
|
look += 3;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
if (is_proc && PATTERN_is(look[2], RS_FUNCTION))
|
|
THROW(E_EXPECTED, "END SUB");
|
|
else if (!is_proc && PATTERN_is(look[2], RS_SUB))
|
|
THROW(E_EXPECTED, "END FUNCTION");
|
|
}
|
|
}
|
|
else if (UNLIKELY(PATTERN_is_end(pat))) // || PATTERN_is_command(pat)))
|
|
THROW(E_MISSING, "END");
|
|
}
|
|
|
|
look++;
|
|
}
|
|
|
|
JOB->current = look;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
static bool header_inherits(void)
|
|
{
|
|
int index;
|
|
|
|
if (!PATTERN_is(*JOB->current, RS_INHERITS))
|
|
return FALSE;
|
|
|
|
/*{
|
|
if (!(PATTERN_is(JOB->current[0], RS_CLASS)
|
|
&& PATTERN_is(JOB->current[1], RS_INHERITS)))
|
|
return FALSE;
|
|
JOB->current++;
|
|
}*/
|
|
|
|
JOB->current++;
|
|
|
|
if (!PATTERN_is_class(*JOB->current))
|
|
THROW("Syntax error. INHERITS needs a class name");
|
|
|
|
if (JOB->class->parent != NO_SYMBOL)
|
|
THROW("Cannot inherit twice");
|
|
|
|
index = PATTERN_index(*JOB->current);
|
|
|
|
if (strcasecmp(TABLE_get_symbol_name(JOB->class->table, index), JOB->class->name) == 0)
|
|
THROW("Cannot inherit itself");
|
|
|
|
JOB->class->parent = CLASS_add_class(JOB->class, index);
|
|
/*printf("JOB->class->parent = %d\n", JOB->class->parent);*/
|
|
|
|
JOB->current++;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
static bool header_option(void)
|
|
{
|
|
if (TRANS_is(RS_EXPORT))
|
|
{
|
|
JOB->class->exported = TRUE;
|
|
|
|
if (TRANS_is(RS_OPTIONAL))
|
|
JOB->class->optional = TRUE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
if (TRANS_is(RS_CREATE))
|
|
{
|
|
if (PATTERN_is_newline(JOB->current[0]) || PATTERN_is(JOB->current[0], RS_STATIC))
|
|
{
|
|
JOB->class->autocreate = TRUE;
|
|
TRANS_ignore(RS_STATIC);
|
|
return TRUE;
|
|
}
|
|
else if (TRANS_is(RS_PRIVATE))
|
|
{
|
|
JOB->class->nocreate = TRUE;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
if (TRANS_is(RS_FAST))
|
|
{
|
|
JOB->class->all_fast = TRUE;
|
|
JOB->class->has_fast = TRUE;
|
|
|
|
if (TRANS_is(RS_UNSAFE))
|
|
JOB->class->all_unsafe = TRUE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
static bool header_library(void)
|
|
{
|
|
if (!TRANS_is(RS_LIBRARY))
|
|
return FALSE;
|
|
|
|
if (!PATTERN_is_string(*JOB->current))
|
|
THROW("Extern library name must be a string");
|
|
|
|
JOB->default_library = PATTERN_index(*JOB->current);
|
|
JOB->current++;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
static bool header_structure(void)
|
|
{
|
|
PATTERN *look = JOB->current;
|
|
bool is_public;
|
|
CLASS_STRUCT *structure;
|
|
VARIABLE *field;
|
|
TRANS_DECL decl;
|
|
int nfield;
|
|
int index;
|
|
|
|
check_public_private(&look, &is_public);
|
|
|
|
if (!PATTERN_is(*look, RS_STRUCT))
|
|
return FALSE;
|
|
look++;
|
|
JOB->current = look;
|
|
|
|
if (!is_public)
|
|
THROW("Structures must be public");
|
|
|
|
if (!PATTERN_is_identifier(*JOB->current))
|
|
THROW("Syntax error. STRUCT needs an identifier");
|
|
|
|
structure = ARRAY_add_void(&JOB->class->structure);
|
|
ARRAY_create(&structure->field);
|
|
nfield = 0;
|
|
|
|
structure->index = PATTERN_index(*JOB->current);
|
|
index = CLASS_add_class_exported(JOB->class, structure->index);
|
|
JOB->class->class[index].structure = TRUE;
|
|
//fprintf(stderr, "Set structure flag to %s\n", TABLE_get_symbol_name(JOB->class->table, structure->index));
|
|
|
|
//TABLE_copy_symbol_with_prefix(JOB->class->table, structure->index, '.', NULL, &structure->index);
|
|
|
|
JOB->current++;
|
|
TRANS_want_newline();
|
|
|
|
for(;;)
|
|
{
|
|
do
|
|
{
|
|
if (PATTERN_is_end(*JOB->current)) // || PATTERN_is_command(*JOB->current))
|
|
THROW ("Missing END STRUCT");
|
|
}
|
|
while (TRANS_newline());
|
|
|
|
if (PATTERN_is(*JOB->current, RS_END) && PATTERN_is(JOB->current[1], RS_STRUCT))
|
|
{
|
|
if (nfield == 0)
|
|
THROW ("Syntax error. A structure must have one field at least.");
|
|
|
|
JOB->current += 2;
|
|
|
|
TRANS_want_newline();
|
|
break;
|
|
}
|
|
|
|
if (!PATTERN_is_identifier(*JOB->current))
|
|
THROW("Syntax error. The &1 field is not a valid identifier", TRANS_get_num_desc(nfield + 1));
|
|
|
|
field = ARRAY_add(&structure->field);
|
|
field->index = PATTERN_index(*JOB->current);
|
|
|
|
|
|
JOB->current++;
|
|
|
|
CLEAR(&decl);
|
|
if (!TRANS_type(TT_CAN_ARRAY | TT_CAN_EMBED, &decl))
|
|
THROW("Syntax error. Invalid type description of &1 field", TRANS_get_num_desc(nfield + 1));
|
|
|
|
TRANS_want_newline();
|
|
|
|
field->type = decl.type;
|
|
|
|
nfield++;
|
|
}
|
|
|
|
structure->nfield = nfield;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static bool header_use(void)
|
|
{
|
|
if (!TRANS_is(RS_USE))
|
|
return FALSE;
|
|
|
|
CLASS_begin_init_function(JOB->class, FUNC_INIT_STATIC);
|
|
|
|
for(;;)
|
|
{
|
|
if (!PATTERN_is_string(*JOB->current))
|
|
THROW("Component name must be a string");
|
|
|
|
TRANS_string(*JOB->current);
|
|
TRANS_subr(TS_SUBR_USE, 1);
|
|
CODE_drop();
|
|
|
|
JOB->current++;
|
|
|
|
if (!TRANS_is(RS_COMMA))
|
|
break;
|
|
}
|
|
|
|
if (!PATTERN_is_newline(*JOB->current))
|
|
THROW(E_SYNTAX);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
static void check_class_header()
|
|
{
|
|
while (TRUE) //(JOB->current < JOB->end)
|
|
{
|
|
if (PATTERN_is_end(*JOB->current))
|
|
break;
|
|
|
|
if (TRANS_newline())
|
|
continue;
|
|
|
|
if (header_option())
|
|
continue;
|
|
|
|
if (header_inherits())
|
|
continue;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
void HEADER_do(void)
|
|
{
|
|
union {
|
|
TRANS_DECL decl;
|
|
TRANS_FUNC func;
|
|
TRANS_EVENT event;
|
|
TRANS_EXTERN ext;
|
|
TRANS_PROPERTY prop;
|
|
} trans;
|
|
|
|
TRANS_reset();
|
|
|
|
header_module_type();
|
|
|
|
if (JOB->line == 1)
|
|
check_class_header();
|
|
|
|
while (TRUE) //JOB->current < JOB->end)
|
|
{
|
|
if (PATTERN_is_end(*JOB->current))
|
|
break;
|
|
|
|
if (TRANS_newline())
|
|
{
|
|
if (JOB->line == 1)
|
|
check_class_header();
|
|
|
|
continue;
|
|
}
|
|
|
|
if (header_function(&trans.func))
|
|
{
|
|
CLASS_add_function(JOB->class, &trans.func);
|
|
continue;
|
|
}
|
|
|
|
if (header_event(&trans.event))
|
|
{
|
|
CLASS_add_event(JOB->class, &trans.event);
|
|
continue;
|
|
}
|
|
|
|
if (header_property(&trans.prop))
|
|
{
|
|
CLASS_add_property(JOB->class, &trans.prop);
|
|
continue;
|
|
}
|
|
|
|
if (header_extern(&trans.ext))
|
|
{
|
|
CLASS_add_extern(JOB->class, &trans.ext);
|
|
continue;
|
|
}
|
|
|
|
if (header_enumeration(&trans.decl))
|
|
continue;
|
|
|
|
if (header_declaration(&trans.decl))
|
|
{
|
|
CLASS_add_declaration(JOB->class, &trans.decl);
|
|
continue;
|
|
}
|
|
|
|
if (header_structure())
|
|
continue;
|
|
|
|
if (header_class(&trans.decl))
|
|
{
|
|
CLASS_add_class_exported(JOB->class, trans.decl.index);
|
|
continue;
|
|
}
|
|
|
|
if (header_inherits())
|
|
continue;
|
|
|
|
if (header_library())
|
|
continue;
|
|
|
|
if (header_use())
|
|
continue;
|
|
|
|
/*if (PATTERN_is_command(*JOB->current))
|
|
{
|
|
JOB->current++;
|
|
continue;
|
|
}*/
|
|
|
|
THROW_UNEXPECTED(JOB->current);
|
|
}
|
|
|
|
// Sort class declaration to avoid alignment problems.
|
|
// This should be useless now, as it is done again by the interpreter
|
|
// when loading the class.
|
|
|
|
CLASS_sort_declaration(JOB->class);
|
|
|
|
if (JOB->verbose)
|
|
CLASS_dump();
|
|
}
|