Exemple #1
0
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;
}
Exemple #2
0
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;
}
Exemple #3
0
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;
}
Exemple #4
0
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;
}
Exemple #5
0
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);
}
Exemple #6
0
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;
}
Exemple #7
0
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;
}
Exemple #8
0
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;
}