void Handle_set_error_from_Error(Handle* handle, const Error* error) { rassert(error != NULL); rassert(Error_is_set(error)); Error_copy(&null_error, error); if (handle != NULL) Error_copy(&handle->error, error); return; }
void Handle_set_validation_error_from_Error(Handle* handle, const Error* error) { rassert(handle != NULL); rassert(error != NULL); rassert(Error_get_type(error) == ERROR_FORMAT); Error_copy(&handle->validation_error, error); return; }
Value* Value_copy(const Value* val) { Value* ret; switch(val->type) { case VAL_INT: ret = ValInt(val->ival); break; case VAL_REAL: ret = ValReal(val->rval); break; case VAL_FRAC: ret = ValFrac(Fraction_copy(val->frac)); break; case VAL_EXPR: ret = ValExpr(BinOp_copy(val->expr)); break; case VAL_CALL: ret = ValCall(FuncCall_copy(val->call)); break; case VAL_UNARY: ret = ValUnary(UnOp_copy(val->term)); break; case VAL_VAR: ret = ValVar(val->name); break; case VAL_VEC: ret = ValVec(Vector_copy(val->vec)); break; case VAL_NEG: /* Shouldn't be reached, but so easy to code */ ret = ValNeg(); break; case VAL_ERR: ret = ValErr(Error_copy(val->err)); break; default: typeError("Unknown value type: %d.", val->type); ret = NULL; break; } return ret; }
void Handle_set_error_( Handle* handle, Error_type type, Error_delay_type delay_type, const char* file, int line, const char* func, const char* message, ...) { rassert(type < ERROR_COUNT_); rassert(delay_type == ERROR_IMMEDIATE || delay_type == ERROR_VALIDATION); rassert(file != NULL); rassert(line >= 0); rassert(func != NULL); rassert(message != NULL); Error* error = ERROR_AUTO; va_list args; va_start(args, message); Error_set_desc_va_list(error, type, file, line, func, message, args); va_end(args); if (delay_type == ERROR_IMMEDIATE) Error_copy(&null_error, error); if (handle != NULL) { if (delay_type == ERROR_IMMEDIATE) Error_copy(&handle->error, error); else if (delay_type == ERROR_VALIDATION) Error_copy(&handle->validation_error, error); else rassert(false); } return; }
static Expression* parseExpr(const char** expr) { Variable* var; Value* val = Value_parse(expr, 0, 0); if(val->type == VAL_END) { var = VarErr(ignoreError()); } else if(val->type == VAL_ERR) { Error* err = Error_copy(val->err); var = VarErr(err); } else { var = VarValue(NULL, Value_copy(val)); } Value_free(val); return Expression_new(var); }
int kqt_Handle_validate(kqt_Handle handle) { check_handle(handle, 0); Handle* h = get_handle(handle); check_data_is_valid(h, 0); // Check error from set_data if (Error_is_set(&h->validation_error)) { Error_copy(&h->error, &h->validation_error); Error_copy(&null_error, &h->validation_error); h->data_is_valid = false; return 0; } // Check album if (h->module->album_is_existent) { const Track_list* tl = h->module->track_list; set_invalid_if( tl == NULL, "Album does not contain a track list"); set_invalid_if( Track_list_get_len(tl) == 0, "Album has no tracks"); } // Check songs for (int i = 0; i < KQT_SONGS_MAX; ++i) { if (!Song_table_get_existent(h->module->songs, i)) continue; // Check for orphans const Track_list* tl = h->module->track_list; set_invalid_if( !h->module->album_is_existent || tl == NULL, "Module contains song %d but no album", i); bool found = false; for (int k = 0; k < Track_list_get_len(tl); ++k) { if (Track_list_get_song_index(tl, k) == i) { found = true; break; } } set_invalid_if(!found, "Song %d is not included in the album", i); // Check for empty songs const Order_list* ol = h->module->order_lists[i]; set_invalid_if( ol == NULL || Order_list_get_len(ol) == 0, "Song %d does not contain systems", i); // Check for missing pattern instances for (int system = 0; system < Order_list_get_len(ol); ++system) { const Pat_inst_ref* piref = Order_list_get_pat_inst_ref(ol, system); Pattern* pat = Pat_table_get(h->module->pats, piref->pat); set_invalid_if( !Pat_table_get_existent(h->module->pats, piref->pat) || pat == NULL || !Pattern_get_inst_existent(pat, piref->inst), "Missing pattern instance [%" PRId16 ", %" PRId16 "]", piref->pat, piref->inst); } } // Check for nonexistent songs in the track list if (h->module->album_is_existent) { const Track_list* tl = h->module->track_list; rassert(tl != NULL); for (uint16_t i = 0; i < Track_list_get_len(tl); ++i) { set_invalid_if( !Song_table_get_existent(h->module->songs, Track_list_get_song_index(tl, i)), "Album includes nonexistent song %d", i); } } // Check existing patterns for (int i = 0; i < KQT_PATTERNS_MAX; ++i) { if (!Pat_table_get_existent(h->module->pats, i)) continue; Pattern* pat = Pat_table_get(h->module->pats, i); set_invalid_if( pat == NULL, "Pattern %d exists but contains no data", i); bool pattern_has_instance = false; for (int k = 0; k < KQT_PAT_INSTANCES_MAX; ++k) { if (Pattern_get_inst_existent(pat, k)) { // Mark found instance pattern_has_instance = true; // Check that the instance is used in the album set_invalid_if( !h->module->album_is_existent, "Pattern instance [%d, %d] exists but no album" " is present", i, k); bool instance_found = false; const Track_list* tl = h->module->track_list; rassert(tl != NULL); for (int track = 0; track < Track_list_get_len(tl); ++track) { const int song_index = Track_list_get_song_index(tl, track); if (!Song_table_get_existent(h->module->songs, song_index)) continue; const Order_list* ol = h->module->order_lists[song_index]; rassert(ol != NULL); for (int system = 0; system < Order_list_get_len(ol); ++system) { const Pat_inst_ref* piref = Order_list_get_pat_inst_ref(ol, system); if (piref->pat == i && piref->inst == k) { set_invalid_if( instance_found, "Duplicate occurrence of pattern instance" " [%d, %d]", i, k); instance_found = true; } } } set_invalid_if( !instance_found, "Pattern instance [%d, %d] exists but is not used", i, k); } } set_invalid_if( !pattern_has_instance, "Pattern %d exists but has no instances", i); } // Check controls if (h->module->au_map != NULL) { set_invalid_if( !Input_map_is_valid(h->module->au_map, h->module->au_controls), "Control map uses nonexistent controls"); } // Check that all connections are between existing ports { char err_msg[DEVICE_CONNECTION_ERROR_LENGTH_MAX] = ""; // Audio units Au_table* au_table = Module_get_au_table(h->module); for (int au_index = 0; au_index < KQT_AUDIO_UNITS_MAX; ++au_index) { const Audio_unit* au = Au_table_get(au_table, au_index); if ((au != NULL) && Device_is_existent((const Device*)au)) { const Connections* au_conns = Audio_unit_get_connections(au); if (au_conns != NULL) { set_invalid_if( !Connections_check_connections(au_conns, err_msg), "Error in connections of device au_%02x: %s", au_index, err_msg); } // Audio unit effects for (int sub_au_index = 0; sub_au_index < KQT_AUDIO_UNITS_MAX; ++sub_au_index) { const Audio_unit* sub_au = Audio_unit_get_au(au, sub_au_index); if ((sub_au != NULL) && Device_is_existent((const Device*)sub_au)) { const Connections* conns = Audio_unit_get_connections(sub_au); if (conns != NULL) { set_invalid_if( !Connections_check_connections(conns, err_msg), "Error in connections of device" " au_%02x/au_%02x: %s", au_index, sub_au_index, err_msg); } } } } } // Top-level connections if (h->module->connections != NULL) { set_invalid_if( !Connections_check_connections( Module_get_connections(h->module), err_msg), "Error in top-level connections: %s", err_msg); } } // Check that audio unit types are allowed in their contexts { Au_table* au_table = Module_get_au_table(h->module); for (int au_index = 0; au_index < KQT_AUDIO_UNITS_MAX; ++au_index) { const Audio_unit* au = Au_table_get(au_table, au_index); if ((au != NULL) && Device_is_existent((const Device*)au)) { const Au_type au_type = Audio_unit_get_type(au); for (int sub_au_index = 0; sub_au_index < KQT_AUDIO_UNITS_MAX; ++sub_au_index) { const Audio_unit* sub_au = Audio_unit_get_au(au, sub_au_index); if ((sub_au != NULL) && Device_is_existent((const Device*)sub_au)) { if (au_type == AU_TYPE_INSTRUMENT) { const Au_type sub_au_type = Audio_unit_get_type(sub_au); set_invalid_if( sub_au_type == AU_TYPE_INSTRUMENT, "Audio unit au_%02x is an instrument but contains" " another instrument", au_index); } set_invalid_if( au_type == AU_TYPE_EFFECT, "Audio unit au_%02x is an effect but contains" " another audio unit", au_index); } } } } } // Data is OK h->data_is_validated = true; // Update connections if needed if (h->update_connections) { if (!Handle_update_connections(h)) return 0; h->update_connections = false; } return 1; }
int kqt_Handle_validate(kqt_Handle handle) { check_handle(handle, 0); Handle* h = get_handle(handle); check_data_is_valid(h, 0); // Check error from set_data if (Error_is_set(&h->validation_error)) { Error_copy(&h->error, &h->validation_error); Error_copy(&null_error, &h->validation_error); h->data_is_valid = false; return 0; } // Check album if (h->module->album_is_existent) { const Track_list* tl = h->module->track_list; set_invalid_if( tl == NULL, "Album does not contain a track list"); set_invalid_if( Track_list_get_len(tl) == 0, "Album has no tracks"); } // Check songs for (int i = 0; i < KQT_SONGS_MAX; ++i) { if (!Song_table_get_existent(h->module->songs, i)) continue; // Check for orphans const Track_list* tl = h->module->track_list; set_invalid_if( !h->module->album_is_existent || tl == NULL, "Module contains song %d but no album", i); bool found = false; for (size_t k = 0; k < Track_list_get_len(tl); ++k) { if (Track_list_get_song_index(tl, k) == i) { found = true; break; } } set_invalid_if(!found, "Song %d is not included in the album", i); // Check for empty songs const Order_list* ol = h->module->order_lists[i]; set_invalid_if( ol == NULL || Order_list_get_len(ol) == 0, "Song %d does not contain systems", i); // Check for missing pattern instances for (size_t system = 0; system < Order_list_get_len(ol); ++system) { const Pat_inst_ref* piref = Order_list_get_pat_inst_ref(ol, system); Pattern* pat = Pat_table_get(h->module->pats, piref->pat); set_invalid_if( !Pat_table_get_existent(h->module->pats, piref->pat) || pat == NULL || !Pattern_get_inst_existent(pat, piref->inst), "Missing pattern instance [%" PRId16 ", %" PRId16 "]", piref->pat, piref->inst); } } // Check for nonexistent songs in the track list if (h->module->album_is_existent) { const Track_list* tl = h->module->track_list; assert(tl != NULL); for (size_t i = 0; i < Track_list_get_len(tl); ++i) { set_invalid_if( !Song_table_get_existent(h->module->songs, Track_list_get_song_index(tl, i)), "Album includes nonexistent song %d", i); } } // Check existing patterns for (int i = 0; i < KQT_PATTERNS_MAX; ++i) { if (!Pat_table_get_existent(h->module->pats, i)) continue; Pattern* pat = Pat_table_get(h->module->pats, i); set_invalid_if( pat == NULL, "Pattern %d exists but contains no data", i); bool pattern_has_instance = false; for (int k = 0; k < KQT_PAT_INSTANCES_MAX; ++k) { if (Pattern_get_inst_existent(pat, k)) { // Mark found instance pattern_has_instance = true; // Check that the instance is used in the album set_invalid_if( !h->module->album_is_existent, "Pattern instance [%d, %d] exists but no album" " is present", i, k); bool instance_found = false; const Track_list* tl = h->module->track_list; assert(tl != NULL); for (size_t track = 0; track < Track_list_get_len(tl); ++track) { const int song_index = Track_list_get_song_index(tl, track); if (!Song_table_get_existent( h->module->songs, song_index)) continue; const Order_list* ol = h->module->order_lists[song_index]; assert(ol != NULL); for (size_t system = 0; system < Order_list_get_len(ol); ++system) { const Pat_inst_ref* piref = Order_list_get_pat_inst_ref( ol, system); if (piref->pat == i && piref->inst == k) { set_invalid_if( instance_found, "Duplicate occurrence of pattern instance" " [%d, %d]", i, k); instance_found = true; } } } set_invalid_if( !instance_found, "Pattern instance [%d, %d] exists but is not used", i, k); } } set_invalid_if( !pattern_has_instance, "Pattern %d exists but has no instances", i); } // Check controls if (h->module->ins_map != NULL) { set_invalid_if( !Input_map_is_valid(h->module->ins_map, h->module->ins_controls), "Control map uses nonexistent controls"); } h->data_is_validated = true; return 1; }
Expression* Expression_parse(const char** expr) { Expression* ret = NULL; Variable* var; Value* val; const char* equals = strchr(*expr, '='); if(equals == NULL) { /* No assignment, just a plain expression. */ return parseExpr(expr); } /* There is an assignment */ /* First, parse the right side of the assignment */ equals++; val = Value_parse(&equals, 0, 0); if(val->type == VAL_ERR) { /* A parse error occurred */ var = VarErr(Error_copy(val->err)); Value_free(val); return Expression_new(var); } if(val->type == VAL_END) { /* Empty input */ Value_free(val); var = VarErr(earlyEnd()); return Expression_new(var); } /* Now parse the left side */ char* name = nextToken(expr); if(name == NULL) { Value_free(val); var = VarErr(syntaxError("No variable to assign to.")); return Expression_new(var); } trimSpaces(expr); if(**expr == '(') { /* Defining a function */ (*expr)++; /* Array of argument names */ unsigned size = 2; char** args = fmalloc(size * sizeof(*args)); unsigned len = 0; /* Add each argument name to the array */ char* arg = nextToken(expr); if(arg == NULL && **expr != ')') { /* Invalid character */ Value_free(val); free(args); free(name); var = VarErr(badChar(**expr)); return Expression_new(var); } trimSpaces(expr); if(arg == NULL) { /* Empty parameter list means function with no args */ free(args); args = NULL; len = 0; } else { /* Loop through each argument in the list */ while(**expr == ',' || **expr == ')') { args[len++] = arg; if(**expr == ')') break; (*expr)++; /* Expand argument array if it's too small */ if(len >= size) { size *= 2; args = frealloc(args, size * sizeof(*args)); } arg = nextToken(expr); if(arg == NULL) { /* Invalid character */ Value_free(val); free(name); /* Free argument names and return */ unsigned i; for(i = 0; i < len; i++) { free(args[i]); } free(args); var = VarErr(badChar(**expr)); return Expression_new(var); } trimSpaces(expr); } } if(**expr != ')') { /* Invalid character inside argument name list */ Value_free(val); free(name); /* Free argument names and return */ unsigned i; for(i = 0; i < len; i++) { free(args[i]); } free(args); var = VarErr(badChar(**expr)); return Expression_new(var); } /* Skip closing parenthesis */ (*expr)++; trimSpaces(expr); if(**expr != '=') { Value_free(val); free(name); unsigned i; for(i = 0; i < len; i++) { free(args[i]); } free(args); var = VarErr(badChar(**expr)); return Expression_new(var); } /* Construct function and return it */ Function* func = Function_new(len, args, val); var = VarFunc(name, func); free(name); ret = Expression_new(var); } else { /* Defining a variable */ if(**expr != '=') { /* In-place manipulation */ BINTYPE bin = BinOp_nextType(expr, 0, 0); /* Still not an equals sign means invalid character */ if(**expr != '=') { Value_free(val); free(name); var = VarErr(badChar(**expr)); return Expression_new(var); } val = ValExpr(BinOp_new(bin, ValVar(name), val)); } var = VarValue(name, val); free(name); ret = Expression_new(var); } return ret; }