Skip to content

Commit 0379496

Browse files
committed
Basic method definition and invocation.
1 parent 17c6445 commit 0379496

12 files changed

Lines changed: 239 additions & 41 deletions

File tree

CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ TESTSUITE ( and-or-not-synonyms aastep arithmetic array array-derivs array-range
247247
draw_string
248248
error-dupes exit exponential
249249
fprintf
250-
function-earlyreturn function-simple function-outputelem
250+
function-earlyreturn function-method function-simple function-outputelem
251251
geomath getattribute-camera getattribute-shader
252252
getsymbol-nonheap gettextureinfo
253253
group-outputs groupstring
@@ -266,7 +266,7 @@ TESTSUITE ( and-or-not-synonyms aastep arithmetic array array-derivs array-range
266266
operator-overloading
267267
oslc-comma oslc-D
268268
oslc-err-arrayindex oslc-err-closuremul oslc-err-field
269-
oslc-err-format oslc-err-intoverflow
269+
oslc-err-format oslc-err-intoverflow oslc-err-method
270270
oslc-err-names oslc-err-noreturn oslc-err-notfunc
271271
oslc-err-outputparamvararray oslc-err-paramdefault
272272
oslc-err-struct-array-init oslc-err-struct-ctr

src/include/osl_pvt.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,10 @@ class Symbol {
557557
m_alias = other;
558558
}
559559

560+
/// Get a reference to whatever this symbol aliases.
561+
///
562+
const Symbol* alias () const { return m_alias; }
563+
560564
/// Return a string representation ("param", "global", etc.) of the
561565
/// SymType s.
562566
static const char *symtype_shortname (SymType s);

src/liboslcomp/ast.cpp

Lines changed: 99 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -285,14 +285,15 @@ ASTnamed_symbol::ASTnamed_symbol (NodeType node_type, OSLCompilerImpl *comp,
285285

286286

287287
bool
288-
ASTnamed_symbol::check_reserved (ustring name, OSLCompilerImpl *comp)
288+
ASTnamed_symbol::check_reserved (ustring name, OSLCompilerImpl *comp,
289+
int vflags)
289290
{
290291
if (Strutil::starts_with(name, "___")) {
291292
comp->error (comp->filename(), comp->lineno(),
292293
"'%s' : sorry, can't start with three underscores",
293294
name);
294295
return false;
295-
} else if (name == "this") {
296+
} else if (!(vflags & allow_this) && name == "this") {
296297
comp->error (comp->filename(), comp->lineno(),
297298
"'this' not allowed in this context");
298299
return false;
@@ -317,9 +318,9 @@ ASTnamed_symbol::previous_decl (ASTNode* node)
317318

318319
Symbol*
319320
ASTnamed_symbol::validate (ustring name, OSLCompilerImpl *comp,
320-
Validation vflags, int allowed)
321+
int vflags, int allowed)
321322
{
322-
check_reserved (name, comp);
323+
check_reserved (name, comp, vflags);
323324

324325
Symbol *f;
325326
bool shadow = vflags & warn_shadow;
@@ -341,19 +342,35 @@ ASTnamed_symbol::validate (ustring name, OSLCompilerImpl *comp,
341342
if (! f || f->symtype() == allowed)
342343
return f;
343344

344-
std::string e = Strutil::format ("'%s' already declared in this scope",
345-
name);
346-
e += previous_decl (f->node());
347-
345+
std::string msg;
346+
ASTNode* hint = f->node();
348347
if (shadow) {
349-
// special case: only a warning for param to mask global function
348+
// Downgrade to warning if param to mask global function
350349
shadow = f->scope() == 0 && f->symtype() == SymTypeFunction;
350+
351+
// also downgrade to warning if local variable shadowing a field
352+
if (!shadow && f->alias() && f->alias()->node()) {
353+
if (f->alias()->node()->typespec().is_structure() &&
354+
f->alias()->name() == Strutil::format("this.%s", name)) {
355+
msg = Strutil::format ("\"%s\" shadows a field with the same name",
356+
name);
357+
// FIXME: Would be nice to hint about where the field was
358+
// declared, but f->alias()->node() is the 'this.field' node.
359+
hint = nullptr;
360+
shadow = true;
361+
}
362+
}
351363
}
352364

365+
if (msg.empty())
366+
msg = Strutil::format ("'%s' already declared in this scope", name);
367+
368+
msg += previous_decl (hint);
369+
353370
if (shadow)
354-
comp->warning(comp->filename(), comp->lineno(), "%s", e);
371+
comp->warning(comp->filename(), comp->lineno(), "%s", msg);
355372
else
356-
comp->error(comp->filename(), comp->lineno(), "%s", e);
373+
comp->error(comp->filename(), comp->lineno(), "%s", msg);
357374
}
358375
return f;
359376
}
@@ -532,17 +549,19 @@ ASTvariable_declaration::ASTvariable_declaration (OSLCompilerImpl *comp,
532549
const TypeSpec &type,
533550
ustring name, ASTNode *init,
534551
bool isparam, bool ismeta,
535-
bool isoutput, bool initlist)
552+
bool isoutput, bool initlist,
553+
bool isthis)
536554
: ASTnamed_symbol (variable_declaration_node, comp, name, init, NULL /* meta */),
537555
m_isparam(isparam), m_isoutput(isoutput), m_ismetadata(ismeta),
538556
m_initlist(initlist)
539557
{
540-
if (! check_reserved ())
558+
int vflags = isthis ? allow_this : 0;
559+
if (! check_reserved (m_name, m_compiler, vflags))
541560
return;
542561

543562
m_typespec = type;
544563
if (! m_ismetadata)
545-
validate (warn_function_clash);
564+
validate (vflags | warn_function_clash);
546565

547566
SymType symtype = isparam ? (isoutput ? SymTypeOutputParam : SymTypeParam)
548567
: SymTypeLocal;
@@ -566,6 +585,50 @@ ASTvariable_declaration::ASTvariable_declaration (OSLCompilerImpl *comp,
566585

567586

568587

588+
ASTvariable_declaration::ASTvariable_declaration (OSLCompilerImpl *comp,
589+
const TypeSpec &type,
590+
ASTNode *args)
591+
: ASTvariable_declaration(comp, type, ustring("this"), NULL,
592+
false, false, false, false, true)
593+
{
594+
// Push 'this' to front of given arguments
595+
concat(this, args);
596+
if (StructSpec* sspec = type.structure() ? type.structspec() : nullptr) {
597+
// Add the fields as accessible without 'this', warning about possible
598+
// shadowing/ambiguity as we go.
599+
for (int i = 0, n = sspec->numfields(); i < n; ++i) {
600+
const auto& field = sspec->field(i);
601+
bool conflict = false;
602+
for (ref next = args; next; next = next->next()) {
603+
ASSERT (next->nodetype() == variable_declaration_node);
604+
auto *arg = static_cast<ASTvariable_declaration*>(next.get());
605+
606+
if (arg->name() == field.name) {
607+
warning ("argument \"%s\" shadows a field with the same name",
608+
field.name);
609+
conflict = true;
610+
break;
611+
}
612+
}
613+
if (! conflict) {
614+
ustring qualname = ustring::format ("this.%s", field.name);
615+
ASSERT (m_compiler->symtab().find (qualname) != nullptr);
616+
ASSERT (!m_compiler->symtab().find (field.name) ||
617+
m_compiler->symtab().find (field.name)->scope() !=
618+
m_compiler->symtab().scopeid());
619+
620+
Symbol* qsym = m_compiler->symtab().find (qualname);
621+
Symbol *fsym = new Symbol (field.name, field.type,
622+
qsym->symtype (), this);
623+
fsym->alias (qsym);
624+
m_compiler->symtab().insert (fsym);
625+
}
626+
}
627+
}
628+
}
629+
630+
631+
569632
const char *
570633
ASTvariable_declaration::nodetypename () const
571634
{
@@ -603,10 +666,10 @@ ASTvariable_declaration::print (std::ostream &out, int indentlevel) const
603666

604667

605668

606-
ASTvariable_ref::ASTvariable_ref (OSLCompilerImpl *comp, ustring name)
669+
ASTvariable_ref::ASTvariable_ref (OSLCompilerImpl *comp, ustring name, bool allowthis)
607670
: ASTnamed_symbol (variable_ref_node, comp, name)
608671
{
609-
m_sym = validate (warn_function_exists);
672+
m_sym = validate (warn_function_exists | (allowthis ? allow_this : 0));
610673
if (m_sym)
611674
m_typespec = m_sym->typespec();
612675
}
@@ -1122,10 +1185,11 @@ ASTtype_constructor::childname (size_t i) const
11221185
ASTfunction_call::ASTfunction_call (OSLCompilerImpl *comp, ustring name,
11231186
ASTNode *args, FunctionSymbol *funcsym)
11241187
: ASTnamed_symbol (function_call_node, comp, name, args),
1125-
m_poly(funcsym), // Default - resolved symbol or null
1126-
m_argread(~1), // Default - all args are read except the first
1127-
m_argwrite(1), // Default - first arg only is written by the op
1128-
m_argtakesderivs(0) // Default - doesn't take derivs
1188+
m_poly(funcsym), // Default - resolved symbol or null
1189+
m_argread(~1), // Default - all args are read except the first
1190+
m_argwrite(1), // Default - first arg only is written by the op
1191+
m_argtakesderivs(0), // Default - doesn't take derivs
1192+
m_method(false)
11291193
{
11301194
m_sym = funcsym ? funcsym : validate (err_must_exist); // Look it up.
11311195
if (! m_sym || is_struct_ctr())
@@ -1139,10 +1203,24 @@ ASTfunction_call::ASTfunction_call (OSLCompilerImpl *comp, ustring name,
11391203

11401204

11411205

1206+
void
1207+
ASTfunction_call::method_from_function (ASTNode* thisRef)
1208+
{
1209+
ASSERT (m_method == false);
1210+
ASSERT (m_children.size() == 1);
1211+
m_method = true;
1212+
if (m_children[0])
1213+
thisRef->append(args().get());
1214+
1215+
m_children[0] = thisRef;
1216+
}
1217+
1218+
1219+
11421220
const char *
11431221
ASTfunction_call::childname (size_t i) const
11441222
{
1145-
return ustring::format ("param%d", (int)i).c_str();
1223+
return (i || !m_method ? ustring::format ("param%d", (int)i) : ustring("this")).c_str();
11461224
}
11471225

11481226

src/liboslcomp/ast.h

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,8 @@ class ASTNode : public OIIO::RefCnt {
301301
/// Type check a list (whose head is given by 'arg' against the list
302302
/// of expected types given in encoded form by 'formals'.
303303
bool check_arglist (const char *funcname, ref arg,
304-
const char *formals, bool coerce=false);
304+
const char *formals, bool coerce=false,
305+
bool methcall = false);
305306

306307
/// Follow a list of nodes, generating code for each in turn, and return
307308
/// the Symbol* for the last thing generated.
@@ -416,26 +417,28 @@ class ASTnamed_symbol : public ASTNode
416417
err_must_exist = 0, ///< Error when the named Symbol does not exist.
417418
check_clashes = 1, ///< If named Symbol exists error as a clash.
418419
warn_shadow = 2, ///< Warn if name shadows a known function.
420+
allow_this = 4, ///< Allow m_name to be 'this'
419421

420422
/// Convenient aliases of validation schemes.
421423
warn_function_exists = err_must_exist | warn_shadow,
422424
warn_function_clash = check_clashes | warn_shadow,
423425
};
424426

425427
/// Validate that m_name is a legal name.
426-
static bool check_reserved (ustring name, OSLCompilerImpl *comp);
428+
static bool check_reserved (ustring name, OSLCompilerImpl *comp,
429+
int allowThis = 0);
427430

428431
/// Validate that m_name is a legal name, and doesn't conflict with rules
429432
/// given in vflags allowing duplicate symbol if its SymType matches allowed.
430433
static Symbol* validate (ustring name, OSLCompilerImpl *comp,
431-
Validation vflags, int allowed = -1);
434+
int vflags, int allowed = -1);
432435

433436
protected:
434437
bool check_reserved () {
435438
return ASTnamed_symbol::check_reserved (m_name, m_compiler);
436439
}
437440

438-
Symbol* validate (Validation vflags, int allowed = -1) {
441+
Symbol* validate (int vflags, int allowed = -1) {
439442
return validate (m_name, m_compiler, vflags, allowed);
440443
}
441444

@@ -503,7 +506,11 @@ class ASTvariable_declaration : public ASTnamed_symbol
503506
ASTvariable_declaration (OSLCompilerImpl *comp, const TypeSpec &type,
504507
ustring name, ASTNode *init, bool isparam=false,
505508
bool ismeta=false, bool isoutput=false,
506-
bool initlist=false);
509+
bool initlist=false, bool isthis=false);
510+
511+
ASTvariable_declaration (OSLCompilerImpl *comp, const TypeSpec &type,
512+
ASTNode *args);
513+
507514
const char *nodetypename () const;
508515
const char *childname (size_t i) const;
509516
void print (std::ostream &out, int indentlevel=0) const;
@@ -550,7 +557,7 @@ class ASTvariable_declaration : public ASTnamed_symbol
550557
class ASTvariable_ref : public ASTnamed_symbol
551558
{
552559
public:
553-
ASTvariable_ref (OSLCompilerImpl *comp, ustring name);
560+
ASTvariable_ref (OSLCompilerImpl *comp, ustring name, bool allowthis);
554561
const char *nodetypename () const { return "variable_ref"; }
555562
const char *childname (size_t i) const { return ""; } // no children
556563
void print (std::ostream &out, int indentlevel=0) const;
@@ -929,6 +936,8 @@ class ASTfunction_call : public ASTnamed_symbol
929936
return (ASTfunction_declaration *) func()->node();
930937
}
931938

939+
void method_from_function(ASTNode* thisRef);
940+
932941
private:
933942
/// Typecheck all polymorphic versions, return UNKNOWN if no match was
934943
/// found, or a real type if there was a match. Also, upon matching,
@@ -1013,10 +1022,13 @@ class ASTfunction_call : public ASTnamed_symbol
10131022
ustring formal, ustring actual,
10141023
Symbol *arrayindex = NULL);
10151024

1025+
protected:
1026+
10161027
FunctionSymbol *m_poly; ///< The specific polymorphic variant
10171028
unsigned int m_argread; ///< Bit field - which args are read
10181029
unsigned int m_argwrite; ///< Bit field - which args are written
10191030
unsigned int m_argtakesderivs; ///< Bit field - which args take derivs
1031+
bool m_method;
10201032
};
10211033

10221034

0 commit comments

Comments
 (0)