1//
2// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7#include "compiler/DirectiveHandler.h"
8
9#include <sstream>
10
11#include "compiler/debug.h"
12#include "compiler/Diagnostics.h"
13
14static TBehavior getBehavior(const std::string& str)
15{
16    static const std::string kRequire("require");
17    static const std::string kEnable("enable");
18    static const std::string kDisable("disable");
19    static const std::string kWarn("warn");
20
21    if (str == kRequire) return EBhRequire;
22    else if (str == kEnable) return EBhEnable;
23    else if (str == kDisable) return EBhDisable;
24    else if (str == kWarn) return EBhWarn;
25    return EBhUndefined;
26}
27
28TDirectiveHandler::TDirectiveHandler(TExtensionBehavior& extBehavior,
29                                     TDiagnostics& diagnostics)
30    : mExtensionBehavior(extBehavior),
31      mDiagnostics(diagnostics)
32{
33}
34
35TDirectiveHandler::~TDirectiveHandler()
36{
37}
38
39void TDirectiveHandler::handleError(const pp::SourceLocation& loc,
40                                    const std::string& msg)
41{
42    mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, loc, msg, "", "");
43}
44
45void TDirectiveHandler::handlePragma(const pp::SourceLocation& loc,
46                                     const std::string& name,
47                                     const std::string& value)
48{
49    static const std::string kSTDGL("STDGL");
50    static const std::string kOptimize("optimize");
51    static const std::string kDebug("debug");
52    static const std::string kOn("on");
53    static const std::string kOff("off");
54
55    bool invalidValue = false;
56    if (name == kSTDGL)
57    {
58        // The STDGL pragma is used to reserve pragmas for use by future
59        // revisions of GLSL. Ignore it.
60        return;
61    }
62    else if (name == kOptimize)
63    {
64        if (value == kOn) mPragma.optimize = true;
65        else if (value == kOff) mPragma.optimize = false;
66        else invalidValue = true;
67    }
68    else if (name == kDebug)
69    {
70        if (value == kOn) mPragma.debug = true;
71        else if (value == kOff) mPragma.debug = false;
72        else invalidValue = true;
73    }
74    else
75    {
76        mDiagnostics.report(pp::Diagnostics::PP_UNRECOGNIZED_PRAGMA, loc, name);
77        return;
78    }
79
80    if (invalidValue)
81      mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, loc,
82                             "invalid pragma value", value,
83                             "'on' or 'off' expected");
84}
85
86void TDirectiveHandler::handleExtension(const pp::SourceLocation& loc,
87                                        const std::string& name,
88                                        const std::string& behavior)
89{
90    static const std::string kExtAll("all");
91
92    TBehavior behaviorVal = getBehavior(behavior);
93    if (behaviorVal == EBhUndefined)
94    {
95        mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, loc,
96                               "behavior", name, "invalid");
97        return;
98    }
99
100    if (name == kExtAll)
101    {
102        if (behaviorVal == EBhRequire)
103        {
104            mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, loc,
105                                   "extension", name,
106                                   "cannot have 'require' behavior");
107        }
108        else if (behaviorVal == EBhEnable)
109        {
110            mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, loc,
111                                   "extension", name,
112                                   "cannot have 'enable' behavior");
113        }
114        else
115        {
116            for (TExtensionBehavior::iterator iter = mExtensionBehavior.begin();
117                 iter != mExtensionBehavior.end(); ++iter)
118                iter->second = behaviorVal;
119        }
120        return;
121    }
122
123    TExtensionBehavior::iterator iter = mExtensionBehavior.find(name);
124    if (iter != mExtensionBehavior.end())
125    {
126        iter->second = behaviorVal;
127        return;
128    }
129
130    pp::Diagnostics::Severity severity = pp::Diagnostics::PP_ERROR;
131    switch (behaviorVal) {
132      case EBhRequire:
133        severity = pp::Diagnostics::PP_ERROR;
134        break;
135      case EBhEnable:
136      case EBhWarn:
137      case EBhDisable:
138        severity = pp::Diagnostics::PP_WARNING;
139        break;
140      default:
141        UNREACHABLE();
142        break;
143    }
144    mDiagnostics.writeInfo(severity, loc,
145                           "extension", name, "is not supported");
146}
147
148void TDirectiveHandler::handleVersion(const pp::SourceLocation& loc,
149                                      int version)
150{
151    static const int kVersion = 100;
152
153    if (version != kVersion)
154    {
155        std::stringstream stream;
156        stream << version;
157        std::string str = stream.str();
158        mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, loc,
159                               "version number", str, "not supported");
160    }
161}
162