Skip to content

Commit 99e9204

Browse files
committed
[[ Foundation ]] Added MCErrorCreateAndThrow API - allows creation of an error ref with info dictionary and throwing in one call.
[[ Foundation ]] Implemented message formatting in MCError - the 'message' string can now contain %{…} where '…' is taken to be a key in the info dictionary. [[ Foundation ]] Added MCAutoErrorRef.
1 parent 56e9b28 commit 99e9204

5 files changed

Lines changed: 151 additions & 18 deletions

File tree

libfoundation/include/foundation-auto.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ typedef MCAutoValueRefBase<MCDataRef> MCAutoDataRef;
7373
typedef MCAutoValueRefBase<MCProperListRef> MCAutoProperListRef;
7474
typedef MCAutoValueRefBase<MCTypeInfoRef> MCAutoTypeInfoRef;
7575
typedef MCAutoValueRefBase<MCRecordRef> MCAutoRecordRef;
76+
typedef MCAutoValueRefBase<MCErrorRef> MCAutoErrorRef;
7677

7778
////////////////////////////////////////////////////////////////////////////////
7879

libfoundation/include/foundation.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2474,6 +2474,11 @@ MC_DLLEXPORT MCValueRef MCErrorGetTargetAtLevel(MCErrorRef error, uindex_t level
24742474
MC_DLLEXPORT uindex_t MCErrorGetRowAtLevel(MCErrorRef error, uindex_t row);
24752475
MC_DLLEXPORT uindex_t MCErrorGetColumnAtLevel(MCErrorRef error, uindex_t column);
24762476

2477+
// Create and throw an error. The arguments are used to build the info dictionary.
2478+
// They should be a sequence of pairs (const char *key, MCValueRef value), and finish
2479+
// with nil.
2480+
MC_DLLEXPORT bool MCErrorCreateAndThrow(MCTypeInfoRef typeinfo, ...);
2481+
24772482
// Throw the given error code (local to the current thread).
24782483
MC_DLLEXPORT bool MCErrorThrow(MCErrorRef error);
24792484

@@ -2490,7 +2495,8 @@ MC_DLLEXPORT MCErrorRef MCErrorPeek(void);
24902495
MC_DLLEXPORT bool MCErrorThrowOutOfMemory(void);
24912496

24922497
// Throw a generic runtime error (one that hasn't had a class made for it yet).
2493-
MC_DLLEXPORT bool MCErrorThrowGeneric(void);
2498+
// The message argument is optional (nil if no message).
2499+
MC_DLLEXPORT bool MCErrorThrowGeneric(MCStringRef message);
24942500

24952501
////////////////////////////////////////////////////////////////////////////////
24962502
//

libfoundation/src/foundation-error.cpp

Lines changed: 137 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,107 @@ static MCErrorRef s_out_of_memory_error = nil;
3232

3333
////////////////////////////////////////////////////////////////////////////////
3434

35+
static bool MCErrorFormatMessage(MCStringRef p_format, MCArrayRef p_info, MCStringRef& r_message)
36+
{
37+
MCAutoStringRef t_message;
38+
if (!MCStringCreateMutable(0, &t_message))
39+
return false;
40+
41+
uindex_t t_limit;
42+
t_limit = MCStringGetLength(p_format);
43+
44+
uindex_t t_index;
45+
t_index = 0;
46+
while(t_index < t_limit)
47+
{
48+
unichar_t t_char;
49+
t_char = MCStringGetCharAtIndex(p_format, t_index);
50+
51+
// If the sequence is '%{' and there is at least one more char after
52+
// the '%{' then assume it is a key index.
53+
if (t_char == '%' &&
54+
t_index + 2 < t_limit &&
55+
MCStringGetCharAtIndex(p_format, t_index + 1) == '{')
56+
{
57+
MCAutoStringRef t_key_string;
58+
if (!MCStringCreateMutable(0, &t_key_string))
59+
return false;
60+
61+
t_index += 2;
62+
while(t_index < t_limit)
63+
{
64+
t_char = MCStringGetCharAtIndex(p_format, t_index);
65+
if (t_char == '}')
66+
break;
67+
68+
if (!MCStringAppendChar(*t_key_string, t_char))
69+
return false;
70+
71+
t_index += 1;
72+
}
73+
74+
// If it is a well-formed %{...} sequence then process it as a key
75+
// of the info array. Otherwise just append the accumulated string.
76+
if (t_char == '}')
77+
{
78+
MCNewAutoNameRef t_key;
79+
if (!MCNameCreate(*t_key_string, &t_key))
80+
return false;
81+
82+
MCValueRef t_value;
83+
if (p_info != nil &&
84+
MCArrayFetchValue(p_info, false, *t_key, t_value))
85+
{
86+
MCAutoStringRef t_formatted_value;
87+
if (!MCStringFormat(&t_formatted_value, "%@", t_value))
88+
return false;
89+
90+
if (!MCStringAppend(*t_message, *t_formatted_value))
91+
return false;
92+
}
93+
}
94+
else
95+
{
96+
if (!MCStringAppend(*t_message, *t_key_string))
97+
return false;
98+
}
99+
}
100+
else if (t_char == '%' &&
101+
t_index + 1 < t_limit &&
102+
MCStringGetCharAtIndex(p_format, t_index + 1) == '%')
103+
{
104+
if (!MCStringAppendChar(*t_message, '%'))
105+
return false;
106+
107+
t_index += 1;
108+
}
109+
else
110+
{
111+
if (!MCStringAppendChar(*t_message, t_char))
112+
return false;
113+
}
114+
115+
t_index += 1;
116+
}
117+
118+
r_message = MCValueRetain(*t_message);
119+
120+
return true;
121+
}
122+
35123
bool MCErrorCreate(MCTypeInfoRef p_typeinfo, MCArrayRef p_info, MCErrorRef& r_error)
36124
{
37125
__MCError *self;
38126
if (!__MCValueCreate(kMCValueTypeCodeError, self))
39127
return false;
40128

129+
if (!MCErrorFormatMessage(MCErrorTypeInfoGetMessage(p_typeinfo), p_info, self -> message))
130+
{
131+
MCValueRelease(self);
132+
return false;
133+
}
134+
41135
self -> typeinfo = MCValueRetain(p_typeinfo);
42-
self -> message = MCValueRetain(MCErrorTypeInfoGetMessage(p_typeinfo));
43136
if (p_info != nil)
44137
self -> info = MCValueRetain(p_info);
45138

@@ -134,6 +227,46 @@ bool MCErrorIsPending(void)
134227

135228
////////////////////////////////////////////////////////////////////////////////
136229

230+
bool MCErrorCreateAndThrow(MCTypeInfoRef p_error_type, ...)
231+
{
232+
MCAutoArrayRef t_info;
233+
if (!MCArrayCreateMutable(&t_info))
234+
return false;
235+
236+
va_list t_args;
237+
va_start(t_args, p_error_type);
238+
for(;;)
239+
{
240+
const char *t_key;
241+
t_key = va_arg(t_args, const char *);
242+
if (t_key == nil)
243+
break;
244+
245+
MCValueRef t_value;
246+
t_value = va_arg(t_args, MCValueRef);
247+
248+
// If a value is nil, then it means don't include it.
249+
if (t_value == nil)
250+
continue;
251+
252+
MCNewAutoNameRef t_name;
253+
if (!MCNameCreateWithNativeChars((const char_t *)t_key, strlen(t_key), &t_name))
254+
return false;
255+
256+
if (!MCArrayStoreValue(*t_info, true, *t_name, t_value))
257+
return false;
258+
}
259+
va_end(t_args);
260+
261+
MCAutoErrorRef t_error;
262+
if (!MCErrorCreate(p_error_type, *t_info, &t_error))
263+
return false;
264+
265+
return MCErrorThrow(*t_error);
266+
}
267+
268+
////////////////////////////////////////////////////////////////////////////////
269+
137270
bool MCErrorThrowOutOfMemory(void)
138271
{
139272
if (s_out_of_memory_error == nil &&
@@ -150,16 +283,9 @@ bool MCErrorThrowOutOfMemory(void)
150283
return false;
151284
}
152285

153-
bool MCErrorThrowGeneric(void)
286+
bool MCErrorThrowGeneric(MCStringRef p_reason)
154287
{
155-
MCErrorRef t_error;
156-
if (!MCErrorCreate(kMCGenericErrorTypeInfo, nil, t_error))
157-
return false;
158-
159-
MCErrorThrow(t_error);
160-
MCValueRelease(t_error);
161-
162-
return false;
288+
return MCErrorCreateAndThrow(kMCGenericErrorTypeInfo, "reason", p_reason, nil);
163289
}
164290

165291
////////////////////////////////////////////////////////////////////////////////
@@ -198,7 +324,7 @@ bool __MCErrorInitialize(void)
198324
return false;
199325

200326
MCAutoTypeInfoRef t_ge_typeinfo;
201-
if (!MCErrorTypeInfoCreate(MCNAME("runtime"), MCSTR("unknown"), &t_ge_typeinfo))
327+
if (!MCErrorTypeInfoCreate(MCNAME("runtime"), MCSTR("%{reason}"), &t_ge_typeinfo))
202328
return false;
203329
if (!MCNamedTypeInfoCreate(MCNAME("livecode.lang.GenericError"), kMCGenericErrorTypeInfo))
204330
return false;

libfoundation/src/foundation-record.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@ static bool __check_conformance(MCTypeInfoRef p_typeinfo, const MCValueRef *p_va
3131
}
3232

3333
if (x_offset + p_typeinfo -> record . field_count > p_value_count)
34-
return MCErrorThrowGeneric();
34+
return MCErrorThrowGeneric(nil);
3535

3636
for(uindex_t i = 0; i < p_typeinfo -> record . field_count; i++)
3737
if (MCTypeInfoConforms(MCValueGetTypeInfo(p_values[x_offset + i]), p_typeinfo -> record . fields[i] . type))
38-
return MCErrorThrowGeneric();
38+
return MCErrorThrowGeneric(nil);
3939

4040
return true;
4141
}
@@ -225,7 +225,7 @@ static bool __store_value(MCTypeInfoRef p_typeinfo, MCRecordRef self, MCNameRef
225225
if (MCNameIsEqualTo(p_field, t_resolved_typeinfo -> record . fields[i] . name))
226226
{
227227
if (!MCTypeInfoConforms(MCValueGetTypeInfo(p_value), t_resolved_typeinfo -> record . fields[i] . type))
228-
return MCErrorThrowGeneric();
228+
return MCErrorThrowGeneric(nil);
229229

230230
self -> fields[i] = MCValueRetain(p_value);
231231
return true;

libfoundation/src/foundation-typeinfo.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,7 @@ MCTypeInfoRef MCNamedTypeInfoGetBoundTypeInfo(MCTypeInfoRef self)
313313
bool MCNamedTypeInfoBind(MCTypeInfoRef self, MCTypeInfoRef p_target)
314314
{
315315
if (self -> named . typeinfo != nil)
316-
return MCErrorThrowGeneric();
316+
return MCErrorThrowGeneric(nil);
317317

318318
self -> named . typeinfo = MCValueRetain(p_target);
319319

@@ -323,7 +323,7 @@ bool MCNamedTypeInfoBind(MCTypeInfoRef self, MCTypeInfoRef p_target)
323323
bool MCNamedTypeInfoUnbind(MCTypeInfoRef self)
324324
{
325325
if (self -> named . typeinfo == nil)
326-
return MCErrorThrowGeneric();
326+
return MCErrorThrowGeneric(nil);
327327

328328
MCValueRelease(self -> named . typeinfo);
329329
self -> named . typeinfo = nil;
@@ -334,7 +334,7 @@ bool MCNamedTypeInfoUnbind(MCTypeInfoRef self)
334334
bool MCNamedTypeInfoResolve(MCTypeInfoRef self, MCTypeInfoRef& r_bound_type)
335335
{
336336
if (self -> named . typeinfo == nil)
337-
return MCErrorThrowGeneric();
337+
return MCErrorThrowGeneric(nil);
338338

339339
r_bound_type = self -> named . typeinfo;
340340

0 commit comments

Comments
 (0)