X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fshader%2Fslang%2Fslang_compile.c;h=68eefd2cf1e70d5ec2c89e3feb681e9f2c0e9985;hb=2dc3de016cd0306bf5b492ed781e824864788f11;hp=619b0de0d0dd353226b3578a023328620e0994ef;hpb=b3a22d0ed61afa9df4d3a02962884d49bc5760a4;p=mesa.git diff --git a/src/mesa/shader/slang/slang_compile.c b/src/mesa/shader/slang/slang_compile.c index 619b0de0d0d..68eefd2cf1e 100644 --- a/src/mesa/shader/slang/slang_compile.c +++ b/src/mesa/shader/slang/slang_compile.c @@ -28,17 +28,20 @@ * \author Michal Krol */ -#include "imports.h" -#include "context.h" -#include "program.h" -#include "prog_parameter.h" -#include "grammar_mesa.h" +#include "main/imports.h" +#include "main/context.h" +#include "shader/program.h" +#include "shader/programopt.h" +#include "shader/prog_print.h" +#include "shader/prog_parameter.h" +#include "shader/grammar/grammar_mesa.h" #include "slang_codegen.h" #include "slang_compile.h" #include "slang_preprocess.h" #include "slang_storage.h" #include "slang_emit.h" #include "slang_log.h" +#include "slang_mem.h" #include "slang_vartable.h" #include "slang_simplify.h" @@ -53,6 +56,23 @@ */ +/** re-defined below, should be the same though */ +#define TYPE_SPECIFIER_COUNT 32 + + +/** + * Check if the given identifier is legal. + */ +static GLboolean +legal_identifier(slang_atom name) +{ + /* "gl_" is a reserved prefix */ + if (_mesa_strncmp((char *) name, "gl_", 3) == 0) { + return GL_FALSE; + } + return GL_TRUE; +} + /** * Allocate storage for a variable of 'size' bytes from given pool. @@ -126,6 +146,7 @@ typedef struct slang_parse_ctx_ GLboolean global_scope; /**< Is object being declared a global? */ slang_atom_pool *atoms; slang_unit_type type; /**< Vertex vs. Fragment */ + GLuint version; /**< user-specified (or default) #version */ } slang_parse_ctx; /* slang_output_ctx */ @@ -138,10 +159,25 @@ typedef struct slang_output_ctx_ slang_var_pool *global_pool; struct gl_program *program; slang_var_table *vartable; + GLuint default_precision[TYPE_SPECIFIER_COUNT]; + GLboolean allow_precision; + GLboolean allow_invariant; + GLboolean allow_centroid; + GLboolean allow_array_types; /* float[] syntax */ } slang_output_ctx; /* _slang_compile() */ + +/* Debugging aid, print file/line where parsing error is detected */ +#define RETURN0 \ + do { \ + if (0) \ + printf("slang error at %s:%d\n", __FILE__, __LINE__); \ + return 0; \ + } while (0) + + static void parse_identifier_str(slang_parse_ctx * C, char **id) { @@ -193,12 +229,12 @@ parse_float(slang_parse_ctx * C, float *number) parse_identifier_str(C, &fractional); parse_identifier_str(C, &exponent); - whole = (char *) (slang_alloc_malloc((_mesa_strlen(integral) + - _mesa_strlen(fractional) + - _mesa_strlen(exponent) + 3) * sizeof(char))); + whole = (char *) _slang_alloc((_mesa_strlen(integral) + + _mesa_strlen(fractional) + + _mesa_strlen(exponent) + 3) * sizeof(char)); if (whole == NULL) { slang_info_log_memory(C->L); - return 0; + RETURN0; } slang_string_copy(whole, integral); @@ -209,19 +245,20 @@ parse_float(slang_parse_ctx * C, float *number) *number = (float) (_mesa_strtod(whole, (char **) NULL)); - slang_alloc_free(whole); + _slang_free(whole); + return 1; } /* revision number - increment after each change affecting emitted output */ -#define REVISION 3 +#define REVISION 4 static int check_revision(slang_parse_ctx * C) { if (*C->I != REVISION) { slang_info_log_error(C->L, "Internal compiler error."); - return 0; + RETURN0; } C->I++; return 1; @@ -233,6 +270,10 @@ static int parse_expression(slang_parse_ctx *, slang_output_ctx *, slang_operation *); static int parse_type_specifier(slang_parse_ctx *, slang_output_ctx *, slang_type_specifier *); +static int +parse_type_array_size(slang_parse_ctx *C, + slang_output_ctx *O, + GLint *array_len); static GLboolean parse_array_len(slang_parse_ctx * C, slang_output_ctx * O, GLuint * len) @@ -254,9 +295,33 @@ parse_array_len(slang_parse_ctx * C, slang_output_ctx * O, GLuint * len) /* evaluate compile-time expression which is array size */ _slang_simplify(&array_size, &space, C->atoms); - result = (array_size.type == SLANG_OPER_LITERAL_INT); - *len = (GLint) array_size.literal[0]; + if (array_size.type == SLANG_OPER_LITERAL_INT) { + result = GL_TRUE; + *len = (GLint) array_size.literal[0]; + } else if (array_size.type == SLANG_OPER_IDENTIFIER) { + slang_variable *var = _slang_locate_variable(array_size.locals, array_size.a_id, GL_TRUE); + if (!var) { + slang_info_log_error(C->L, "undefined variable '%s'", + (char *) array_size.a_id); + result = GL_FALSE; + } else if (var->type.qualifier == SLANG_QUAL_CONST && + var->type.specifier.type == SLANG_SPEC_INT) { + if (var->initializer && + var->initializer->type == SLANG_OPER_LITERAL_INT) { + *len = (GLint) var->initializer->literal[0]; + result = GL_TRUE; + } else { + slang_info_log_error(C->L, "unable to parse array size declaration"); + result = GL_FALSE; + } + } else { + slang_info_log_error(C->L, "unable to parse array size declaration"); + result = GL_FALSE; + } + } else { + result = GL_FALSE; + } slang_operation_destruct(&array_size); return result; @@ -284,11 +349,11 @@ static GLboolean convert_to_array(slang_parse_ctx * C, slang_variable * var, const slang_type_specifier * sp) { - /* sized array - mark it as array, copy the specifier to the array element and - * parse the expression */ + /* sized array - mark it as array, copy the specifier to the array element + * and parse the expression */ var->type.specifier.type = SLANG_SPEC_ARRAY; var->type.specifier._array = (slang_type_specifier *) - slang_alloc_malloc(sizeof(slang_type_specifier)); + _slang_alloc(sizeof(slang_type_specifier)); if (var->type.specifier._array == NULL) { slang_info_log_memory(C->L); return GL_FALSE; @@ -304,18 +369,29 @@ convert_to_array(slang_parse_ctx * C, slang_variable * var, static GLboolean parse_struct_field_var(slang_parse_ctx * C, slang_output_ctx * O, - slang_variable * var, const slang_type_specifier * sp) + slang_variable * var, slang_atom a_name, + const slang_type_specifier * sp, + GLuint array_len) { - var->a_name = parse_identifier(C); + var->a_name = a_name; if (var->a_name == SLANG_ATOM_NULL) return GL_FALSE; switch (*C->I++) { case FIELD_NONE: - if (!slang_type_specifier_copy(&var->type.specifier, sp)) - return GL_FALSE; + if (array_len != -1) { + if (!convert_to_array(C, var, sp)) + return GL_FALSE; + var->array_len = array_len; + } + else { + if (!slang_type_specifier_copy(&var->type.specifier, sp)) + return GL_FALSE; + } break; case FIELD_ARRAY: + if (array_len != -1) + return GL_FALSE; if (!convert_to_array(C, var, sp)) return GL_FALSE; if (!parse_array_len(C, O, &var->array_len)) @@ -333,19 +409,29 @@ parse_struct_field(slang_parse_ctx * C, slang_output_ctx * O, slang_struct * st, slang_type_specifier * sp) { slang_output_ctx o = *O; + GLint array_len; o.structs = st->structs; if (!parse_type_specifier(C, &o, sp)) - return 0; + RETURN0; + if (!parse_type_array_size(C, &o, &array_len)) + RETURN0; do { + slang_atom a_name; slang_variable *var = slang_variable_scope_grow(st->fields); if (!var) { slang_info_log_memory(C->L); - return 0; + RETURN0; + } + a_name = parse_identifier(C); + if (_slang_locate_variable(st->fields, a_name, GL_FALSE)) { + slang_info_log_error(C->L, "duplicate field '%s'", (char *) a_name); + RETURN0; } - if (!parse_struct_field_var(C, &o, var, sp)) - return 0; + + if (!parse_struct_field_var(C, &o, var, a_name, sp, array_len)) + RETURN0; } while (*C->I++ != FIELD_NONE); @@ -361,26 +447,26 @@ parse_struct(slang_parse_ctx * C, slang_output_ctx * O, slang_struct ** st) /* parse struct name (if any) and make sure it is unique in current scope */ a_name = parse_identifier(C); if (a_name == SLANG_ATOM_NULL) - return 0; + RETURN0; name = slang_atom_pool_id(C->atoms, a_name); if (name[0] != '\0' && slang_struct_scope_find(O->structs, a_name, 0) != NULL) { slang_info_log_error(C->L, "%s: duplicate type name.", name); - return 0; + RETURN0; } /* set-up a new struct */ - *st = (slang_struct *) slang_alloc_malloc(sizeof(slang_struct)); + *st = (slang_struct *) _slang_alloc(sizeof(slang_struct)); if (*st == NULL) { slang_info_log_memory(C->L); - return 0; + RETURN0; } if (!slang_struct_construct(*st)) { - slang_alloc_free(*st); + _slang_free(*st); *st = NULL; slang_info_log_memory(C->L); - return 0; + RETURN0; } (**st).a_name = a_name; (**st).structs->outer_scope = O->structs; @@ -392,7 +478,7 @@ parse_struct(slang_parse_ctx * C, slang_output_ctx * O, slang_struct ** st) slang_type_specifier_ctr(&sp); if (!parse_struct_field(C, O, *st, &sp)) { slang_type_specifier_dtr(&sp); - return 0; + RETURN0; } slang_type_specifier_dtr(&sp); } @@ -403,27 +489,69 @@ parse_struct(slang_parse_ctx * C, slang_output_ctx * O, slang_struct ** st) slang_struct *s; O->structs->structs = - (slang_struct *) slang_alloc_realloc(O->structs->structs, - O->structs->num_structs * - sizeof(slang_struct), - (O->structs->num_structs + - 1) * sizeof(slang_struct)); + (slang_struct *) _slang_realloc(O->structs->structs, + O->structs->num_structs + * sizeof(slang_struct), + (O->structs->num_structs + 1) + * sizeof(slang_struct)); if (O->structs->structs == NULL) { slang_info_log_memory(C->L); - return 0; + RETURN0; } s = &O->structs->structs[O->structs->num_structs]; if (!slang_struct_construct(s)) - return 0; + RETURN0; O->structs->num_structs++; if (!slang_struct_copy(s, *st)) - return 0; + RETURN0; } return 1; } +/* invariant qualifer */ +#define TYPE_VARIANT 90 +#define TYPE_INVARIANT 91 + +static int +parse_type_variant(slang_parse_ctx * C, slang_type_variant *variant) +{ + GLuint invariant = *C->I++; + switch (invariant) { + case TYPE_VARIANT: + *variant = SLANG_VARIANT; + return 1; + case TYPE_INVARIANT: + *variant = SLANG_INVARIANT; + return 1; + default: + RETURN0; + } +} + + +/* centroid qualifer */ +#define TYPE_CENTER 95 +#define TYPE_CENTROID 96 + +static int +parse_type_centroid(slang_parse_ctx * C, slang_type_centroid *centroid) +{ + GLuint c = *C->I++; + switch (c) { + case TYPE_CENTER: + *centroid = SLANG_CENTER; + return 1; + case TYPE_CENTROID: + *centroid = SLANG_CENTROID; + return 1; + default: + RETURN0; + } +} + + /* type qualifier */ #define TYPE_QUALIFIER_NONE 0 #define TYPE_QUALIFIER_CONST 1 @@ -436,7 +564,8 @@ parse_struct(slang_parse_ctx * C, slang_output_ctx * O, slang_struct ** st) static int parse_type_qualifier(slang_parse_ctx * C, slang_type_qualifier * qual) { - switch (*C->I++) { + GLuint qualifier = *C->I++; + switch (qualifier) { case TYPE_QUALIFIER_NONE: *qual = SLANG_QUAL_NONE; break; @@ -459,7 +588,7 @@ parse_type_qualifier(slang_parse_ctx * C, slang_type_qualifier * qual) *qual = SLANG_QUAL_FIXEDINPUT; break; default: - return 0; + RETURN0; } return 1; } @@ -491,6 +620,13 @@ parse_type_qualifier(slang_parse_ctx * C, slang_type_qualifier * qual) #define TYPE_SPECIFIER_SAMPLER2DRECTSHADOW 23 #define TYPE_SPECIFIER_STRUCT 24 #define TYPE_SPECIFIER_TYPENAME 25 +#define TYPE_SPECIFIER_MAT23 26 +#define TYPE_SPECIFIER_MAT32 27 +#define TYPE_SPECIFIER_MAT24 28 +#define TYPE_SPECIFIER_MAT42 29 +#define TYPE_SPECIFIER_MAT34 30 +#define TYPE_SPECIFIER_MAT43 31 +#define TYPE_SPECIFIER_COUNT 32 static int parse_type_specifier(slang_parse_ctx * C, slang_output_ctx * O, @@ -545,6 +681,24 @@ parse_type_specifier(slang_parse_ctx * C, slang_output_ctx * O, case TYPE_SPECIFIER_MAT4: spec->type = SLANG_SPEC_MAT4; break; + case TYPE_SPECIFIER_MAT23: + spec->type = SLANG_SPEC_MAT23; + break; + case TYPE_SPECIFIER_MAT32: + spec->type = SLANG_SPEC_MAT32; + break; + case TYPE_SPECIFIER_MAT24: + spec->type = SLANG_SPEC_MAT24; + break; + case TYPE_SPECIFIER_MAT42: + spec->type = SLANG_SPEC_MAT42; + break; + case TYPE_SPECIFIER_MAT34: + spec->type = SLANG_SPEC_MAT34; + break; + case TYPE_SPECIFIER_MAT43: + spec->type = SLANG_SPEC_MAT43; + break; case TYPE_SPECIFIER_SAMPLER1D: spec->type = SLANG_SPEC_SAMPLER1D; break; @@ -572,7 +726,7 @@ parse_type_specifier(slang_parse_ctx * C, slang_output_ctx * O, case TYPE_SPECIFIER_STRUCT: spec->type = SLANG_SPEC_STRUCT; if (!parse_struct(C, O, &spec->_struct)) - return 0; + RETURN0; break; case TYPE_SPECIFIER_TYPENAME: spec->type = SLANG_SPEC_STRUCT; @@ -582,44 +736,159 @@ parse_type_specifier(slang_parse_ctx * C, slang_output_ctx * O, a_name = parse_identifier(C); if (a_name == NULL) - return 0; + RETURN0; stru = slang_struct_scope_find(O->structs, a_name, 1); if (stru == NULL) { slang_info_log_error(C->L, "undeclared type name '%s'", slang_atom_pool_id(C->atoms, a_name)); - return 0; + RETURN0; } - spec->_struct = - (slang_struct *) slang_alloc_malloc(sizeof(slang_struct)); + spec->_struct = (slang_struct *) _slang_alloc(sizeof(slang_struct)); if (spec->_struct == NULL) { slang_info_log_memory(C->L); - return 0; + RETURN0; } if (!slang_struct_construct(spec->_struct)) { - slang_alloc_free(spec->_struct); + _slang_free(spec->_struct); spec->_struct = NULL; - return 0; + RETURN0; } if (!slang_struct_copy(spec->_struct, stru)) - return 0; + RETURN0; } break; default: - return 0; + RETURN0; } return 1; } +#define TYPE_SPECIFIER_NONARRAY 0 +#define TYPE_SPECIFIER_ARRAY 1 + +static int +parse_type_array_size(slang_parse_ctx *C, + slang_output_ctx *O, + GLint *array_len) +{ + GLuint size; + + switch (*C->I++) { + case TYPE_SPECIFIER_NONARRAY: + *array_len = -1; /* -1 = not an array */ + break; + case TYPE_SPECIFIER_ARRAY: + if (!parse_array_len(C, O, &size)) + RETURN0; + *array_len = (GLint) size; + break; + default: + assert(0); + RETURN0; + } + return 1; +} + +#define PRECISION_DEFAULT 0 +#define PRECISION_LOW 1 +#define PRECISION_MEDIUM 2 +#define PRECISION_HIGH 3 + +static int +parse_type_precision(slang_parse_ctx *C, + slang_type_precision *precision) +{ + GLint prec = *C->I++; + switch (prec) { + case PRECISION_DEFAULT: + *precision = SLANG_PREC_DEFAULT; + return 1; + case PRECISION_LOW: + *precision = SLANG_PREC_LOW; + return 1; + case PRECISION_MEDIUM: + *precision = SLANG_PREC_MEDIUM; + return 1; + case PRECISION_HIGH: + *precision = SLANG_PREC_HIGH; + return 1; + default: + RETURN0; + } +} + static int parse_fully_specified_type(slang_parse_ctx * C, slang_output_ctx * O, slang_fully_specified_type * type) { + if (!parse_type_variant(C, &type->variant)) + RETURN0; + + if (!parse_type_centroid(C, &type->centroid)) + RETURN0; + if (!parse_type_qualifier(C, &type->qualifier)) - return 0; + RETURN0; + + if (!parse_type_precision(C, &type->precision)) + RETURN0; + if (!parse_type_specifier(C, O, &type->specifier)) - return 0; + RETURN0; + + if (!parse_type_array_size(C, O, &type->array_len)) + RETURN0; + + if (!O->allow_invariant && type->variant == SLANG_INVARIANT) { + slang_info_log_error(C->L, + "'invariant' keyword not allowed (perhaps set #version 120)"); + RETURN0; + } + + if (!O->allow_centroid && type->centroid == SLANG_CENTROID) { + slang_info_log_error(C->L, + "'centroid' keyword not allowed (perhaps set #version 120)"); + RETURN0; + } + else if (type->centroid == SLANG_CENTROID && + type->qualifier != SLANG_QUAL_VARYING) { + slang_info_log_error(C->L, + "'centroid' keyword only allowed for varying vars"); + RETURN0; + } + + + /* need this? + if (type->qualifier != SLANG_QUAL_VARYING && + type->variant == SLANG_INVARIANT) { + slang_info_log_error(C->L, + "invariant qualifer only allowed for varying vars"); + RETURN0; + } + */ + + if (O->allow_precision) { + if (type->precision == SLANG_PREC_DEFAULT) { + assert(type->specifier.type < TYPE_SPECIFIER_COUNT); + /* use the default precision for this datatype */ + type->precision = O->default_precision[type->specifier.type]; + } + } + else { + /* only default is allowed */ + if (type->precision != SLANG_PREC_DEFAULT) { + slang_info_log_error(C->L, "precision qualifiers not allowed"); + RETURN0; + } + } + + if (!O->allow_array_types && type->array_len >= 0) { + slang_info_log_error(C->L, "first-class array types not allowed"); + RETURN0; + } + return 1; } @@ -686,12 +955,14 @@ parse_fully_specified_type(slang_parse_ctx * C, slang_output_ctx * O, #define OP_FIELD 59 #define OP_POSTINCREMENT 60 #define OP_POSTDECREMENT 61 +#define OP_PRECISION 62 +#define OP_METHOD 63 /** * When parsing a compound production, this function is used to parse the * children. - * For example, a a while-loop compound will have two children, the + * For example, a while-loop compound will have two children, the * while condition expression and the loop body. So, this function will * be called twice to parse those two sub-expressions. * \param C the parsing context @@ -719,14 +990,18 @@ static int parse_statement(slang_parse_ctx * C, slang_output_ctx * O, slang_operation * oper) { + int op; + oper->locals->outer_scope = O->vars; - switch (*C->I++) { + + op = *C->I++; + switch (op) { case OP_BLOCK_BEGIN_NO_NEW_SCOPE: /* parse child statements, do not create new variable scope */ oper->type = SLANG_OPER_BLOCK_NO_NEW_SCOPE; while (*C->I != OP_END) if (!parse_child_operation(C, O, oper, 1)) - return 0; + RETURN0; C->I++; break; case OP_BLOCK_BEGIN_NEW_SCOPE: @@ -738,7 +1013,7 @@ parse_statement(slang_parse_ctx * C, slang_output_ctx * O, o.vars = oper->locals; while (*C->I != OP_END) if (!parse_child_operation(C, &o, oper, 1)) - return 0; + RETURN0; C->I++; } break; @@ -754,22 +1029,33 @@ parse_statement(slang_parse_ctx * C, slang_output_ctx * O, * than one declarators */ if (!parse_declaration(C, O)) - return 0; + RETURN0; if (first_var < O->vars->num_variables) { const unsigned int num_vars = O->vars->num_variables - first_var; unsigned int i; - + assert(oper->num_children == 0); oper->num_children = num_vars; oper->children = slang_operation_new(num_vars); if (oper->children == NULL) { slang_info_log_memory(C->L); - return 0; + RETURN0; } for (i = first_var; i < O->vars->num_variables; i++) { slang_operation *o = &oper->children[i - first_var]; + slang_variable *var = O->vars->variables[i]; o->type = SLANG_OPER_VARIABLE_DECL; o->locals->outer_scope = O->vars; - o->a_id = O->vars->variables[i]->a_name; + o->a_id = var->a_name; + + /* new/someday... + calculate_var_size(C, O, var); + */ + + if (!legal_identifier(o->a_id)) { + slang_info_log_error(C->L, "illegal variable name '%s'", + (char *) o->a_id); + RETURN0; + } } } } @@ -781,10 +1067,10 @@ parse_statement(slang_parse_ctx * C, slang_output_ctx * O, oper->type = SLANG_OPER_ASM; oper->a_id = parse_identifier(C); if (oper->a_id == SLANG_ATOM_NULL) - return 0; + RETURN0; while (*C->I != OP_END) { if (!parse_child_operation(C, O, oper, 0)) - return 0; + RETURN0; } C->I++; break; @@ -800,21 +1086,21 @@ parse_statement(slang_parse_ctx * C, slang_output_ctx * O, case OP_RETURN: oper->type = SLANG_OPER_RETURN; if (!parse_child_operation(C, O, oper, 0)) - return 0; + RETURN0; break; case OP_EXPRESSION: oper->type = SLANG_OPER_EXPRESSION; if (!parse_child_operation(C, O, oper, 0)) - return 0; + RETURN0; break; case OP_IF: oper->type = SLANG_OPER_IF; if (!parse_child_operation(C, O, oper, 0)) - return 0; + RETURN0; if (!parse_child_operation(C, O, oper, 1)) - return 0; + RETURN0; if (!parse_child_operation(C, O, oper, 1)) - return 0; + RETURN0; break; case OP_WHILE: { @@ -823,17 +1109,17 @@ parse_statement(slang_parse_ctx * C, slang_output_ctx * O, oper->type = SLANG_OPER_WHILE; o.vars = oper->locals; if (!parse_child_operation(C, &o, oper, 1)) - return 0; + RETURN0; if (!parse_child_operation(C, &o, oper, 1)) - return 0; + RETURN0; } break; case OP_DO: oper->type = SLANG_OPER_DO; if (!parse_child_operation(C, O, oper, 1)) - return 0; + RETURN0; if (!parse_child_operation(C, O, oper, 0)) - return 0; + RETURN0; break; case OP_FOR: { @@ -842,17 +1128,28 @@ parse_statement(slang_parse_ctx * C, slang_output_ctx * O, oper->type = SLANG_OPER_FOR; o.vars = oper->locals; if (!parse_child_operation(C, &o, oper, 1)) - return 0; + RETURN0; if (!parse_child_operation(C, &o, oper, 1)) - return 0; + RETURN0; if (!parse_child_operation(C, &o, oper, 0)) - return 0; + RETURN0; if (!parse_child_operation(C, &o, oper, 1)) - return 0; + RETURN0; + } + break; + case OP_PRECISION: + { + /* set default precision for a type in this scope */ + /* ignored at this time */ + int prec_qual = *C->I++; + int datatype = *C->I++; + (void) prec_qual; + (void) datatype; } break; default: - return 0; + printf("Unexpected operation %d\n", op); + RETURN0; } return 1; } @@ -864,26 +1161,28 @@ handle_nary_expression(slang_parse_ctx * C, slang_operation * op, { unsigned int i; - op->children = - (slang_operation *) slang_alloc_malloc(n * sizeof(slang_operation)); + op->children = slang_operation_new(n); if (op->children == NULL) { slang_info_log_memory(C->L); - return 0; + RETURN0; } op->num_children = n; - for (i = 0; i < n; i++) + for (i = 0; i < n; i++) { + slang_operation_destruct(&op->children[i]); op->children[i] = (*ops)[*total_ops - (n + 1 - i)]; + } + (*ops)[*total_ops - (n + 1)] = (*ops)[*total_ops - 1]; *total_ops -= n; *ops = (slang_operation *) - slang_alloc_realloc(*ops, - (*total_ops + n) * sizeof(slang_operation), - *total_ops * sizeof(slang_operation)); + _slang_realloc(*ops, + (*total_ops + n) * sizeof(slang_operation), + *total_ops * sizeof(slang_operation)); if (*ops == NULL) { slang_info_log_memory(C->L); - return 0; + RETURN0; } return 1; } @@ -897,6 +1196,9 @@ is_constructor_name(const char *name, slang_atom a_name, return slang_struct_scope_find(structs, a_name, 1) != NULL; } +#define FUNCTION_CALL_NONARRAY 0 +#define FUNCTION_CALL_ARRAY 1 + static int parse_expression(slang_parse_ctx * C, slang_output_ctx * O, slang_operation * oper) @@ -911,17 +1213,17 @@ parse_expression(slang_parse_ctx * C, slang_output_ctx * O, /* allocate default operation, becomes a no-op if not used */ ops = (slang_operation *) - slang_alloc_realloc(ops, - num_ops * sizeof(slang_operation), - (num_ops + 1) * sizeof(slang_operation)); + _slang_realloc(ops, + num_ops * sizeof(slang_operation), + (num_ops + 1) * sizeof(slang_operation)); if (ops == NULL) { slang_info_log_memory(C->L); - return 0; + RETURN0; } op = &ops[num_ops]; if (!slang_operation_construct(op)) { slang_info_log_memory(C->L); - return 0; + RETURN0; } num_ops++; op->locals->outer_scope = O->vars; @@ -933,7 +1235,7 @@ parse_expression(slang_parse_ctx * C, slang_output_ctx * O, case OP_PUSH_BOOL: op->type = SLANG_OPER_LITERAL_BOOL; if (!parse_number(C, &number)) - return 0; + RETURN0; op->literal[0] = op->literal[1] = op->literal[2] = @@ -943,7 +1245,7 @@ parse_expression(slang_parse_ctx * C, slang_output_ctx * O, case OP_PUSH_INT: op->type = SLANG_OPER_LITERAL_INT; if (!parse_number(C, &number)) - return 0; + RETURN0; op->literal[0] = op->literal[1] = op->literal[2] = @@ -953,7 +1255,7 @@ parse_expression(slang_parse_ctx * C, slang_output_ctx * O, case OP_PUSH_FLOAT: op->type = SLANG_OPER_LITERAL_FLOAT; if (!parse_float(C, &op->literal[0])) - return 0; + RETURN0; op->literal[1] = op->literal[2] = op->literal[3] = op->literal[0]; @@ -963,37 +1265,37 @@ parse_expression(slang_parse_ctx * C, slang_output_ctx * O, op->type = SLANG_OPER_IDENTIFIER; op->a_id = parse_identifier(C); if (op->a_id == SLANG_ATOM_NULL) - return 0; + RETURN0; break; case OP_SEQUENCE: op->type = SLANG_OPER_SEQUENCE; if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - return 0; + RETURN0; break; case OP_ASSIGN: op->type = SLANG_OPER_ASSIGN; if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - return 0; + RETURN0; break; case OP_ADDASSIGN: op->type = SLANG_OPER_ADDASSIGN; if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - return 0; + RETURN0; break; case OP_SUBASSIGN: op->type = SLANG_OPER_SUBASSIGN; if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - return 0; + RETURN0; break; case OP_MULASSIGN: op->type = SLANG_OPER_MULASSIGN; if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - return 0; + RETURN0; break; case OP_DIVASSIGN: op->type = SLANG_OPER_DIVASSIGN; if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - return 0; + RETURN0; break; /*case OP_MODASSIGN: */ /*case OP_LSHASSIGN: */ @@ -1004,22 +1306,22 @@ parse_expression(slang_parse_ctx * C, slang_output_ctx * O, case OP_SELECT: op->type = SLANG_OPER_SELECT; if (!handle_nary_expression(C, op, &ops, &num_ops, 3)) - return 0; + RETURN0; break; case OP_LOGICALOR: op->type = SLANG_OPER_LOGICALOR; if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - return 0; + RETURN0; break; case OP_LOGICALXOR: op->type = SLANG_OPER_LOGICALXOR; if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - return 0; + RETURN0; break; case OP_LOGICALAND: op->type = SLANG_OPER_LOGICALAND; if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - return 0; + RETURN0; break; /*case OP_BITOR: */ /*case OP_BITXOR: */ @@ -1027,97 +1329,103 @@ parse_expression(slang_parse_ctx * C, slang_output_ctx * O, case OP_EQUAL: op->type = SLANG_OPER_EQUAL; if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - return 0; + RETURN0; break; case OP_NOTEQUAL: op->type = SLANG_OPER_NOTEQUAL; if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - return 0; + RETURN0; break; case OP_LESS: op->type = SLANG_OPER_LESS; if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - return 0; + RETURN0; break; case OP_GREATER: op->type = SLANG_OPER_GREATER; if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - return 0; + RETURN0; break; case OP_LESSEQUAL: op->type = SLANG_OPER_LESSEQUAL; if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - return 0; + RETURN0; break; case OP_GREATEREQUAL: op->type = SLANG_OPER_GREATEREQUAL; if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - return 0; + RETURN0; break; /*case OP_LSHIFT: */ /*case OP_RSHIFT: */ case OP_ADD: op->type = SLANG_OPER_ADD; if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - return 0; + RETURN0; break; case OP_SUBTRACT: op->type = SLANG_OPER_SUBTRACT; if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - return 0; + RETURN0; break; case OP_MULTIPLY: op->type = SLANG_OPER_MULTIPLY; if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - return 0; + RETURN0; break; case OP_DIVIDE: op->type = SLANG_OPER_DIVIDE; if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - return 0; + RETURN0; break; /*case OP_MODULUS: */ case OP_PREINCREMENT: op->type = SLANG_OPER_PREINCREMENT; if (!handle_nary_expression(C, op, &ops, &num_ops, 1)) - return 0; + RETURN0; break; case OP_PREDECREMENT: op->type = SLANG_OPER_PREDECREMENT; if (!handle_nary_expression(C, op, &ops, &num_ops, 1)) - return 0; + RETURN0; break; case OP_PLUS: op->type = SLANG_OPER_PLUS; if (!handle_nary_expression(C, op, &ops, &num_ops, 1)) - return 0; + RETURN0; break; case OP_MINUS: op->type = SLANG_OPER_MINUS; if (!handle_nary_expression(C, op, &ops, &num_ops, 1)) - return 0; + RETURN0; break; case OP_NOT: op->type = SLANG_OPER_NOT; if (!handle_nary_expression(C, op, &ops, &num_ops, 1)) - return 0; + RETURN0; break; /*case OP_COMPLEMENT: */ case OP_SUBSCRIPT: op->type = SLANG_OPER_SUBSCRIPT; if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - return 0; + RETURN0; break; - case OP_CALL: - op->type = SLANG_OPER_CALL; + case OP_METHOD: + op->type = SLANG_OPER_METHOD; + op->a_obj = parse_identifier(C); + if (op->a_obj == SLANG_ATOM_NULL) + RETURN0; + op->a_id = parse_identifier(C); if (op->a_id == SLANG_ATOM_NULL) - return 0; + RETURN0; + while (*C->I != OP_END) if (!parse_child_operation(C, O, op, 0)) - return 0; + RETURN0; C->I++; - +#if 0 + /* don't lookup the method (not yet anyway) */ if (!C->parsing_builtin && !slang_function_scope_find_by_name(O->funs, op->a_id, 1)) { const char *id; @@ -1125,7 +1433,78 @@ parse_expression(slang_parse_ctx * C, slang_output_ctx * O, id = slang_atom_pool_id(C->atoms, op->a_id); if (!is_constructor_name(id, op->a_id, O->structs)) { slang_info_log_error(C->L, "%s: undeclared function name.", id); - return 0; + RETURN0; + } + } +#endif + break; + case OP_CALL: + { + GLboolean array_constructor = GL_FALSE; + GLint array_constructor_size; + + op->type = SLANG_OPER_CALL; + op->a_id = parse_identifier(C); + if (op->a_id == SLANG_ATOM_NULL) + RETURN0; + switch (*C->I++) { + case FUNCTION_CALL_NONARRAY: + /* Nothing to do. */ + break; + case FUNCTION_CALL_ARRAY: + /* Calling an array constructor. For example: + * float[3](1.1, 2.2, 3.3); + */ + if (!O->allow_array_types) { + slang_info_log_error(C->L, + "array constructors not allowed " + "in this GLSL version"); + RETURN0; + } + else { + array_constructor = GL_TRUE; + /* parse the array constructor size */ + slang_operation array_size; + slang_operation_construct(&array_size); + if (!parse_expression(C, O, &array_size)) { + slang_operation_destruct(&array_size); + return GL_FALSE; + } + if (array_size.type != SLANG_OPER_LITERAL_INT) { + slang_info_log_error(C->L, + "constructor array size is not an integer"); + slang_operation_destruct(&array_size); + RETURN0; + } + array_constructor_size = (int) array_size.literal[0]; + slang_operation_destruct(&array_size); + } + break; + default: + assert(0); + RETURN0; + } + while (*C->I != OP_END) + if (!parse_child_operation(C, O, op, 0)) + RETURN0; + C->I++; + + if (array_constructor && + array_constructor_size != op->num_children) { + slang_info_log_error(C->L, "number of parameters to array" + " constructor does not match array size"); + RETURN0; + } + + if (!C->parsing_builtin + && !slang_function_scope_find_by_name(O->funs, op->a_id, 1)) { + const char *id; + + id = slang_atom_pool_id(C->atoms, op->a_id); + if (!is_constructor_name(id, op->a_id, O->structs)) { + slang_info_log_error(C->L, "%s: undeclared function name.", id); + RETURN0; + } } } break; @@ -1133,28 +1512,29 @@ parse_expression(slang_parse_ctx * C, slang_output_ctx * O, op->type = SLANG_OPER_FIELD; op->a_id = parse_identifier(C); if (op->a_id == SLANG_ATOM_NULL) - return 0; + RETURN0; if (!handle_nary_expression(C, op, &ops, &num_ops, 1)) - return 0; + RETURN0; break; case OP_POSTINCREMENT: op->type = SLANG_OPER_POSTINCREMENT; if (!handle_nary_expression(C, op, &ops, &num_ops, 1)) - return 0; + RETURN0; break; case OP_POSTDECREMENT: op->type = SLANG_OPER_POSTDECREMENT; if (!handle_nary_expression(C, op, &ops, &num_ops, 1)) - return 0; + RETURN0; break; default: - return 0; + RETURN0; } } C->I++; - *oper = *ops; - slang_alloc_free(ops); + slang_operation_destruct(oper); + *oper = *ops; /* struct copy */ + _slang_free(ops); return 1; } @@ -1172,17 +1552,21 @@ static int parse_parameter_declaration(slang_parse_ctx * C, slang_output_ctx * O, slang_variable * param) { + int param_qual, precision_qual; + /* parse and validate the parameter's type qualifiers (there can be * two at most) because not all combinations are valid */ if (!parse_type_qualifier(C, ¶m->type.qualifier)) - return 0; - switch (*C->I++) { + RETURN0; + + param_qual = *C->I++; + switch (param_qual) { case PARAM_QUALIFIER_IN: if (param->type.qualifier != SLANG_QUAL_CONST && param->type.qualifier != SLANG_QUAL_NONE) { slang_info_log_error(C->L, "Invalid type qualifier."); - return 0; + RETURN0; } break; case PARAM_QUALIFIER_OUT: @@ -1190,7 +1574,7 @@ parse_parameter_declaration(slang_parse_ctx * C, slang_output_ctx * O, param->type.qualifier = SLANG_QUAL_OUT; else { slang_info_log_error(C->L, "Invalid type qualifier."); - return 0; + RETURN0; } break; case PARAM_QUALIFIER_INOUT: @@ -1198,19 +1582,44 @@ parse_parameter_declaration(slang_parse_ctx * C, slang_output_ctx * O, param->type.qualifier = SLANG_QUAL_INOUT; else { slang_info_log_error(C->L, "Invalid type qualifier."); - return 0; + RETURN0; } break; default: - return 0; + RETURN0; } + /* parse precision qualifier (lowp, mediump, highp */ + precision_qual = *C->I++; + /* ignored at this time */ + (void) precision_qual; + /* parse parameter's type specifier and name */ if (!parse_type_specifier(C, O, ¶m->type.specifier)) - return 0; + RETURN0; + if (!parse_type_array_size(C, O, ¶m->type.array_len)) + RETURN0; param->a_name = parse_identifier(C); if (param->a_name == SLANG_ATOM_NULL) - return 0; + RETURN0; + + /* first-class array + */ + if (param->type.array_len >= 0) { + slang_type_specifier p; + + slang_type_specifier_ctr(&p); + if (!slang_type_specifier_copy(&p, ¶m->type.specifier)) { + slang_type_specifier_dtr(&p); + RETURN0; + } + if (!convert_to_array(C, param, &p)) { + slang_type_specifier_dtr(&p); + RETURN0; + } + slang_type_specifier_dtr(&p); + param->array_len = param->type.array_len; + } /* if the parameter is an array, parse its size (the size must be * explicitly defined @@ -1218,24 +1627,29 @@ parse_parameter_declaration(slang_parse_ctx * C, slang_output_ctx * O, if (*C->I++ == PARAMETER_ARRAY_PRESENT) { slang_type_specifier p; + if (param->type.array_len >= 0) { + slang_info_log_error(C->L, "multi-dimensional arrays not allowed"); + RETURN0; + } slang_type_specifier_ctr(&p); if (!slang_type_specifier_copy(&p, ¶m->type.specifier)) { slang_type_specifier_dtr(&p); - return GL_FALSE; + RETURN0; } if (!convert_to_array(C, param, &p)) { slang_type_specifier_dtr(&p); - return GL_FALSE; + RETURN0; } slang_type_specifier_dtr(&p); if (!parse_array_len(C, O, ¶m->array_len)) - return GL_FALSE; + RETURN0; } +#if 0 /* calculate the parameter size */ if (!calculate_var_size(C, O, param)) - return GL_FALSE; - + RETURN0; +#endif /* TODO: allocate the local address here? */ return 1; } @@ -1327,50 +1741,60 @@ parse_operator_name(slang_parse_ctx * C) slang_atom_pool_atom(C->atoms, operator_names[i].o_name); if (atom == SLANG_ATOM_NULL) { slang_info_log_memory(C->L); - return 0; + RETURN0; } C->I++; return atom; } } - return 0; + RETURN0; } + static int parse_function_prototype(slang_parse_ctx * C, slang_output_ctx * O, slang_function * func) { + GLuint functype; /* parse function type and name */ if (!parse_fully_specified_type(C, O, &func->header.type)) - return 0; - switch (*C->I++) { + RETURN0; + + functype = *C->I++; + switch (functype) { case FUNCTION_ORDINARY: func->kind = SLANG_FUNC_ORDINARY; func->header.a_name = parse_identifier(C); if (func->header.a_name == SLANG_ATOM_NULL) - return 0; + RETURN0; break; case FUNCTION_CONSTRUCTOR: func->kind = SLANG_FUNC_CONSTRUCTOR; if (func->header.type.specifier.type == SLANG_SPEC_STRUCT) - return 0; + RETURN0; func->header.a_name = slang_atom_pool_atom(C->atoms, slang_type_specifier_type_to_string (func->header.type.specifier.type)); if (func->header.a_name == SLANG_ATOM_NULL) { slang_info_log_memory(C->L); - return 0; + RETURN0; } break; case FUNCTION_OPERATOR: func->kind = SLANG_FUNC_OPERATOR; func->header.a_name = parse_operator_name(C); if (func->header.a_name == SLANG_ATOM_NULL) - return 0; + RETURN0; break; default: - return 0; + RETURN0; + } + + if (!legal_identifier(func->header.a_name)) { + slang_info_log_error(C->L, "illegal function name '%s'", + (char *) func->header.a_name); + RETURN0; } /* parse function parameters */ @@ -1378,10 +1802,10 @@ parse_function_prototype(slang_parse_ctx * C, slang_output_ctx * O, slang_variable *p = slang_variable_scope_grow(func->parameters); if (!p) { slang_info_log_memory(C->L); - return 0; + RETURN0; } if (!parse_parameter_declaration(C, O, p)) - return 0; + RETURN0; } /* if the function returns a value, append a hidden __retVal 'out' @@ -1415,20 +1839,19 @@ parse_function_definition(slang_parse_ctx * C, slang_output_ctx * O, slang_output_ctx o = *O; if (!parse_function_prototype(C, O, func)) - return 0; + RETURN0; /* create function's body operation */ - func->body = - (slang_operation *) slang_alloc_malloc(sizeof(slang_operation)); + func->body = (slang_operation *) _slang_alloc(sizeof(slang_operation)); if (func->body == NULL) { slang_info_log_memory(C->L); - return 0; + RETURN0; } if (!slang_operation_construct(func->body)) { - slang_alloc_free(func->body); + _slang_free(func->body); func->body = NULL; slang_info_log_memory(C->L); - return 0; + RETURN0; } /* to parse the body the parse context is modified in order to @@ -1437,7 +1860,7 @@ parse_function_definition(slang_parse_ctx * C, slang_output_ctx * O, C->global_scope = GL_FALSE; o.vars = func->parameters; if (!parse_statement(C, &o, func->body)) - return 0; + RETURN0; C->global_scope = GL_TRUE; return 1; @@ -1457,7 +1880,7 @@ initialize_global(slang_assemble_ctx * A, slang_variable * var) /* put the variable into operation's scope */ op_id.locals->variables = - (slang_variable **) slang_alloc_malloc(sizeof(slang_variable *)); + (slang_variable **) _slang_alloc(sizeof(slang_variable *)); if (op_id.locals->variables == NULL) { slang_operation_destruct(&op_id); return GL_FALSE; @@ -1473,7 +1896,7 @@ initialize_global(slang_assemble_ctx * A, slang_variable * var) } op_assign.type = SLANG_OPER_ASSIGN; op_assign.children = - (slang_operation *) slang_alloc_malloc(2 * sizeof(slang_operation)); + (slang_operation *) _slang_alloc(2 * sizeof(slang_operation)); if (op_assign.children == NULL) { slang_operation_destruct(&op_assign); op_id.locals->num_variables = 0; @@ -1488,7 +1911,7 @@ initialize_global(slang_assemble_ctx * A, slang_variable * var) /* carefully destroy the operations */ op_assign.num_children = 0; - slang_alloc_free(op_assign.children); + _slang_free(op_assign.children); op_assign.children = NULL; slang_operation_destruct(&op_assign); op_id.locals->num_variables = 0; @@ -1520,64 +1943,109 @@ parse_init_declarator(slang_parse_ctx * C, slang_output_ctx * O, const slang_fully_specified_type * type) { slang_variable *var; + slang_atom a_name; /* empty init declatator (without name, e.g. "float ;") */ if (*C->I++ == VARIABLE_NONE) return 1; + a_name = parse_identifier(C); + + /* check if name is already in this scope */ + if (_slang_locate_variable(O->vars, a_name, GL_FALSE)) { + slang_info_log_error(C->L, + "declaration of '%s' conflicts with previous declaration", + (char *) a_name); + RETURN0; + } + /* make room for the new variable and initialize it */ var = slang_variable_scope_grow(O->vars); if (!var) { slang_info_log_memory(C->L); - return 0; + RETURN0; } - /* copy the declarator qualifier type, parse the identifier */ + /* copy the declarator type qualifier/etc info, parse the identifier */ var->type.qualifier = type->qualifier; - var->a_name = parse_identifier(C); + var->type.centroid = type->centroid; + var->type.precision = type->precision; + var->type.variant = type->variant; + var->a_name = a_name; if (var->a_name == SLANG_ATOM_NULL) - return 0; + RETURN0; switch (*C->I++) { case VARIABLE_NONE: /* simple variable declarator - just copy the specifier */ - if (!slang_type_specifier_copy(&var->type.specifier, &type->specifier)) - return 0; + if (type->array_len >= 0) { + /* The type was something like "float[4]" */ + convert_to_array(C, var, &type->specifier); + var->array_len = type->array_len; + } + else { + if (!slang_type_specifier_copy(&var->type.specifier, &type->specifier)) + RETURN0; + } break; case VARIABLE_INITIALIZER: /* initialized variable - copy the specifier and parse the expression */ - if (!slang_type_specifier_copy(&var->type.specifier, &type->specifier)) - return 0; + if (type->array_len >= 0) { + /* The type was something like "float[4]" */ + convert_to_array(C, var, &type->specifier); + var->array_len = type->array_len; + } + else { + if (!slang_type_specifier_copy(&var->type.specifier, &type->specifier)) + RETURN0; + } var->initializer = - (slang_operation *) slang_alloc_malloc(sizeof(slang_operation)); + (slang_operation *) _slang_alloc(sizeof(slang_operation)); if (var->initializer == NULL) { slang_info_log_memory(C->L); - return 0; + RETURN0; } if (!slang_operation_construct(var->initializer)) { - slang_alloc_free(var->initializer); + _slang_free(var->initializer); var->initializer = NULL; slang_info_log_memory(C->L); - return 0; + RETURN0; } if (!parse_expression(C, O, var->initializer)) - return 0; + RETURN0; break; case VARIABLE_ARRAY_UNKNOWN: /* unsized array - mark it as array and copy the specifier to - the array element - */ + * the array element + */ + if (type->array_len >= 0) { + slang_info_log_error(C->L, "multi-dimensional arrays not allowed"); + RETURN0; + } if (!convert_to_array(C, var, &type->specifier)) return GL_FALSE; break; case VARIABLE_ARRAY_EXPLICIT: + if (type->array_len >= 0) { + slang_info_log_error(C->L, "multi-dimensional arrays not allowed"); + RETURN0; + } if (!convert_to_array(C, var, &type->specifier)) return GL_FALSE; if (!parse_array_len(C, O, &var->array_len)) return GL_FALSE; break; default: - return 0; + RETURN0; + } + + /* allocate global address space for a variable with a known size */ + if (C->global_scope + && !(var->type.specifier.type == SLANG_SPEC_ARRAY + && var->array_len == 0)) { + if (!calculate_var_size(C, O, var)) + return GL_FALSE; + var->address = slang_var_pool_alloc(O->global_pool, var->size); } /* emit code for global var decl */ @@ -1589,16 +2057,10 @@ parse_init_declarator(slang_parse_ctx * C, slang_output_ctx * O, A.space.vars = O->vars; A.program = O->program; A.vartable = O->vartable; - _slang_codegen_global_variable(&A, var, C->type); - } - - /* allocate global address space for a variable with a known size */ - if (C->global_scope - && !(var->type.specifier.type == SLANG_SPEC_ARRAY - && var->array_len == 0)) { - if (!calculate_var_size(C, O, var)) - return GL_FALSE; - var->address = slang_var_pool_alloc(O->global_pool, var->size); + A.log = C->L; + A.curFuncEndLabel = NULL; + if (!_slang_codegen_global_variable(&A, var, C->type)) + RETURN0; } /* initialize global variable */ @@ -1611,7 +2073,7 @@ parse_init_declarator(slang_parse_ctx * C, slang_output_ctx * O, A.space.structs = O->structs; A.space.vars = O->vars; if (!initialize_global(&A, var)) - return 0; + RETURN0; } } return 1; @@ -1628,17 +2090,17 @@ parse_init_declarator_list(slang_parse_ctx * C, slang_output_ctx * O) /* parse the fully specified type, common to all declarators */ if (!slang_fully_specified_type_construct(&type)) - return 0; + RETURN0; if (!parse_fully_specified_type(C, O, &type)) { slang_fully_specified_type_destruct(&type); - return 0; + RETURN0; } /* parse declarators, pass-in the parsed type */ do { if (!parse_init_declarator(C, O, &type)) { slang_fully_specified_type_destruct(&type); - return 0; + RETURN0; } } while (*C->I++ == DECLARATOR_NEXT); @@ -1686,11 +2148,11 @@ parse_function(slang_parse_ctx * C, slang_output_ctx * O, int definition, if (found_func == NULL) { /* New function, add it to the function list */ O->funs->functions = - (slang_function *) slang_alloc_realloc(O->funs->functions, - O->funs->num_functions * - sizeof(slang_function), - (O->funs->num_functions + - 1) * sizeof(slang_function)); + (slang_function *) _slang_realloc(O->funs->functions, + O->funs->num_functions + * sizeof(slang_function), + (O->funs->num_functions + 1) + * sizeof(slang_function)); if (O->funs->functions == NULL) { slang_info_log_memory(C->L); slang_function_destruct(&parsed_func); @@ -1732,20 +2194,6 @@ parse_function(slang_parse_ctx * C, slang_output_ctx * O, int definition, *parsed_func_ret = found_func; } - /* assemble the parsed function */ - { - slang_assemble_ctx A; - - A.atoms = C->atoms; - A.space.funcs = O->funs; - A.space.structs = O->structs; - A.space.vars = O->vars; - A.program = O->program; - A.vartable = O->vartable; - A.log = C->L; - - _slang_codegen_function(&A, *parsed_func_ret); - } return GL_TRUE; } @@ -1759,35 +2207,131 @@ parse_declaration(slang_parse_ctx * C, slang_output_ctx * O) switch (*C->I++) { case DECLARATION_INIT_DECLARATOR_LIST: if (!parse_init_declarator_list(C, O)) - return 0; + RETURN0; break; case DECLARATION_FUNCTION_PROTOTYPE: { slang_function *dummy_func; if (!parse_function(C, O, 0, &dummy_func)) - return 0; + RETURN0; } break; default: - return 0; + RETURN0; } return 1; } -/* external declaration */ +static int +parse_default_precision(slang_parse_ctx * C, slang_output_ctx * O) +{ + int precision, type; + + if (!O->allow_precision) { + slang_info_log_error(C->L, "syntax error at \"precision\""); + RETURN0; + } + + precision = *C->I++; + switch (precision) { + case PRECISION_LOW: + case PRECISION_MEDIUM: + case PRECISION_HIGH: + /* OK */ + break; + default: + _mesa_problem(NULL, "unexpected precision %d at %s:%d\n", + precision, __FILE__, __LINE__); + RETURN0; + } + + type = *C->I++; + switch (type) { + case TYPE_SPECIFIER_FLOAT: + case TYPE_SPECIFIER_INT: + case TYPE_SPECIFIER_SAMPLER1D: + case TYPE_SPECIFIER_SAMPLER2D: + case TYPE_SPECIFIER_SAMPLER3D: + case TYPE_SPECIFIER_SAMPLERCUBE: + case TYPE_SPECIFIER_SAMPLER1DSHADOW: + case TYPE_SPECIFIER_SAMPLER2DSHADOW: + case TYPE_SPECIFIER_SAMPLER2DRECT: + case TYPE_SPECIFIER_SAMPLER2DRECTSHADOW: + /* OK */ + break; + default: + _mesa_problem(NULL, "unexpected type %d at %s:%d\n", + type, __FILE__, __LINE__); + RETURN0; + } + + assert(type < TYPE_SPECIFIER_COUNT); + O->default_precision[type] = precision; + + return 1; +} + + +/** + * Initialize the default precision for all types. + * XXX this info isn't used yet. + */ +static void +init_default_precision(slang_output_ctx *O, slang_unit_type type) +{ + GLuint i; + for (i = 0; i < TYPE_SPECIFIER_COUNT; i++) { +#if FEATURE_es2_glsl + O->default_precision[i] = PRECISION_LOW; +#else + O->default_precision[i] = PRECISION_HIGH; +#endif + } + + if (type == SLANG_UNIT_VERTEX_SHADER) { + O->default_precision[TYPE_SPECIFIER_FLOAT] = PRECISION_HIGH; + O->default_precision[TYPE_SPECIFIER_INT] = PRECISION_HIGH; + } + else { + O->default_precision[TYPE_SPECIFIER_INT] = PRECISION_MEDIUM; + } +} + + +static int +parse_invariant(slang_parse_ctx * C, slang_output_ctx * O) +{ + if (O->allow_invariant) { + slang_atom *a = parse_identifier(C); + /* XXX not doing anything with this var yet */ + /*printf("ID: %s\n", (char*) a);*/ + return a ? 1 : 0; + } + else { + slang_info_log_error(C->L, "syntax error at \"invariant\""); + RETURN0; + } +} + + +/* external declaration or default precision specifier */ #define EXTERNAL_NULL 0 #define EXTERNAL_FUNCTION_DEFINITION 1 #define EXTERNAL_DECLARATION 2 +#define DEFAULT_PRECISION 3 +#define INVARIANT_STMT 4 + static GLboolean parse_code_unit(slang_parse_ctx * C, slang_code_unit * unit, - struct gl_program *program) + struct gl_shader *shader) { GET_CURRENT_CONTEXT(ctx); slang_output_ctx o; GLboolean success; GLuint maxRegs; + slang_function *mainFunc = NULL; if (unit->type == SLANG_UNIT_FRAGMENT_BUILTIN || unit->type == SLANG_UNIT_FRAGMENT_SHADER) { @@ -1804,10 +2348,31 @@ parse_code_unit(slang_parse_ctx * C, slang_code_unit * unit, o.structs = &unit->structs; o.vars = &unit->vars; o.global_pool = &unit->object->varpool; - o.program = program; + o.program = shader ? shader->Program : NULL; o.vartable = _slang_new_var_table(maxRegs); _slang_push_var_table(o.vartable); + /* allow 'invariant' keyword? */ +#if FEATURE_es2_glsl + o.allow_invariant = GL_TRUE; +#else + o.allow_invariant = (C->version >= 120) ? GL_TRUE : GL_FALSE; +#endif + + /* allow 'centroid' keyword? */ + o.allow_centroid = (C->version >= 120) ? GL_TRUE : GL_FALSE; + + /* allow 'lowp/mediump/highp' keywords? */ +#if FEATURE_es2_glsl + o.allow_precision = GL_TRUE; +#else + o.allow_precision = (C->version >= 120) ? GL_TRUE : GL_FALSE; +#endif + init_default_precision(&o, unit->type); + + /* allow 'float[]' keyword? */ + o.allow_array_types = (C->version >= 120) ? GL_TRUE : GL_FALSE; + /* parse individual functions and declarations */ while (*C->I != EXTERNAL_NULL) { switch (*C->I++) { @@ -1815,11 +2380,22 @@ parse_code_unit(slang_parse_ctx * C, slang_code_unit * unit, { slang_function *func; success = parse_function(C, &o, 1, &func); + if (success && + _mesa_strcmp((char *) func->header.a_name, "main") == 0) { + /* found main() */ + mainFunc = func; + } } break; case EXTERNAL_DECLARATION: success = parse_declaration(C, &o); break; + case DEFAULT_PRECISION: + success = parse_default_precision(C, &o); + break; + case INVARIANT_STMT: + success = parse_invariant(C, &o); + break; default: success = GL_FALSE; } @@ -1832,15 +2408,41 @@ parse_code_unit(slang_parse_ctx * C, slang_code_unit * unit, } C->I++; + if (mainFunc) { + /* assemble (generate code) for main() */ + slang_assemble_ctx A; + + A.atoms = C->atoms; + A.space.funcs = o.funs; + A.space.structs = o.structs; + A.space.vars = o.vars; + A.program = o.program; + A.vartable = o.vartable; + A.log = C->L; + + /* main() takes no parameters */ + if (mainFunc->param_count > 0) { + slang_info_log_error(A.log, "main() takes no arguments"); + return GL_FALSE; + } + + _slang_codegen_function(&A, mainFunc); + + shader->Main = GL_TRUE; /* this shader defines main() */ + } + _slang_pop_var_table(o.vartable); + _slang_delete_var_table(o.vartable); + return GL_TRUE; } static GLboolean compile_binary(const byte * prod, slang_code_unit * unit, + GLuint version, slang_unit_type type, slang_info_log * infolog, slang_code_unit * builtin, slang_code_unit * downlink, - struct gl_program *program) + struct gl_shader *shader) { slang_parse_ctx C; @@ -1853,6 +2455,7 @@ compile_binary(const byte * prod, slang_code_unit * unit, C.global_scope = GL_TRUE; C.atoms = &unit->object->atompool; C.type = type; + C.version = version; if (!check_revision(&C)) return GL_FALSE; @@ -1864,26 +2467,36 @@ compile_binary(const byte * prod, slang_code_unit * unit, } /* parse translation unit */ - return parse_code_unit(&C, unit, program); + return parse_code_unit(&C, unit, shader); } static GLboolean compile_with_grammar(grammar id, const char *source, slang_code_unit * unit, slang_unit_type type, slang_info_log * infolog, slang_code_unit * builtin, - struct gl_program *program) + struct gl_shader *shader) { byte *prod; GLuint size, start, version; slang_string preprocessed; + GLuint maxVersion; + +#if FEATURE_ARB_shading_language_120 + maxVersion = 120; +#elif FEATURE_es2_glsl + maxVersion = 100; +#else + maxVersion = 110; +#endif /* First retrieve the version number. */ if (!_slang_preprocess_version(source, &version, &start, infolog)) return GL_FALSE; - if (version > 110) { + if (version > maxVersion) { slang_info_log_error(infolog, - "language version specified is not supported."); + "language version %.2f is not supported.", + version * 0.01); return GL_FALSE; } @@ -1921,9 +2534,9 @@ compile_with_grammar(grammar id, const char *source, slang_code_unit * unit, slang_string_free(&preprocessed); /* Syntax is okay - translate it to internal representation. */ - if (!compile_binary(prod, unit, type, infolog, builtin, + if (!compile_binary(prod, unit, version, type, infolog, builtin, &builtin[SLANG_BUILTIN_TOTAL - 1], - program)) { + shader)) { grammar_alloc_free(prod); return GL_FALSE; } @@ -1939,6 +2552,14 @@ static const byte slang_core_gc[] = { #include "library/slang_core_gc.h" }; +static const byte slang_120_core_gc[] = { +#include "library/slang_120_core_gc.h" +}; + +static const byte slang_120_fragment_gc[] = { +#include "library/slang_builtin_120_fragment_gc.h" +}; + static const byte slang_common_builtin_gc[] = { #include "library/slang_common_builtin_gc.h" }; @@ -1954,9 +2575,10 @@ static const byte slang_vertex_builtin_gc[] = { static GLboolean compile_object(grammar * id, const char *source, slang_code_object * object, slang_unit_type type, slang_info_log * infolog, - struct gl_program *program) + struct gl_shader *shader) { slang_code_unit *builtins = NULL; + GLuint base_version = 110; /* load GLSL grammar */ *id = grammar_load_from_text((const byte *) (slang_shader_syn)); @@ -1984,28 +2606,58 @@ compile_object(grammar * id, const char *source, slang_code_object * object, /* compile core functionality first */ if (!compile_binary(slang_core_gc, &object->builtin[SLANG_BUILTIN_CORE], + base_version, SLANG_UNIT_FRAGMENT_BUILTIN, infolog, NULL, NULL, NULL)) return GL_FALSE; +#if FEATURE_ARB_shading_language_120 + if (!compile_binary(slang_120_core_gc, + &object->builtin[SLANG_BUILTIN_120_CORE], + 120, + SLANG_UNIT_FRAGMENT_BUILTIN, infolog, + NULL, &object->builtin[SLANG_BUILTIN_CORE], NULL)) + return GL_FALSE; +#endif + /* compile common functions and variables, link to core */ if (!compile_binary(slang_common_builtin_gc, &object->builtin[SLANG_BUILTIN_COMMON], +#if FEATURE_ARB_shading_language_120 + 120, +#else + base_version, +#endif SLANG_UNIT_FRAGMENT_BUILTIN, infolog, NULL, - &object->builtin[SLANG_BUILTIN_CORE], NULL)) +#if FEATURE_ARB_shading_language_120 + &object->builtin[SLANG_BUILTIN_120_CORE], +#else + &object->builtin[SLANG_BUILTIN_CORE], +#endif + NULL)) return GL_FALSE; /* compile target-specific functions and variables, link to common */ if (type == SLANG_UNIT_FRAGMENT_SHADER) { if (!compile_binary(slang_fragment_builtin_gc, &object->builtin[SLANG_BUILTIN_TARGET], + base_version, SLANG_UNIT_FRAGMENT_BUILTIN, infolog, NULL, &object->builtin[SLANG_BUILTIN_COMMON], NULL)) return GL_FALSE; +#if FEATURE_ARB_shading_language_120 + if (!compile_binary(slang_120_fragment_gc, + &object->builtin[SLANG_BUILTIN_TARGET], + 120, + SLANG_UNIT_FRAGMENT_BUILTIN, infolog, NULL, + &object->builtin[SLANG_BUILTIN_COMMON], NULL)) + return GL_FALSE; +#endif } else if (type == SLANG_UNIT_VERTEX_SHADER) { if (!compile_binary(slang_vertex_builtin_gc, &object->builtin[SLANG_BUILTIN_TARGET], + base_version, SLANG_UNIT_VERTEX_BUILTIN, infolog, NULL, &object->builtin[SLANG_BUILTIN_COMMON], NULL)) return GL_FALSE; @@ -2022,7 +2674,7 @@ compile_object(grammar * id, const char *source, slang_code_object * object, /* compile the actual shader - pass-in built-in library for external shader */ return compile_with_grammar(*id, source, &object->unit, type, infolog, - builtins, program); + builtins, shader); } @@ -2031,16 +2683,21 @@ compile_shader(GLcontext *ctx, slang_code_object * object, slang_unit_type type, slang_info_log * infolog, struct gl_shader *shader) { - struct gl_program *program = shader->Programs[0]; GLboolean success; grammar id = 0; - assert(program); +#if 0 /* for debug */ + _mesa_printf("********* COMPILE SHADER ***********\n"); + _mesa_printf("%s\n", shader->Source); + _mesa_printf("************************************\n"); +#endif + + assert(shader->Program); _slang_code_object_dtr(object); _slang_code_object_ctr(object); - success = compile_object(&id, shader->Source, object, type, infolog, program); + success = compile_object(&id, shader->Source, object, type, infolog, shader); if (id != 0) grammar_destroy(id); if (!success) @@ -2067,21 +2724,23 @@ _slang_compile(GLcontext *ctx, struct gl_shader *shader) type = SLANG_UNIT_FRAGMENT_SHADER; } - /* XXX temporary hack */ - if (!shader->Programs) { + if (!shader->Source) + return GL_FALSE; + + ctx->Shader.MemPool = _slang_new_mempool(1024*1024); + + shader->Main = GL_FALSE; + + if (!shader->Program) { GLenum progTarget; if (shader->Type == GL_VERTEX_SHADER) progTarget = GL_VERTEX_PROGRAM_ARB; else progTarget = GL_FRAGMENT_PROGRAM_ARB; - shader->Programs - = (struct gl_program **) malloc(sizeof(struct gl_program*)); - shader->Programs[0] = _mesa_new_program(ctx, progTarget, 1); - shader->NumPrograms = 1; - - shader->Programs[0]->Parameters = _mesa_new_parameter_list(); - shader->Programs[0]->Varying = _mesa_new_parameter_list(); - shader->Programs[0]->Attributes = _mesa_new_parameter_list(); + shader->Program = ctx->Driver.NewProgram(ctx, progTarget, 1); + shader->Program->Parameters = _mesa_new_parameter_list(); + shader->Program->Varying = _mesa_new_parameter_list(); + shader->Program->Attributes = _mesa_new_parameter_list(); } slang_info_log_construct(&info_log); @@ -2107,6 +2766,24 @@ _slang_compile(GLcontext *ctx, struct gl_shader *shader) slang_info_log_destruct(&info_log); _slang_code_object_dtr(&obj); + _slang_delete_mempool((slang_mempool *) ctx->Shader.MemPool); + ctx->Shader.MemPool = NULL; + + /* remove any reads of output registers */ +#if 0 + printf("Pre-remove output reads:\n"); + _mesa_print_program(shader->Program); +#endif + _mesa_remove_output_reads(shader->Program, PROGRAM_OUTPUT); + if (shader->Type == GL_VERTEX_SHADER) { + /* and remove writes to varying vars in vertex programs */ + _mesa_remove_output_reads(shader->Program, PROGRAM_VARYING); + } +#if 0 + printf("Post-remove output reads:\n"); + _mesa_print_program(shader->Program); +#endif + return success; }