]> git.tdb.fi Git - libs/gl.git/commitdiff
Refactor error reporting in SL::Parser
authorMikko Rasa <tdb@tdb.fi>
Sun, 14 Feb 2021 14:57:32 +0000 (16:57 +0200)
committerMikko Rasa <tdb@tdb.fi>
Sun, 14 Feb 2021 17:37:30 +0000 (19:37 +0200)
There's now dedicated exception classes which take care of the
formatting.

source/glsl/glsl_error.cpp [new file with mode: 0644]
source/glsl/glsl_error.h [new file with mode: 0644]
source/glsl/parser.cpp
source/glsl/parser.h

diff --git a/source/glsl/glsl_error.cpp b/source/glsl/glsl_error.cpp
new file mode 100644 (file)
index 0000000..ea8e930
--- /dev/null
@@ -0,0 +1,20 @@
+#include "glsl_error.h"
+#include "parser.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GL {
+namespace SL {
+
+invalid_shader_source::invalid_shader_source(const Location &loc, const string &message):
+       runtime_error(format("%s:%d: %s", loc.name, loc.line, message))
+{ }
+
+parse_error::parse_error(const Location &loc, const string &token, const string &expected):
+       invalid_shader_source(loc, "Parse error at '%s': expected %s", token, expected)
+{ }
+
+} // namespace SL
+} // namespace GL
+} // namespace Msp
diff --git a/source/glsl/glsl_error.h b/source/glsl/glsl_error.h
new file mode 100644 (file)
index 0000000..63c49bb
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef MSP_GL_SL_ERROR_H_
+#define MSP_GL_SL_ERROR_H_
+
+#include <stdexcept>
+#include <msp/strings/format.h>
+
+namespace Msp {
+namespace GL {
+namespace SL {
+
+struct Location;
+
+class invalid_shader_source: public std::runtime_error
+{
+public:
+       invalid_shader_source(const Location &, const std::string &);
+#if __cplusplus>=201103L
+       template<typename... Args>
+       invalid_shader_source(const Location &loc, const std::string & fmt, Args... args):
+               invalid_shader_source(loc, format(fmt, args...))
+       { }
+#endif
+       virtual ~invalid_shader_source() throw() { }
+};
+
+class parse_error: public invalid_shader_source
+{
+public:
+       parse_error(const Location &, const std::string &, const std::string &);
+       virtual ~parse_error() throw() { }
+};
+
+} // namespace SL
+} // namespace GL
+} // namespace Msp
+
+#endif
index d55cdab3abc5ff426fbf89b3edeab1d56109ddff..3126fae627a69941b1489ca969babf22e90658b9 100644 (file)
@@ -1,6 +1,7 @@
 #include <msp/core/raii.h>
 #include <msp/strings/format.h>
 #include <msp/strings/regex.h>
+#include "glsl_error.h"
 #include "parser.h"
 
 #undef interface
@@ -72,7 +73,7 @@ Parser::~Parser()
 Module &Parser::parse(const string &s, const string &n, unsigned i)
 {
        source = s;
-       source_name = n;
+       location.name = n;
        source_index = i;
        parse_source();
        return *module;
@@ -81,7 +82,7 @@ Module &Parser::parse(const string &s, const string &n, unsigned i)
 Module &Parser::parse(IO::Base &io, const string &n, unsigned i)
 {
        source = string();
-       source_name = n;
+       location.name = n;
        source_index = i;
        while(!io.eof())
        {
@@ -111,23 +112,12 @@ void Parser::parse_source()
        cur_stage = &module->shared;
        iter = source.begin();
        source_end = source.end();
-       current_line = 1;
+       location.line = 1;
        allow_preprocess = true;
        while(RefPtr<Statement> statement = parse_global_declaration())
                cur_stage->content.body.push_back(statement);
 }
 
-string Parser::format_error(const std::string &message)
-{
-       string location = format("%s:%d: ", source_name, current_line);
-       return location+message;
-}
-
-string Parser::format_syntax_error(const std::string &expected)
-{
-       return format_error(format("Syntax error at '%s': expected %s", last_token, expected));
-}
-
 const string &Parser::peek_token(unsigned index)
 {
        while(next_tokens.size()<=index)
@@ -272,7 +262,7 @@ void Parser::skip_comment_and_whitespace()
 
                if(*iter=='\n')
                {
-                       ++current_line;
+                       ++location.line;
                        allow_preprocess = (comment<3);
                }
 
@@ -284,14 +274,14 @@ void Parser::expect(const string &token)
 {
        string parsed = parse_token();
        if(parsed!=token)
-               throw runtime_error(format_syntax_error(format("'%s'", token)));
+               throw parse_error(location, parsed, format("'%s'", token));
 }
 
 string Parser::expect_type()
 {
        string token = parse_token();
        if(!is_type(token))
-               throw runtime_error(format_syntax_error("a type"));
+               throw parse_error(location, token, "a type");
        return token;
 }
 
@@ -299,7 +289,7 @@ string Parser::expect_identifier()
 {
        string token = parse_token();
        if(!is_identifier(token))
-               throw runtime_error(format_syntax_error("an identifier"));
+               throw parse_error(location, token, "an identifier");
        return token;
 }
 
@@ -372,9 +362,9 @@ void Parser::preprocess()
                preprocess_version();
        else if(token=="define" || token=="undef" || token=="if" || token=="ifdef" || token=="ifndef" || token=="else" ||
                token=="elif" || token=="endif" || token=="error" || token=="extension" || token=="line")
-               throw runtime_error(format_error(format("Unsupported preprocessor directive '%s'", token)));
+               throw invalid_shader_source(location, "Unsupported preprocessor directive '%s'", token);
        else if(!token.empty())
-               throw runtime_error(format_syntax_error("a preprocessor directive"));
+               throw parse_error(location, token, "a preprocessor directive");
 
        iter = line_end;
 }
@@ -388,7 +378,7 @@ void Parser::preprocess_version()
 
        token = parse_token();
        if(!token.empty())
-               throw runtime_error(format_syntax_error("end of line"));
+               throw parse_error(location, token, "end of line");
 }
 
 void Parser::preprocess_pragma()
@@ -405,17 +395,17 @@ void Parser::preprocess_pragma_msp()
        if(token=="stage")
                preprocess_stage();
        else
-               throw runtime_error(format_error(format("Unrecognized MSP pragma '%s'", token)));
+               throw invalid_shader_source(location, "Unrecognized MSP pragma '%s'", token);
 
        token = parse_token();
        if(!token.empty())
-               throw runtime_error(format_syntax_error("end of line"));
+               throw parse_error(location, token, "end of line");
 }
 
 void Parser::preprocess_stage()
 {
        if(!allow_stage_change)
-               throw runtime_error(format_error("Changing stage not allowed here"));
+               throw invalid_shader_source(location, "Changing stage not allowed here");
 
        expect("stage");
        expect("(");
@@ -428,11 +418,11 @@ void Parser::preprocess_stage()
        else if(token=="fragment")
                stage = FRAGMENT;
        else
-               throw runtime_error(format_syntax_error("stage identifier"));
+               throw parse_error(location, token, "stage identifier");
        expect(")");
 
        if(stage<=cur_stage->type)
-               throw runtime_error(format_error(format("Stage '%s' not allowed here", token)));
+               throw invalid_shader_source(location, "Stage '%s' not allowed here", token);
 
        module->stages.push_back(stage);
 
@@ -459,7 +449,7 @@ RefPtr<Statement> Parser::parse_global_declaration()
                {
                        RefPtr<InterfaceLayout> iface_lo = new InterfaceLayout;
                        iface_lo->source = source_index;
-                       iface_lo->line = current_line;
+                       iface_lo->line = location.line;
                        iface_lo->layout.qualifiers = layout->qualifiers;
                        iface_lo->interface = parse_token();
                        expect(";");
@@ -494,7 +484,7 @@ RefPtr<Statement> Parser::parse_global_declaration()
        else if(token.empty())
                return 0;
        else
-               throw runtime_error(format_syntax_error("a global declaration"));
+               throw parse_error(location, token, "a global declaration");
 }
 
 RefPtr<Statement> Parser::parse_statement()
@@ -514,7 +504,7 @@ RefPtr<Statement> Parser::parse_statement()
        {
                RefPtr<Jump> jump = new Jump;
                jump->source = source_index;
-               jump->line = current_line;
+               jump->line = location.line;
                jump->keyword = parse_token();
                expect(";");
 
@@ -526,25 +516,25 @@ RefPtr<Statement> Parser::parse_statement()
        {
                RefPtr<ExpressionStatement> expr = new ExpressionStatement;
                expr->source = source_index;
-               expr->line = current_line;
+               expr->line = location.line;
                expr->expression = parse_expression();
                expect(";");
 
                return expr;
        }
        else
-               throw runtime_error(format_syntax_error("a statement"));
+               throw parse_error(location, token, "a statement");
 }
 
 RefPtr<Import> Parser::parse_import()
 {
        if(cur_stage->type!=SHARED)
-               throw runtime_error(format_error("Imports are only allowed in the shared section"));
+               throw invalid_shader_source(location, "Imports are only allowed in the shared section");
 
        expect("import");
        RefPtr<Import> import = new Import;
        import->source = source_index;
-       import->line = current_line;
+       import->line = location.line;
        import->module = expect_identifier();
        expect(";");
        return import;
@@ -555,16 +545,16 @@ RefPtr<Precision> Parser::parse_precision()
        expect("precision");
        RefPtr<Precision> precision = new Precision;
        precision->source = source_index;
-       precision->line = current_line;
+       precision->line = location.line;
 
        precision->precision = parse_token();
        if(!is_precision_qualifier(precision->precision))
-               throw runtime_error(format_syntax_error("a precision qualifier"));
+               throw parse_error(location, precision->precision, "a precision qualifier");
 
        precision->type = parse_token();
        // Not entirely accurate; only float, int and sampler types are allowed
        if(!is_builtin_type(precision->type))
-               throw runtime_error(format_syntax_error("a builtin type"));
+               throw parse_error(location, precision->type, "a builtin type");
 
        expect(";");
 
@@ -580,7 +570,7 @@ RefPtr<Layout> Parser::parse_layout()
        {
                string token = parse_token();
                if(token==")")
-                       throw runtime_error(format_syntax_error("a layout qualifier name"));
+                       throw parse_error(location, token, "a layout qualifier name");
 
                layout->qualifiers.push_back(Layout::Qualifier());
                Layout::Qualifier &qual = layout->qualifiers.back();
@@ -637,14 +627,14 @@ RefPtr<Expression> Parser::parse_expression(unsigned precedence)
                        if(left)
                                return left;
                        else
-                               throw runtime_error(format_syntax_error("an expression"));
+                               throw parse_error(location, token, "an expression");
                }
                else if(left)
                {
                        if(token=="(")
                        {
                                if(!left_var)
-                                       throw runtime_error(format_error("Syntax error before '(': function name must be an identifier"));
+                                       throw invalid_shader_source(location, "Syntax error before '(': function name must be an identifier");
                                left = parse_function_call(*left_var);
                        }
                        else if(token==".")
@@ -666,7 +656,7 @@ RefPtr<Expression> Parser::parse_expression(unsigned precedence)
                        else if(oper && oper->type==BINARY)
                                left = parse_binary(left, oper);
                        else
-                               throw runtime_error(format_syntax_error("an operator"));
+                               throw parse_error(location, token, "an operator");
                        left_var = 0;
                }
                else
@@ -701,7 +691,7 @@ RefPtr<Expression> Parser::parse_expression(unsigned precedence)
                                left = unary;
                        }
                        else
-                               throw runtime_error(format_syntax_error("an expression"));
+                               throw parse_error(location, token, "an expression");
                }
        }
 }
@@ -743,7 +733,7 @@ RefPtr<StructDeclaration> Parser::parse_struct_declaration()
        expect("struct");
        RefPtr<StructDeclaration> strct = new StructDeclaration;
        strct->source = source_index;
-       strct->line = current_line;
+       strct->line = location.line;
 
        strct->name = expect_identifier();
        parse_block(strct->members, true);
@@ -757,7 +747,7 @@ RefPtr<VariableDeclaration> Parser::parse_variable_declaration()
 {
        RefPtr<VariableDeclaration> var = new VariableDeclaration;
        var->source = source_index;
-       var->line = current_line;
+       var->line = location.line;
 
        string token = peek_token();
        while(is_qualifier(token))
@@ -800,7 +790,7 @@ RefPtr<FunctionDeclaration> Parser::parse_function_declaration()
 {
        RefPtr<FunctionDeclaration> func = new FunctionDeclaration;
        func->source = source_index;
-       func->line = current_line;
+       func->line = location.line;
 
        func->return_type = expect_type();
        func->name = expect_identifier();
@@ -829,7 +819,7 @@ RefPtr<FunctionDeclaration> Parser::parse_function_declaration()
        else if(token==";")
                parse_token();
        else
-               throw runtime_error(format_syntax_error("'{' or ';'"));
+               throw parse_error(location, token, "'{' or ';'");
 
        return func;
 }
@@ -838,11 +828,11 @@ RefPtr<InterfaceBlock> Parser::parse_interface_block()
 {
        RefPtr<InterfaceBlock> iface = new InterfaceBlock;
        iface->source = source_index;
-       iface->line = current_line;
+       iface->line = location.line;
 
        iface->interface = parse_token();
        if(!is_interface_qualifier(iface->interface))
-               throw runtime_error(format_syntax_error("an interface qualifier"));
+               throw parse_error(location, iface->interface, "an interface qualifier");
 
        iface->name = expect_identifier();
        parse_block(iface->members, true);
@@ -865,7 +855,7 @@ RefPtr<Conditional> Parser::parse_conditional()
        expect("if");
        RefPtr<Conditional> cond = new Conditional;
        cond->source = source_index;
-       cond->line = current_line;
+       cond->line = location.line;
        expect("(");
        cond->condition = parse_expression();
        expect(")");
@@ -887,7 +877,7 @@ RefPtr<Iteration> Parser::parse_for()
        expect("for");
        RefPtr<Iteration> loop = new Iteration;
        loop->source = source_index;
-       loop->line = current_line;
+       loop->line = location.line;
        expect("(");
        string token = peek_token();
        if(is_type(token))
@@ -919,7 +909,7 @@ RefPtr<Iteration> Parser::parse_while()
        expect("while");
        RefPtr<Iteration> loop = new Iteration;
        loop->source = source_index;
-       loop->line = current_line;
+       loop->line = location.line;
        expect("(");
        loop->condition = parse_expression();
        expect(")");
@@ -934,7 +924,7 @@ RefPtr<Passthrough> Parser::parse_passthrough()
        expect("passthrough");
        RefPtr<Passthrough> pass = new Passthrough;
        pass->source = source_index;
-       pass->line = current_line;
+       pass->line = location.line;
        if(cur_stage->type==GEOMETRY)
        {
                expect("[");
@@ -950,7 +940,7 @@ RefPtr<Return> Parser::parse_return()
        expect("return");
        RefPtr<Return> ret = new Return;
        ret->source = source_index;
-       ret->line = current_line;
+       ret->line = location.line;
        if(peek_token()!=";")
                ret->expression = parse_expression();
        expect(";");
index c9588bfbdd99486a0e759df55ebd7c520ebeefb0..743149d83362a84be8b91e5b13dad8789e90bede 100644 (file)
@@ -12,6 +12,12 @@ namespace Msp {
 namespace GL {
 namespace SL {
 
+struct Location
+{
+       std::string name;
+       unsigned line;
+};
+
 class Parser
 {
 private:
@@ -38,9 +44,8 @@ private:
        };
 
        std::string source;
-       std::string source_name;
        unsigned source_index;
-       unsigned current_line;
+       Location location;
        std::string::const_iterator iter;
        std::string::const_iterator source_end;
        bool allow_preprocess;
@@ -63,9 +68,6 @@ public:
 private:
        void parse_source();
 
-       std::string format_error(const std::string &);
-       std::string format_syntax_error(const std::string &);
-
        const std::string &peek_token(unsigned = 0);
        const std::string &parse_token();
        std::string parse_token_();