Skip to content

Commit 958f162

Browse files
committed
[oslcomp] Reworked source location to include column numbers
and track begin/end pairs. Introduce OSL::pvt::SrcLoc to track this and percolate throughout the source Signed-off-by: Luca Fascione <lfascione@nvidia.com>
1 parent 532053e commit 958f162

File tree

11 files changed

+553
-366
lines changed

11 files changed

+553
-366
lines changed

src/include/osl_pvt.h

Lines changed: 113 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,111 @@ namespace pvt {
1515
class ASTNode;
1616
class StructSpec;
1717

18+
/// A location in the OSL source
19+
/// Conversions from the FLEX/Bison convention happens in from_yyloc()
20+
/// It's tempting to make this class also track the straight byte-offset
21+
/// in the file, which would help us when we print out errors, code in the
22+
/// OSO's and whathaveyou. But the action of the preprocessor kills our
23+
/// ability to do so, as the parser doesn't ever see the user's version
24+
/// of the source
25+
struct SrcLoc {
26+
static const uint32_t kUnknown { uint32_t(-1) };
27+
28+
ustring filename;
29+
// this storage asymmetry is weird, but it's what you want:
30+
// the column markers work like a normal STL [begin, end) span,
31+
// but the line markers are actually [start, stop] because they
32+
// need to say on which line the non-inclusive `column_end` side is
33+
uint32_t line_start = kUnknown; ///< start line number, 0-based, inclusive
34+
uint32_t column_begin
35+
= kUnknown; ///< start col number, 0-based, [begin, end)-style like the STL
36+
uint32_t line_stop = kUnknown; ///< finish line number, 0-based, inclusive
37+
uint32_t column_end
38+
= kUnknown; ///< finish col number, 0-based, [begin, end)-style like the STL
39+
40+
SrcLoc() = default;
41+
42+
SrcLoc(ustring filename, int first_line, int first_column, int last_line, int last_column) :
43+
filename(filename)
44+
{
45+
from_yyloc(first_line, first_column, last_line, last_column);
46+
}
47+
48+
explicit operator bool() const { return !filename.empty(); }
49+
50+
/// Convert the classic/built-in representation of a YYLTYPE
51+
/// to our convention
52+
void from_yyloc(int first_line, int first_column, int last_line,
53+
int last_column)
54+
{
55+
// we go from 1-based to 0-based
56+
line_start = first_line ? first_line - 1 : kUnknown;
57+
column_begin = first_column ? first_column - 1 : kUnknown;
58+
line_stop = last_line ? last_line - 1 : kUnknown;
59+
column_end = last_column ? last_column - 1 : kUnknown;
60+
}
61+
62+
bool operator==(const SrcLoc& other) const
63+
{
64+
return line_start == other.line_start
65+
&& column_begin == other.column_begin
66+
&& line_stop == other.line_stop
67+
&& column_end == other.column_end;
68+
}
69+
70+
bool operator!=(const SrcLoc& other) const { return !(*this == other); }
71+
72+
/// Operator < compares the start locations only.
73+
/// This is what you want, trust me
74+
bool operator<(const SrcLoc& other) const
75+
{
76+
return line_start < other.line_start
77+
|| (line_start == other.line_start
78+
&& column_begin < other.column_begin);
79+
}
80+
81+
/// How many lines spanned by this token.
82+
/// Unlike colcount(), which needs care to be used, this is always correct.
83+
/// Also, unlike colcount(), this is probably nowhere near as useful
84+
size_t linecount() const { return line_stop - line_start + 1; }
85+
86+
/// How many columns spanned by this token.
87+
/// N.B. This needs to be used with care: first off it is only ever a correct
88+
/// notion when first_lineno() == last_lineno(), because we don't know how
89+
/// long lines are. Further, the parser counts all whitespace as _one_ character
90+
/// so '\t' counts as one, not 8 (or 4, or whatever your terminal is set to)
91+
size_t colcount() const { return column_end - column_begin; }
92+
93+
/// Line number, 1-based, for humans, first line of the location span, inclusive
94+
int first_lineno() const { return line_start + 1; }
95+
96+
/// Column number, 1-based, for humans, first line of the location span, inclusive
97+
int first_colno() const { return column_begin + 1; }
98+
99+
/// Line number, 1-based, for humans, last line of the location span, inclusive
100+
int last_lineno() const { return line_stop + 1; }
101+
102+
/// Column number, 1-based, for humans, last character of the location span, inclusive
103+
// (because of our internal representation this does not need a "+1")
104+
int last_colno() const { return column_end; }
105+
106+
// see also fmt::formatter at the end of the file
107+
friend std::ostream& operator<<(std::ostream& out, const SrcLoc& sl)
108+
{
109+
if (sl.column_begin != kUnknown)
110+
return out << fmtformat("{}:{}:{}", sl.filename, sl.last_lineno(),
111+
sl.last_colno());
112+
else if (sl.line_start != kUnknown)
113+
return out << fmtformat("{}:{}", sl.filename, sl.last_lineno());
114+
else if (!sl.filename.empty())
115+
return out << fmtformat("{}", sl.filename);
116+
117+
// if there is no filename we print nothing
118+
return out;
119+
}
120+
};
121+
122+
18123

19124
/// Kinds of shaders
20125
///
@@ -937,7 +1042,7 @@ typedef std::vector<Symbol*> SymbolPtrVec;
9371042
class Opcode {
9381043
public:
9391044
Opcode(ustring op, ustring method, size_t firstarg = 0, size_t nargs = 0)
940-
: m_firstarg((int)firstarg), m_method(method), m_sourceline(0)
1045+
: m_firstarg((int)firstarg), m_method(method)
9411046
{
9421047
reset(op, nargs); // does most of the heavy lifting
9431048
}
@@ -959,13 +1064,11 @@ class Opcode {
9591064
int nargs() const { return m_nargs; }
9601065
ustring method() const { return m_method; }
9611066
void method(ustring method) { m_method = method; }
962-
void source(ustring sourcefile, int sourceline)
963-
{
964-
m_sourcefile = sourcefile;
965-
m_sourceline = sourceline;
966-
}
967-
ustring sourcefile() const { return m_sourcefile; }
968-
int sourceline() const { return m_sourceline; }
1067+
void source(const SrcLoc& srcloc) { m_srcloc = srcloc; }
1068+
ustring sourcefile() const { return m_srcloc.filename; }
1069+
const SrcLoc& srcloc() const { return m_srcloc; }
1070+
// removeme
1071+
int sourceline() const { return m_srcloc.first_lineno(); }
9691072

9701073
void set_args(size_t firstarg, size_t nargs)
9711074
{
@@ -1131,8 +1234,7 @@ class Opcode {
11311234
int m_nargs; ///< Total number of arguments
11321235
ustring m_method; ///< Which param or method this code is for
11331236
int m_jump[max_jumps]; ///< Jump addresses (-1 means none)
1134-
ustring m_sourcefile; ///< Source filename for this op
1135-
int m_sourceline; ///< Line of source code for this op
1237+
SrcLoc m_srcloc; ///< Location in source code for this op
11361238
unsigned int m_argread; ///< Bit field - which args are read
11371239
unsigned int m_argwrite; ///< Bit field - which args are written
11381240
unsigned int m_argtakesderivs; ///< Bit field - which args take derivs
@@ -1172,5 +1274,6 @@ OSL_NAMESPACE_END
11721274
#if FMT_VERSION >= 100000
11731275
FMT_BEGIN_NAMESPACE
11741276
template<> struct formatter<OSL::pvt::TypeSpec> : ostream_formatter {};
1277+
template<> struct formatter<OSL::pvt::SrcLoc> : ostream_formatter {};
11751278
FMT_END_NAMESPACE
11761279
#endif

src/liboslcomp/ast.cpp

Lines changed: 29 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,7 @@ reverse(ASTNode::ref list)
7171
ASTNode::ASTNode(NodeType nodetype, OSLCompilerImpl* compiler)
7272
: m_nodetype(nodetype)
7373
, m_compiler(compiler)
74-
, m_sourcefile(compiler->filename())
75-
, m_sourceline(compiler->lineno())
74+
, m_srcloc(compiler->srcloc())
7675
, m_op(0)
7776
, m_is_lvalue(false)
7877
{
@@ -88,8 +87,7 @@ ASTNode::ASTNode(NodeType nodetype, OSLCompilerImpl* compiler, int op,
8887
ASTNode* a)
8988
: m_nodetype(nodetype)
9089
, m_compiler(compiler)
91-
, m_sourcefile(compiler->filename())
92-
, m_sourceline(compiler->lineno())
90+
, m_srcloc(compiler->srcloc())
9391
, m_op(op)
9492
, m_is_lvalue(false)
9593
{
@@ -105,8 +103,7 @@ ASTNode::ASTNode(NodeType nodetype, OSLCompilerImpl* compiler, int op,
105103
ASTNode::ASTNode(NodeType nodetype, OSLCompilerImpl* compiler, int op)
106104
: m_nodetype(nodetype)
107105
, m_compiler(compiler)
108-
, m_sourcefile(compiler->filename())
109-
, m_sourceline(compiler->lineno())
106+
, m_srcloc(compiler->srcloc())
110107
, m_op(op)
111108
, m_is_lvalue(false)
112109
{
@@ -122,8 +119,7 @@ ASTNode::ASTNode(NodeType nodetype, OSLCompilerImpl* compiler, int op,
122119
ASTNode* a, ASTNode* b)
123120
: m_nodetype(nodetype)
124121
, m_compiler(compiler)
125-
, m_sourcefile(compiler->filename())
126-
, m_sourceline(compiler->lineno())
122+
, m_srcloc(compiler->srcloc())
127123
, m_op(op)
128124
, m_is_lvalue(false)
129125
{
@@ -141,8 +137,7 @@ ASTNode::ASTNode(NodeType nodetype, OSLCompilerImpl* compiler, int op,
141137
ASTNode* a, ASTNode* b, ASTNode* c)
142138
: m_nodetype(nodetype)
143139
, m_compiler(compiler)
144-
, m_sourcefile(compiler->filename())
145-
, m_sourceline(compiler->lineno())
140+
, m_srcloc(compiler->srcloc())
146141
, m_op(op)
147142
, m_is_lvalue(false)
148143
{
@@ -161,8 +156,7 @@ ASTNode::ASTNode(NodeType nodetype, OSLCompilerImpl* compiler, int op,
161156
ASTNode* a, ASTNode* b, ASTNode* c, ASTNode* d)
162157
: m_nodetype(nodetype)
163158
, m_compiler(compiler)
164-
, m_sourcefile(compiler->filename())
165-
, m_sourceline(compiler->lineno())
159+
, m_srcloc(compiler->srcloc())
166160
, m_op(op)
167161
, m_is_lvalue(false)
168162
{
@@ -213,31 +207,31 @@ ASTNode::~ASTNode()
213207
void
214208
ASTNode::error_impl(string_view msg) const
215209
{
216-
m_compiler->errorfmt(sourcefile(), sourceline(), "{}", msg);
210+
m_compiler->errorfmt(sourceloc(), "{}", msg);
217211
}
218212

219213

220214

221215
void
222216
ASTNode::warning_impl(string_view msg) const
223217
{
224-
m_compiler->warningfmt(sourcefile(), sourceline(), "{}", msg);
218+
m_compiler->warningfmt(sourceloc(), "{}", msg);
225219
}
226220

227221

228222

229223
void
230224
ASTNode::info_impl(string_view msg) const
231225
{
232-
m_compiler->infofmt(sourcefile(), sourceline(), "{}", msg);
226+
m_compiler->infofmt(sourceloc(), "{}", msg);
233227
}
234228

235229

236230

237231
void
238232
ASTNode::message_impl(string_view msg) const
239233
{
240-
m_compiler->messagefmt(sourcefile(), sourceline(), "{}", msg);
234+
m_compiler->messagefmt(sourceloc(), "{}", msg);
241235
}
242236

243237

@@ -366,7 +360,7 @@ ASTfunction_declaration::ASTfunction_declaration(OSLCompilerImpl* comp,
366360
TypeSpec type, ustring name,
367361
ASTNode* form, ASTNode* stmts,
368362
ASTNode* meta,
369-
int sourceline_start)
363+
const SrcLoc& srcloc_start)
370364
: ASTNode(function_declaration_node, comp, 0, meta, form, stmts)
371365
, m_name(name)
372366
, m_sym(NULL)
@@ -375,8 +369,12 @@ ASTfunction_declaration::ASTfunction_declaration(OSLCompilerImpl* comp,
375369
// Some trickery -- the compiler's idea of the "current" source line
376370
// is the END of the function body, so if a hint was passed about the
377371
// start of the declaration, substitute that.
378-
if (sourceline_start >= 0)
379-
m_sourceline = sourceline_start;
372+
// FIXME: [lfascione] Maybe with the move from int sourceline to SrcLoc this
373+
// is the right thing to do here
374+
if (srcloc_start) {
375+
m_srcloc.line_start = srcloc_start.line_start;
376+
m_srcloc.column_begin = srcloc_start.column_begin;
377+
}
380378

381379
if (Strutil::starts_with(name, "___"))
382380
errorfmt("\"{}\" : sorry, can't start with three underscores", name);
@@ -386,7 +384,9 @@ ASTfunction_declaration::ASTfunction_declaration(OSLCompilerImpl* comp,
386384
if (existing_syms && existing_syms->symtype() != SymTypeFunction) {
387385
errorfmt("\"{}\" already declared in this scope as a {}", name,
388386
existing_syms->typespec());
389-
// FIXME -- print the file and line of the other definition
387+
// print the file and line of the other definition when available
388+
if (existing_syms->node())
389+
comp->message_srcloc(existing_syms->node()->sourceloc());
390390
existing_syms = NULL;
391391
}
392392

@@ -429,13 +429,9 @@ ASTfunction_declaration::ASTfunction_declaration(OSLCompilerImpl* comp,
429429
}
430430
err += "\n ";
431431
if (other) {
432-
err += Strutil::fmt::format(
433-
"{}:{}",
434-
OIIO::Filesystem::filename(
435-
other->sourcefile().string()),
436-
other->sourceline());
432+
err += Strutil::fmt::format("{}", other->sourceloc());
437433
} else
438-
err += "built-in";
434+
err += "(built-in)";
439435
}
440436
}
441437
}
@@ -519,7 +515,7 @@ ASTvariable_declaration::ASTvariable_declaration(OSLCompilerImpl* comp,
519515
ustring name, ASTNode* init,
520516
bool isparam, bool ismeta,
521517
bool isoutput, bool initlist,
522-
int sourceline_start)
518+
const SrcLoc& srcloc_start)
523519
: ASTNode(variable_declaration_node, comp, 0, init, NULL /* meta */)
524520
, m_name(name)
525521
, m_sym(NULL)
@@ -531,8 +527,10 @@ ASTvariable_declaration::ASTvariable_declaration(OSLCompilerImpl* comp,
531527
// Some trickery -- the compiler's idea of the "current" source line
532528
// is the END of the declaration, so if a hint was passed about the
533529
// start of the declaration, substitute that.
534-
if (sourceline_start >= 0)
535-
m_sourceline = sourceline_start;
530+
if (srcloc_start) {
531+
m_srcloc.line_start = srcloc_start.line_start;
532+
m_srcloc.column_begin = srcloc_start.column_begin;
533+
}
536534

537535
if (m_initlist && init) {
538536
// Typecheck the init list early.
@@ -547,10 +545,8 @@ ASTvariable_declaration::ASTvariable_declaration(OSLCompilerImpl* comp,
547545
= Strutil::fmt::format("\"{}\" already declared in this scope",
548546
name);
549547
if (f->node()) {
550-
std::string filename = OIIO::Filesystem::filename(
551-
f->node()->sourcefile().string());
552-
e += Strutil::fmt::format("\n\t\tprevious declaration was at {}:{}",
553-
filename, f->node()->sourceline());
548+
e += Strutil::fmt::format("\n\t\tprevious declaration was at {}",
549+
f->node()->sourceloc());
554550
}
555551
if (f->scope() == 0 && f->symtype() == SymTypeFunction && isparam) {
556552
// special case: only a warning for param to mask global function

src/liboslcomp/ast.h

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -191,15 +191,11 @@ class ASTNode : public OIIO::RefCnt {
191191
/// Reverse the order of the list.
192192
friend ASTNode::ref reverse(ASTNode::ref list);
193193

194-
/// What source file was this parse node created from?
194+
/// What location in the source file was this parse node created from?
195195
///
196-
ustring sourcefile() const { return m_sourcefile; }
196+
const SrcLoc sourceloc() const { return m_srcloc; }
197197

198-
/// What line of the source file was this parse node created from?
199-
///
200-
int sourceline() const { return m_sourceline; }
201-
202-
void sourceline(int line) { m_sourceline = line; }
198+
void sourceloc(const SrcLoc& loc) { m_srcloc = loc; }
203199

204200
template<typename... Args>
205201
void errorfmt(const char* format, const Args&... args) const
@@ -407,8 +403,7 @@ class ASTNode : public OIIO::RefCnt {
407403
NodeType m_nodetype; ///< Type of node this is
408404
ref m_next; ///< Next node in the list
409405
OSLCompilerImpl* m_compiler; ///< Back-pointer to the compiler
410-
ustring m_sourcefile; ///< Filename of source where the node came from
411-
int m_sourceline; ///< Line number in source where the node came from
406+
SrcLoc m_srcloc; ///< Location in source where the node came from
412407
std::vector<ref> m_children; ///< Child nodes
413408
int m_op; ///< Operator selection
414409
TypeSpec m_typespec; ///< Data type of this node
@@ -445,7 +440,7 @@ class ASTfunction_declaration final : public ASTNode {
445440
public:
446441
ASTfunction_declaration(OSLCompilerImpl* comp, TypeSpec type, ustring name,
447442
ASTNode* form, ASTNode* stmts, ASTNode* meta,
448-
int sourceline_start = -1);
443+
const SrcLoc& srcloc_start);
449444
const char* nodetypename() const { return "function_declaration"; }
450445
const char* childname(size_t i) const;
451446
void print(std::ostream& out, int indentlevel = 0) const;
@@ -476,7 +471,7 @@ class ASTvariable_declaration final : public ASTNode {
476471
ASTvariable_declaration(OSLCompilerImpl* comp, const TypeSpec& type,
477472
ustring name, ASTNode* init, bool isparam,
478473
bool ismeta, bool isoutput, bool initlist,
479-
int sourceline_start = -1);
474+
const SrcLoc& srcloc_start);
480475
const char* nodetypename() const;
481476
const char* childname(size_t i) const;
482477
void print(std::ostream& out, int indentlevel = 0) const;

0 commit comments

Comments
 (0)