mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-07-11 22:03:01 -06:00
Core: CParser LineInfoComment, Skylark: Improved witz error handling
git-svn-id: svn://ultimatepp.org/upp/trunk@7318 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
parent
c1e6bcb309
commit
e7f12ab537
10 changed files with 180 additions and 93 deletions
|
|
@ -88,7 +88,12 @@ public:
|
|||
operator bool() const { return *term; }
|
||||
|
||||
int GetLine() const { return line; }
|
||||
int GetColumn(int tabsize) const;
|
||||
String GetFileName() const { return fn; }
|
||||
|
||||
static String LineInfoComment(const String& filename, int line = 1, int column = 1);
|
||||
String GetLineInfoComment(int tabsize = 4) const;
|
||||
enum { LINEINFO_ESC = '\2' };
|
||||
|
||||
void Set(const char *ptr, const char *fn, int line = 1);
|
||||
void Set(const char *ptr);
|
||||
|
|
|
|||
|
|
@ -2,12 +2,12 @@
|
|||
|
||||
NAMESPACE_UPP
|
||||
|
||||
#define LLOG(x) // LOG(x)
|
||||
#define LLOG(x) // DLOG(x)
|
||||
#define LTIMING(x) // RTIMING(x)
|
||||
|
||||
void CParser::ThrowError(const char *s) {
|
||||
LLOG("CParser::Error: " << s);
|
||||
LLOG(~String(term, min(strlen((const char *)term), 512U)));
|
||||
LLOG(~String(term, min((int)strlen((const char *)term), 512)));
|
||||
Pos pos = GetPos();
|
||||
Error err(fn + Format("(%d,%d): ", line, pos.GetColumn()) + s);
|
||||
// err.term = (const char *)term;
|
||||
|
|
@ -21,6 +21,30 @@ bool CParser::Spaces0() {
|
|||
!(term[0] == '/' && term[1] == '*'))
|
||||
return false;
|
||||
for(;;) {
|
||||
if(*term == LINEINFO_ESC) {
|
||||
term++;
|
||||
fn.Clear();
|
||||
while(*term) {
|
||||
if(*term == LINEINFO_ESC) {
|
||||
++term;
|
||||
break;
|
||||
}
|
||||
if(*term == '\3') {
|
||||
line = atoi(++term);
|
||||
while(*term) {
|
||||
if(*term == LINEINFO_ESC) {
|
||||
++term;
|
||||
break;
|
||||
}
|
||||
term++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
fn.Cat(*term++);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else
|
||||
if(term[0] == '/' && term[1] == '/') {
|
||||
term += 2;
|
||||
while(*term && *term != '\n')
|
||||
|
|
@ -48,6 +72,17 @@ bool CParser::Spaces0() {
|
|||
return true;
|
||||
}
|
||||
|
||||
String CParser::LineInfoComment(const String& file, int line, int column)
|
||||
{
|
||||
return String().Cat() << (char)LINEINFO_ESC << file << '\3'
|
||||
<< line << '\3' << column << (char)LINEINFO_ESC;
|
||||
}
|
||||
|
||||
String CParser::GetLineInfoComment(int tabsize) const
|
||||
{
|
||||
return LineInfoComment(GetFileName(), GetLine(), GetColumn(tabsize));
|
||||
}
|
||||
|
||||
const char *CParser::IsId0(const char *s) const {
|
||||
const char *t = term + 1;
|
||||
s++;
|
||||
|
|
@ -409,6 +444,13 @@ int CParser::Pos::GetColumn(int tabsize) const
|
|||
{
|
||||
int pos = 1;
|
||||
for(const char *s = lineptr; s < ptr; s++) {
|
||||
if(*s == CParser::LINEINFO_ESC) {
|
||||
s++;
|
||||
while(s < ptr && *s != CParser::LINEINFO_ESC)
|
||||
if(*s++ == '\3')
|
||||
pos = atoi(s);
|
||||
}
|
||||
else
|
||||
if(*s == '\t')
|
||||
pos = (pos + tabsize - 1) / tabsize * tabsize + 1;
|
||||
else
|
||||
|
|
@ -417,8 +459,14 @@ int CParser::Pos::GetColumn(int tabsize) const
|
|||
return pos;
|
||||
}
|
||||
|
||||
int CParser::GetColumn(int tabsize) const
|
||||
{
|
||||
return GetPos().GetColumn(tabsize);
|
||||
}
|
||||
|
||||
void CParser::SetPos(const CParser::Pos& p)
|
||||
{
|
||||
LLOG("SetPos " << p.fn << ":" << p.line);
|
||||
line = p.line;
|
||||
fn = p.fn;
|
||||
term = p.ptr;
|
||||
|
|
@ -459,6 +507,7 @@ void CParser::Set(const char *_ptr, const char *_fn, int _line)
|
|||
line = _line;
|
||||
skipspaces = true;
|
||||
Spaces();
|
||||
LLOG("Set " << fn << ":" << line);
|
||||
}
|
||||
|
||||
void CParser::Set(const char *_ptr)
|
||||
|
|
|
|||
|
|
@ -366,12 +366,37 @@ a different [* CParser].&]
|
|||
[s2; Returns the current line number.&]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:CParser`:`:GetColumn`(int`)const: [@(0.0.255) int]_[* GetColumn]([@(0.0.255) int]_[*@3 t
|
||||
absize])_[@(0.0.255) const]&]
|
||||
[s2;%% Returns the current column, with given [%-*@3 tabsize].&]
|
||||
[s3;%% &]
|
||||
[s4; &]
|
||||
[s5;:CParser`:`:GetFileName`(`)const: [_^String^ String]_[* GetFileName]()_[@(0.0.255) cons
|
||||
t]&]
|
||||
[s2; Returns the actual filename.&]
|
||||
[s3;%% &]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:CParser`:`:LineInfoComment`(const String`&`,int`,int`): [@(0.0.255) static]
|
||||
[_^String^ String]_[* LineInfoComment]([@(0.0.255) const]_[_^String^ String][@(0.0.255) `&]_
|
||||
[*@3 filename], [@(0.0.255) int]_[*@3 line]_`=_[@3 1], [@(0.0.255) int]_[*@3 column]_`=_[@3 1])
|
||||
&]
|
||||
[s2;%% This function creates a special comment that when parsed by
|
||||
CParser, switches filename and line number. This is supposed
|
||||
to help in situations when parsed text is actually a result of
|
||||
e.g. include operations of some original files, to improve error
|
||||
reporting. Not that such comment is lexically treated as comment.
|
||||
Comment is created using LINEINFO`_ESC characters begin/end delimiter
|
||||
(current value is `'`\2`').&]
|
||||
[s3;%% &]
|
||||
[s4; &]
|
||||
[s5;:CParser`:`:GetLineInfoComment`(int`)const: [_^String^ String]_[* GetLineInfoComment](
|
||||
[@(0.0.255) int]_[*@3 tabsize]_`=_[@3 4])_[@(0.0.255) const]&]
|
||||
[s2;%% Calls LineInfoComment(GetFileName(), GetLine(), GetColumn([%-*@3 tabsize]))
|
||||
`- creates a comment to identify current file position in further
|
||||
processing.&]
|
||||
[s3; &]
|
||||
[s4; &]
|
||||
[s5;:CParser`:`:Set`(const char`*`,const char`*`,int`): [@(0.0.255) void]_[* Set]([@(0.0.255) c
|
||||
onst]_[@(0.0.255) char]_`*[*@3 ptr], [@(0.0.255) const]_[@(0.0.255) char]_`*[*@3 fn],
|
||||
[@(0.0.255) int]_[*@3 line]_`=_[@3 1])&]
|
||||
|
|
@ -478,10 +503,9 @@ at the beginning of the line when the line length is exceeded.&]
|
|||
[s0;~~~1408;%% -|ASCSTRING`_SMART-|breaks string into lines when too
|
||||
long&]
|
||||
[s0;~~~1408;%% -|ASCSTRING`_OCTALHI-|escapes characters >128&]
|
||||
[s0;~~~1408;%% -|ASCSTRING`_JSON-|uses JSON notation for escapes (`\u0001
|
||||
-| instead of `\001)&]
|
||||
[s0;~~~1408;%% -|ASCSTRING`_JSON-|uses JSON notation for escapes &]
|
||||
[s0;~~~1408;%% -|(`\u0001 instead of `\001)&]
|
||||
[s0;~~~1408;%% &]
|
||||
[s0;%% &]
|
||||
[s7;%% [*/ Return value]-|C`-like literal.&]
|
||||
[s3;%% &]
|
||||
[s4; &]
|
||||
|
|
|
|||
|
|
@ -345,7 +345,14 @@ void Compiler::ExeBlock::AddText(const char *b, const char *s)
|
|||
{
|
||||
if(s > b) {
|
||||
RawHtmlText t;
|
||||
t.text = String(b, s);
|
||||
while(b < s) {
|
||||
if(*b == CParser::LINEINFO_ESC) {
|
||||
b++;
|
||||
while(b < s && *b++ != CParser::LINEINFO_ESC);
|
||||
}
|
||||
else
|
||||
t.text.Cat(*b++);
|
||||
}
|
||||
item.Add().Create<ExeConst>().value = RawToValue(t);
|
||||
}
|
||||
}
|
||||
|
|
@ -354,65 +361,66 @@ One<Exe> Compiler::Block()
|
|||
{
|
||||
One<Exe> result;
|
||||
ExeBlock& blk = result.Create<ExeBlock>();
|
||||
const char *s = p.GetSpacePtr();
|
||||
const char *b = s;
|
||||
int line = p.GetLine();
|
||||
while(*s) {
|
||||
if(*s == '$') {
|
||||
if(s[1] == '$') {
|
||||
blk.AddText(b, s + 1);
|
||||
p.Set(s + 2, NULL, line);
|
||||
b = s = p.GetSpacePtr();
|
||||
}
|
||||
else {
|
||||
blk.AddText(b, s);
|
||||
p.Set(s + 1, NULL, line);
|
||||
if(p.Id("if")) {
|
||||
ExeCond& c = blk.item.Add().Create<ExeCond>();
|
||||
p.PassChar('(');
|
||||
c.cond = Exp();
|
||||
p.PassChar(')');
|
||||
c.ontrue = Block();
|
||||
if(p.Id("else"))
|
||||
c.onfalse = Block();
|
||||
if(!p.Char('/'))
|
||||
p.PassId("endif");
|
||||
}
|
||||
else
|
||||
if(p.Id("for")) {
|
||||
ExeFor& c = blk.item.Add().Create<ExeFor>();
|
||||
p.PassChar('(');
|
||||
int q = var.GetCount();
|
||||
var.Add(p.ReadId());
|
||||
var.Add(Null); // LoopInfo placeholder
|
||||
forvar.Add(true);
|
||||
forvar.Add(true);
|
||||
p.PassId("in");
|
||||
c.value = Exp();
|
||||
p.PassChar(')');
|
||||
c.body = Block();
|
||||
var.Trim(q);
|
||||
forvar.SetCount(q);
|
||||
if(p.Id("else"))
|
||||
c.onempty = Block();
|
||||
if(!p.Char('/'))
|
||||
p.PassId("endfor");
|
||||
}
|
||||
else
|
||||
if(p.IsId("else") || p.IsId("endif") || p.IsId("endfor") || p.IsChar('/'))
|
||||
return result;
|
||||
else
|
||||
blk.item.AddPick(Prim());
|
||||
b = s = p.GetSpacePtr();
|
||||
line = p.GetLine();
|
||||
}
|
||||
const char *b = p.GetSpacePtr();
|
||||
while(!p.IsEof()) {
|
||||
const char *s = p.GetPtr();
|
||||
if(p.Char2('$', '$')) {
|
||||
blk.AddText(b, s + 1);
|
||||
b = p.GetSpacePtr();
|
||||
}
|
||||
else
|
||||
if(*s++ == '\n')
|
||||
line++;
|
||||
if(p.Char('$')) {
|
||||
blk.AddText(b, s);
|
||||
if(p.Id("if")) {
|
||||
ExeCond& c = blk.item.Add().Create<ExeCond>();
|
||||
p.PassChar('(');
|
||||
c.cond = Exp();
|
||||
p.PassChar(')');
|
||||
c.ontrue = Block();
|
||||
if(p.Id("else"))
|
||||
c.onfalse = Block();
|
||||
if(!p.Char('/'))
|
||||
p.PassId("endif");
|
||||
}
|
||||
else
|
||||
if(p.Id("for")) {
|
||||
ExeFor& c = blk.item.Add().Create<ExeFor>();
|
||||
p.PassChar('(');
|
||||
int q = var.GetCount();
|
||||
var.Add(p.ReadId());
|
||||
var.Add(Null); // LoopInfo placeholder
|
||||
forvar.Add(true);
|
||||
forvar.Add(true);
|
||||
p.PassId("in");
|
||||
c.value = Exp();
|
||||
p.PassChar(')');
|
||||
c.body = Block();
|
||||
var.Trim(q);
|
||||
forvar.SetCount(q);
|
||||
if(p.Id("else"))
|
||||
c.onempty = Block();
|
||||
if(!p.Char('/'))
|
||||
p.PassId("endfor");
|
||||
}
|
||||
else
|
||||
if(p.IsId("else") || p.IsId("endif") || p.IsId("endfor") || p.IsChar('/'))
|
||||
return result;
|
||||
else
|
||||
blk.item.AddPick(Prim());
|
||||
b = p.GetSpacePtr();
|
||||
}
|
||||
else {
|
||||
// We need to advance CParser, but SkipTerm is not good, because '$' can be in quoites - "$x"
|
||||
// We also need CParser to process whitespaces to allow for correct lineinfo processing
|
||||
CParser::Pos pos = p.GetPos();
|
||||
pos.ptr++;
|
||||
const char *s = p.GetPtr();
|
||||
while((byte)*s > ' ' && *s != '$')
|
||||
s++;
|
||||
p.SetPos(pos);
|
||||
}
|
||||
}
|
||||
blk.AddText(b, s);
|
||||
p.Set(s, NULL, line);
|
||||
blk.AddText(b, p.GetPtr());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -418,18 +418,17 @@ void Http::Dispatch(TcpSocket& socket)
|
|||
socket.WhenWait = callback2(this, &Http::WaitHandler, bd.progress, rsocket);
|
||||
}
|
||||
content = socket.GetAll(len);
|
||||
if(bd.progress)
|
||||
{
|
||||
if(bd.progress) {
|
||||
socket.WhenWait.Clear();
|
||||
(*bd.progress)(PROGRESS_END, *this, len);
|
||||
}
|
||||
if(post)
|
||||
if(post) {
|
||||
if(rc.StartsWith("application/x-www-form-urlencoded"))
|
||||
ParseRequest(content);
|
||||
else
|
||||
if(rc.StartsWith("multipart/"))
|
||||
ReadMultiPart(content);
|
||||
|
||||
}
|
||||
response.Clear();
|
||||
if(bd.handler) {
|
||||
if(post && !bd.post_raw) {
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ void Http::ParseRequest(const char *p)
|
|||
last = p;
|
||||
while(*p && *p != '&')
|
||||
p++;
|
||||
if(*key != '.' && *key != '@')
|
||||
if(*key != '.' && *key != '@') {
|
||||
if(key.EndsWith("[]")) {
|
||||
Value &v = var.GetAdd(key);
|
||||
if(v.IsNull())
|
||||
|
|
@ -45,6 +45,7 @@ void Http::ParseRequest(const char *p)
|
|||
}
|
||||
else
|
||||
var.GetAdd(key) = UrlDecode(last, p);
|
||||
}
|
||||
if(*p)
|
||||
p++;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,8 +28,10 @@ String LoadTemplate(const char *file, const String& search_path, int lang)
|
|||
SKYLARKLOG("Loading template file " << path);
|
||||
FileIn in(path);
|
||||
String r;
|
||||
int lineno = 0;
|
||||
while(in && !in.IsEof()) {
|
||||
String line = in.GetLine();
|
||||
lineno++;
|
||||
CParser p(line);
|
||||
if(p.Char('#') && p.Id("include")) {
|
||||
String file = p.GetPtr();
|
||||
|
|
@ -41,7 +43,7 @@ String LoadTemplate(const char *file, const String& search_path, int lang)
|
|||
r << LoadTemplate(file, GetFileFolder(path) + ';' + search_path, lang);
|
||||
}
|
||||
else
|
||||
r << line;
|
||||
r << CParser::LineInfoComment(path, lineno) << line;
|
||||
r << "\n";
|
||||
}
|
||||
return r;
|
||||
|
|
@ -62,7 +64,7 @@ VectorMap<String, String> GetTemplateDefs(const char *file, int lang)
|
|||
id = p.ReadId();
|
||||
ti = def.FindAdd(id);
|
||||
def[ti].Clear();
|
||||
def[ti] << p.GetPtr();
|
||||
def[ti] << p.GetLineInfoComment() << p.GetPtr();
|
||||
}
|
||||
else
|
||||
def[ti] << line << "\n";
|
||||
|
|
|
|||
|
|
@ -61,33 +61,32 @@ ArrayMap<String, One<Exe> > template_cache;
|
|||
|
||||
const One<Exe>& Renderer::GetTemplate(const char *template_name)
|
||||
{
|
||||
LTIMING("GetTemplate");
|
||||
StringBuffer s;
|
||||
{
|
||||
LTIMING("MakeSignature");
|
||||
for(int i = 0; i < var.GetCount(); i++)
|
||||
s << var.GetKey(i) << ';';
|
||||
s << ':' << template_name;
|
||||
}
|
||||
if(!SkylarkApp::Config().use_caching) // Templates get overwritten is not cached, MT hazard
|
||||
s << ';' << Thread::GetCurrentId();
|
||||
String sgn = s;
|
||||
LLOG("Trying to retrieve " << sgn << " from cache");
|
||||
Mutex::Lock __(template_cache_lock);
|
||||
int q = template_cache.Find(sgn);
|
||||
if(q >= 0 && SkylarkApp::Config().use_caching)
|
||||
return template_cache[q];
|
||||
One<Exe>& exe = q >= 0 ? template_cache[q] : template_cache.Add(sgn);
|
||||
try {
|
||||
LTIMING("GetTemplate");
|
||||
StringBuffer s;
|
||||
{
|
||||
LTIMING("MakeSignature");
|
||||
for(int i = 0; i < var.GetCount(); i++)
|
||||
s << var.GetKey(i) << ';';
|
||||
s << ':' << template_name;
|
||||
}
|
||||
if(!SkylarkApp::Config().use_caching) // Templates get overwritten is not cached, MT hazard
|
||||
s << ';' << Thread::GetCurrentId();
|
||||
String sgn = s;
|
||||
LLOG("Trying to retrieve " << sgn << " from cache");
|
||||
Mutex::Lock __(template_cache_lock);
|
||||
int q = template_cache.Find(sgn);
|
||||
if(q >= 0 && SkylarkApp::Config().use_caching)
|
||||
return template_cache[q];
|
||||
LLOG("About to compile: " << sgn);
|
||||
LTIMING("Compile");
|
||||
One<Exe>& exe = q >= 0 ? template_cache[q] : template_cache.Add(sgn);
|
||||
exe = Compile(GetPreprocessedTemplate(template_name, lang), var.GetIndex());
|
||||
return exe;
|
||||
}
|
||||
catch(CParser::Error e)
|
||||
{
|
||||
throw TemplateExc(e);
|
||||
catch(CParser::Error e) {
|
||||
exe = Compile(String().Cat() << "<html><body>Error in template: " << e << "</body></html>", var.GetIndex());
|
||||
}
|
||||
return exe;
|
||||
NEVER();
|
||||
return template_cache[0];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
#ifndef _Skylark_icpp_init_stub
|
||||
#define _Skylark_icpp_init_stub
|
||||
#include "Sql/init"
|
||||
#define BLITZ_INDEX__ Fdc34a156e19f70e79e3af4bc5aee3879
|
||||
#define BLITZ_INDEX__ F99b1b565e5194ee2f9bb1998be2e6f71
|
||||
#include "StdLib.icpp"
|
||||
#undef BLITZ_INDEX__
|
||||
#define BLITZ_INDEX__ F4f56e545eab9f60b3cd674a218cc0915
|
||||
#define BLITZ_INDEX__ Fadc563b9c69ab7173de2094508da8708
|
||||
#include "Static.icpp"
|
||||
#undef BLITZ_INDEX__
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ specific version of template first, then defaults to common version.&]
|
|||
[s0; [@5 #define] [/ id]&]
|
||||
[s0; &]
|
||||
[s0; This starts a new template subblock which ends with another
|
||||
subblock. First subblock (the one befure first #define is encountered)
|
||||
subblock. First subblock (the one before first #define is encountered)
|
||||
has [/ id] `"MAIN`". The value of `"MAIN`" subblock represents
|
||||
the template at the end of preprocessing process.&]
|
||||
[s0; &]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue