commit x64 compilation from lulu cause the other branch dont seems to compile properly at home
This commit is contained in:
266
include/modules/script_squirrel/squirrel_analyzer.cpp
Normal file
266
include/modules/script_squirrel/squirrel_analyzer.cpp
Normal file
@ -0,0 +1,266 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "script_squirrel/squirrel_analyzer.h"
|
||||
#include "ascii/parser.h"
|
||||
#include "filesystem/filesystem.h"
|
||||
#include "platform.h"
|
||||
|
||||
using namespace GS;
|
||||
using namespace GS::SquirrelAnalyzer;
|
||||
using namespace GS::AsciiParser;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/* static bool SymbolFindByNameFunctor(Symbol *s, const char *n) { return s->name == n; } */
|
||||
static bool SourceFindByNameFunctor(Source *s, const char *n) { return s->name == n; }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
struct ParserContext
|
||||
{
|
||||
const char *s, *e, *o;
|
||||
SharedList <Symbol *> *symbols;
|
||||
Symbol::Type type;
|
||||
|
||||
Offset CurrentOffset() const
|
||||
{
|
||||
Offset offset(1, 0);
|
||||
for (const char *p = o; p < e; ++offset.line)
|
||||
{
|
||||
const char *eol = RunToEOL(p, e);
|
||||
|
||||
if (eol > s)
|
||||
{
|
||||
offset.column = s - p;
|
||||
break;
|
||||
}
|
||||
if (eol >= e)
|
||||
return Offset(1, 0);
|
||||
|
||||
p = SkipEOL(eol, e);
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
ParserContext(const char *_s, const char *_e, const char *_o, SharedList <Symbol *> *_symbols, Symbol::Type _type) : s(_s), e(_e), o(_o), symbols(_symbols), type(_type) {}
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void ParseContext(ParserContext &);
|
||||
bool ParseMemberVariable(ParserContext &ctx)
|
||||
{
|
||||
AutoPtr <Variable> _var(new Variable);
|
||||
_var->offset = ctx.CurrentOffset();
|
||||
_var->var_type = Variable::VarMember;
|
||||
|
||||
const char *e = SkipEntry(ctx.s, ctx.e);
|
||||
_var->name.Set(ctx.s, e);
|
||||
|
||||
ctx.s = NextEntry(ctx.s, ctx.e) + 1;
|
||||
ctx.symbols->Add(_var.Detach());
|
||||
return true;
|
||||
}
|
||||
bool ParseGlobalVariable(ParserContext &ctx)
|
||||
{
|
||||
AutoPtr <Variable> _var(new Variable);
|
||||
_var->offset = ctx.CurrentOffset();
|
||||
_var->var_type = Variable::VarGlobal;
|
||||
|
||||
const char *e = SkipEntry(ctx.s, ctx.e);
|
||||
_var->name.Set(ctx.s, e);
|
||||
|
||||
ctx.s = NextEntry(ctx.s, ctx.e) + 2;
|
||||
ctx.symbols->Add(_var.Detach());
|
||||
return true;
|
||||
}
|
||||
bool ParseLocalVariable(ParserContext &ctx)
|
||||
{
|
||||
AutoPtr <Variable> _var(new Variable);
|
||||
_var->offset = ctx.CurrentOffset();
|
||||
_var->var_type = Variable::VarLocal;
|
||||
|
||||
const char *s = NextEntry(ctx.s, ctx.e);
|
||||
_var->name.Set(s, SkipEntry(s, ctx.e));
|
||||
ctx.symbols->Add(_var.Detach());
|
||||
|
||||
// parse subsequent declarations.
|
||||
s = NextEntry(s, ctx.e);
|
||||
|
||||
forever
|
||||
{
|
||||
/*
|
||||
// TODO a naive test won't do as there is no mandatory end-of-statement in Squirrel
|
||||
if (s[0] == '=')
|
||||
{
|
||||
// check if there are more variables declared by this statement
|
||||
}
|
||||
*/
|
||||
if (s[0] == ',')
|
||||
{
|
||||
s = NextEntry(s + 1, ctx.e);
|
||||
ctx.s = s;
|
||||
|
||||
_var = new Variable;
|
||||
_var->offset = ctx.CurrentOffset();
|
||||
_var->var_type = Variable::VarLocal;
|
||||
|
||||
_var->name.Set(s, SkipEntry(s, ctx.e));
|
||||
ctx.symbols->Add(_var.Detach());
|
||||
|
||||
s = NextEntry(s, ctx.e);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
ctx.s = s;
|
||||
return true;
|
||||
}
|
||||
bool ParseFunction(ParserContext &ctx)
|
||||
{
|
||||
AutoPtr <Function> _function(new Function);
|
||||
_function->offset = ctx.CurrentOffset();
|
||||
|
||||
const char *s = NextEntry(ctx.s, ctx.e);
|
||||
_function->name.Set(s, SkipEntry(s, ctx.e));
|
||||
|
||||
s = NextEntry(s, ctx.e);
|
||||
|
||||
// Parse prototype.
|
||||
if (s[0] != '(')
|
||||
return false;
|
||||
|
||||
const char *eoproto = RunToEOG(s, ctx.e, '(', ')');
|
||||
if (eoproto == NULL)
|
||||
return false;
|
||||
|
||||
_function->prototype.Set(s + 1, eoproto);
|
||||
s = NextEntry(eoproto + 1, ctx.e);
|
||||
|
||||
// Parse function content.
|
||||
if (s[0] != '{')
|
||||
return false;
|
||||
|
||||
const char *eofunc = RunToEOG(s, ctx.e, '{', '}');
|
||||
if (eofunc == NULL)
|
||||
eofunc = ctx.e;
|
||||
ParserContext func_ctx(s + 1, eofunc, ctx.o, &_function->symbols, _function->type);
|
||||
|
||||
ParseContext(func_ctx);
|
||||
|
||||
ctx.s = eofunc + 1;
|
||||
ctx.symbols->Add(_function.Detach());
|
||||
return true;
|
||||
}
|
||||
bool ParseClass(ParserContext &ctx)
|
||||
{
|
||||
AutoPtr <Class> _class(new Class);
|
||||
_class->offset = ctx.CurrentOffset();
|
||||
|
||||
ctx.s = NextEntry(ctx.s, ctx.e);
|
||||
_class->name.Set(ctx.s, SkipEntry(ctx.s, ctx.e));
|
||||
|
||||
const char *s = NextEntry(ctx.s, ctx.e);
|
||||
|
||||
if (!String::strccmp("extends", s))
|
||||
{
|
||||
s = NextEntry(s, ctx.e);
|
||||
_class->extends.Set(s, SkipEntry(s, ctx.e));
|
||||
|
||||
ctx.s = SkipEntry(s, ctx.e);
|
||||
|
||||
s = NextEntry(s, ctx.e);
|
||||
if (s == ctx.e)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Parse class content.
|
||||
if (s[0] != '{')
|
||||
return false;
|
||||
|
||||
const char *eoclass = RunToEOG(s, ctx.e, '{', '}');
|
||||
if (eoclass == NULL)
|
||||
eoclass = ctx.e;
|
||||
|
||||
ParserContext class_ctx(s + 1, eoclass, ctx.o, &_class->symbols, _class->type);
|
||||
ParseContext(class_ctx);
|
||||
|
||||
ctx.s = eoclass + 1;
|
||||
ctx.symbols->Add(_class.Detach());
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void ParseContext(ParserContext &ctx)
|
||||
{
|
||||
for (bool r = true; r && (ctx.s < ctx.e); )
|
||||
{
|
||||
if (!String::strccmp("class", ctx.s))
|
||||
r = ParseClass(ctx);
|
||||
else if (!String::strccmp("function", ctx.s))
|
||||
r = ParseFunction(ctx);
|
||||
else if (!String::strccmp("local", ctx.s))
|
||||
r = ParseLocalVariable(ctx);
|
||||
else
|
||||
{
|
||||
const char *e = SkipEntry(ctx.s, ctx.e);
|
||||
String tmp(ctx.s, e);
|
||||
|
||||
const char *s = NextEntry(ctx.s, ctx.e);
|
||||
if (ctx.s == s)
|
||||
++ctx.s; // skip
|
||||
else
|
||||
{
|
||||
if ((s[0] == '<') && (s[1] == '-'))
|
||||
r = ParseGlobalVariable(ctx);
|
||||
else if ((ctx.type == Symbol::TypeClass) && (s[0] == '='))
|
||||
r = ParseMemberVariable(ctx);
|
||||
else
|
||||
ctx.s = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Source *ParseSource(const char *s, const char *e)
|
||||
{
|
||||
AutoPtr <Source> source(new Source);
|
||||
|
||||
ParserContext ctx(s, e, s, &source->symbols, Symbol::TypeNone);
|
||||
ParseContext(ctx);
|
||||
|
||||
return source.Detach();
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Source *SquirrelAnalyzer::Analyze(const char *nut, Program &program, bool replace)
|
||||
{
|
||||
Source *old_source = ListFindEx(program.sources, SourceFindByNameFunctor, nut);
|
||||
if (old_source && !replace)
|
||||
return NULL;
|
||||
|
||||
String source;
|
||||
{
|
||||
Array <char> buffer;
|
||||
if (!Platform::Get().io->FileLoad(nut, buffer))
|
||||
return NULL;
|
||||
source.Set(buffer.c_ptr(), buffer.c_ptr() + buffer.GetCount());
|
||||
}
|
||||
|
||||
Source *new_source = ParseSource(source.c_str(), source.c_str() + source.Len());
|
||||
if (!new_source)
|
||||
return NULL;
|
||||
|
||||
new_source->name = nut;
|
||||
|
||||
program.sources.Remove(old_source);
|
||||
program.sources.Add(new_source);
|
||||
return new_source;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
Reference in New Issue
Block a user