1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.millscript.millscript.functions;
23
24 import org.millscript.commons.alert.Alert;
25 import org.millscript.commons.util.EMap;
26 import org.millscript.commons.util.IList;
27 import org.millscript.commons.util.ListIterator;
28 import org.millscript.commons.util.MapIterator;
29 import org.millscript.commons.util.Maplet;
30 import org.millscript.commons.util.map.ELinkedHashMap;
31 import org.millscript.millscript.alert.Alerts;
32 import org.millscript.millscript.tools.CastLibrary;
33 import org.millscript.millscript.vm.Machine;
34
35 /**
36 * This class implements the MillScript <code>mishap</code> function.
37 */
38 public final class MishapFunction extends Function {
39
40 /**
41 * @see org.millscript.millscript.functions.Function#apply(org.millscript.millscript.vm.Machine, int)
42 */
43 @Override
44 public void apply( final Machine mc, final int nargs ) {
45 EMap< Object, Object > map = new ELinkedHashMap< Object, Object >();
46 initialize( mc, nargs, map );
47 String complaint = (String) map.get( "complaint" );
48 map.removeKey( "complaint" );
49 String reason = (String) map.get( "reason" );
50 map.removeKey( "reason" );
51 final Alert alert = Alerts.eval( complaint, reason );
52 MapIterator< Object, Object > it = map.iterator( true );
53 while ( it.hasNext() ) {
54 alert.culprit( CastLibrary.toString( it.nextKey() ), it.currentValue() );
55 }
56 throw(
57 alert.mishap()
58 );
59 }
60
61 /**
62 * Initialises the specified map with the mishaps culprits.
63 *
64 * @param mc the machine to obtain culprit values from
65 * @param nargs the number of culprits/arguments
66 * @param map the map holding a mapping of culprit to explanation
67 * @return the number of culprit left to process
68 */
69 private static int initialize( final Machine mc, final int nargs, final EMap< Object, Object > map ) {
70 if ( nargs >= 1 ) {
71 final Object obj = mc.popObject();
72 final int anonymous = initialize( mc, nargs - 1, map );
73
74 if ( obj instanceof String ) {
75 if ( anonymous == 0 ) {
76 map.insert( "complaint", obj );
77 } else if ( anonymous == 1 ) {
78 map.insert( "reason", obj );
79 } else {
80 throw(
81 Alerts.eval(
82 "Too many unlabelled arguments",
83 "Only the first two are valid"
84 ).culprit( "String", obj ).mishap()
85 );
86 }
87 return anonymous + 1;
88 } else if ( obj instanceof EMap ) {
89 map.insertAll( (EMap< ?, ? >) obj );
90 return anonymous;
91 } else if ( obj instanceof Maplet ) {
92 map.insert( (Maplet< ?, ? >) obj );
93 return anonymous;
94 } else if ( obj instanceof IList ) {
95 ListIterator< ? > it = ((IList) obj).iterator( true );
96 while ( it.hasNext() ) {
97 Object key = it.nextValue();
98 Object val = it.nextValue();
99 map.insert( key, val );
100 }
101 return anonymous;
102 } else {
103 throw(
104 Alerts.eval(
105 "Invalid mishap argument",
106 "Only Strings, Maps, Maplets or Lists allowed"
107 ).culprit( "object", obj ).mishap()
108 );
109 }
110 } else {
111 return 0;
112 }
113 }
114
115 }