#include <msp/core/raii.h>
#include <msp/strings/format.h>
#include <msp/strings/regex.h>
+#include "glsl_error.h"
#include "parser.h"
#undef interface
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;
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())
{
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)
if(*iter=='\n')
{
- ++current_line;
+ ++location.line;
allow_preprocess = (comment<3);
}
{
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;
}
{
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;
}
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;
}
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()
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("(");
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);
{
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(";");
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()
{
RefPtr<Jump> jump = new Jump;
jump->source = source_index;
- jump->line = current_line;
+ jump->line = location.line;
jump->keyword = parse_token();
expect(";");
{
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;
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(";");
{
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();
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==".")
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
left = unary;
}
else
- throw runtime_error(format_syntax_error("an expression"));
+ throw parse_error(location, token, "an expression");
}
}
}
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);
{
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))
{
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();
else if(token==";")
parse_token();
else
- throw runtime_error(format_syntax_error("'{' or ';'"));
+ throw parse_error(location, token, "'{' or ';'");
return func;
}
{
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);
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(")");
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))
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(")");
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("[");
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(";");