1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.millscript.millscript.conf.functions;
22
23 import org.millscript.commons.alert.alerts.Fault;
24 import org.millscript.millscript.alert.Alerts;
25 import org.millscript.millscript.functions.Function;
26 import org.millscript.millscript.vm.Machine;
27 import org.millscript.millscript.vm.Package;
28
29 import java.lang.reflect.Constructor;
30 import java.lang.reflect.InvocationTargetException;
31
32
33 /**
34 * This class implements the configuration function <code>AddFunction</code>.
35 */
36 public class AddFunctionFunction extends Function {
37
38 /**
39 * The package we should add functions to.
40 */
41 private Package pack;
42
43 /**
44 * Constructs a new add function function, to add a function to the given
45 * package.
46 *
47 * @param p the package we should add functions to
48 */
49 public AddFunctionFunction( final Package p ) {
50 this.pack = p;
51 }
52
53 /**
54 * @see org.millscript.millscript.functions.Function#apply(org.millscript.millscript.vm.Machine, int)
55 */
56 @Override
57 @SuppressWarnings("unchecked")
58 public void apply( Machine mc, int nargs ) {
59 checkNargs( mc, 2, nargs );
60 final String functionClassName = mc.popString();
61 final String functionName = mc.popString();
62 try {
63
64 final Class< ? > functionClass = Class.forName( functionClassName );
65
66 if ( Function.class.isAssignableFrom( functionClass ) ) {
67
68 final Function function = this.constructFunction( (Class< Function >) functionClass );
69
70 pack.bindConst( functionName, function );
71 } else {
72
73 throw new Fault(
74 "A function must inherit from the Function class"
75 ).culprit( "class", functionClass ).mishap();
76 }
77 } catch ( ClassNotFoundException ex ) {
78 throw(
79 Alerts.parse(
80 "Function Class not found",
81 "Ensure function class is available in a classes folder"
82 ).culprit( "class", functionClassName ).mishap()
83 );
84 }
85 }
86
87 /**
88 * Returns a new instance of the specified function class.
89 *
90 * @param functionClass the <code>Function</code> class to make a new
91 * instance of.
92 * @return a new instance of the specified <code>Function</code> class
93 */
94 public Function constructFunction( final Class< Function > functionClass ) {
95 try {
96 try {
97
98
99 Constructor< Function > c = functionClass.getConstructor( Package.class );
100
101 return c.newInstance( this.pack );
102 } catch ( NoSuchMethodException ex ) {
103 try {
104 Constructor< Function > c = functionClass.getConstructor();
105
106 return c.newInstance();
107 } catch ( NoSuchMethodException ex2 ) {
108 throw new Fault(
109 "Could not construct function - need an empty or single(Package) arg constructor"
110 ).culprit( "class", functionClass ).setParentThrowable( ex2 ).mishap();
111 }
112 }
113
114 } catch ( ExceptionInInitializerError ex ) {
115 throw new Fault(
116 "Could not construct function - unexpected failure in a static initialiser"
117 ).culprit( "class", functionClass ).setParentThrowable( ex ).mishap();
118 } catch ( IllegalAccessException ex ) {
119 throw new Fault(
120 "Could not construct function - illegal access to constructor"
121 ).culprit( "class", functionClass ).setParentThrowable( ex ).mishap();
122 } catch ( IllegalArgumentException ex ) {
123 throw new Fault(
124 "Could not construct function - illegal argument for constructor"
125 ).culprit( "class", functionClass ).setParentThrowable( ex ).mishap();
126 } catch ( InstantiationException ex ) {
127 throw new Fault(
128 "Could not construct function - abstract class cannot be constructed"
129 ).culprit( "class", functionClass ).setParentThrowable( ex ).mishap();
130 } catch ( InvocationTargetException ex ) {
131 throw new Fault(
132 "Could not construct function - constructor threw an exception"
133 ).culprit(
134 "class",
135 functionClass
136 ).culprit(
137 "exception",
138 ex.getCause()
139 ).setParentThrowable( ex ).mishap();
140 } catch ( SecurityException ex ) {
141 throw new Fault(
142 "Could not construct function - access to constructor denied"
143 ).culprit( "class", functionClass ).setParentThrowable( ex ).mishap();
144 }
145 }
146
147 }