// make a property args from the this accessor sig and kind public FuncInfo propertySig(final String accessorName) { FuncInfo fi = null; if (accessorName.equals("set")) { // remove the last argument from the set accessor Debug.Assert( +_paramTypes.length > 0, "a set accessor must have at least one argument (the value arg)"); fi = new FuncInfo(this); // copy final int numPropArgs = _paramTypes.length - 1; final TypeSpec[] pTypes = new TypeSpec[numPropArgs]; for (int i = 0; i < numPropArgs; i++) { pTypes[i] = _paramTypes[i]; } final String[] pNames = new String[numPropArgs]; for (int i = 0; i < numPropArgs; i++) { pNames[i] = _paramNames[i]; } final Object[] pDefaults = new Object[numPropArgs]; for (int i = 0; i < numPropArgs; i++) { pDefaults[i] = _paramDefaults[i]; } final boolean[] pHasDefault = new boolean[numPropArgs]; for (int i = 0; i < numPropArgs; i++) { pHasDefault[i] = _paramHasDefault[i]; } fi._paramNames = pNames; fi._paramTypes = pTypes; fi._paramDefaults = pDefaults; fi._paramHasDefault = pHasDefault; } else if (accessorName.equals("get")) { // property args are the same as the get accessor args, no change fi = new FuncInfo(this); // copy } else { Debug.Assert(false, "invalid accessor kind name (should be 'get' or 'set'"); } return fi; }
// compare for equality, ignoring return types // NB: doens't consider param names or default values public boolean equalsParams(final FuncInfo f) { if (f == null) { return false; } if (f.numArgs() != numArgs()) { return false; } if (f.numRequiredArgs() != numRequiredArgs()) { return false; } for (int a = 0; a < numArgs(); a++) { if (!_paramTypes[a].equals(f._paramTypes[a])) { return false; } } return true; }
public static TypeSpec propertyTypeFromAccessor( final String accessorName, final FuncInfo accessorSig) { if (accessorName.equals("get")) { return accessorSig._returnType; } else if (accessorName.equals("set")) { return accessorSig._paramTypes[accessorSig.numArgs() - 1]; } else { Debug.Assert(false, "invalid accessor name"); } return null; }
// can this func be called using a call with signature callSig? // if callSig.returnType is any, then ignore return type compatibility // (NB: this doesn't consider implicit argument conversions, use // TypeManager.isMatchingFunc() for that) public boolean callCompatible(final FuncInfo callSig) { Debug.Assert(callSig != null); if (callSig.numArgs() < numRequiredArgs()) { return false; // not enough args } if (callSig.numArgs() > numArgs()) { return false; // too many args } // check types for (int a = 0; a < callSig.numArgs(); a++) { if (!_paramTypes[a].equals(callSig._paramTypes[a])) { return false; } } if (callSig.getReturnType() != null) { if (!callSig.getReturnType().equals(TypeSpec.typeOf("any"))) { if (!_returnType.equals(callSig.getReturnType())) { return false; } } } return true; }
// make a property accessor signature from this property args and the // property type public FuncInfo accessorSig(final String accessorName, final TypeSpec propertyType) { FuncInfo fi = null; if (accessorName.equals("set")) { // add the propertyType as an extra // parameter named 'value' fi = new FuncInfo(); final int numPropArgs = _paramTypes.length; final TypeSpec[] pTypes = new TypeSpec[numPropArgs + 1]; for (int i = 0; i < numPropArgs; i++) { pTypes[i] = _paramTypes[i]; } pTypes[numPropArgs] = propertyType; final String[] pNames = new String[numPropArgs + 1]; for (int i = 0; i < numPropArgs; i++) { pNames[i] = _paramNames[i]; } pNames[numPropArgs] = "value"; final Object[] pDefaults = new Object[numPropArgs + 1]; for (int i = 0; i < numPropArgs; i++) { pDefaults[i] = _paramDefaults[i]; } pDefaults[numPropArgs] = null; final boolean[] pHasDefault = new boolean[numPropArgs + 1]; for (int i = 0; i < numPropArgs; i++) { pHasDefault[i] = _paramHasDefault[i]; } pHasDefault[numPropArgs] = false; fi._paramNames = pNames; fi._paramTypes = pTypes; fi._paramDefaults = pDefaults; fi._paramHasDefault = pHasDefault; } else if (accessorName.equals("get")) { // set the returnType to the // propertyType fi = new FuncInfo(this); fi._returnType = propertyType; } else { Debug.Assert(false, "invalid accessor kind name (should be 'get' or 'set'"); } return fi; }
// convert the args for a call with signature callSig that is compatible // with this // to exactly the types this func expects (including filling in defaults if // possible) // throws on arg type or number mismatch public Object[] convertParameters( final FuncInfo callSig, Object[] args, final boolean externCall) { if (args == null) { args = new Object[0]; } Debug.Assert(callSig != null); Debug.Assert(callSig.numArgs() == args.length, "supplied arg count must match callSig"); // if (externCall) //!!! // Debug.WriteLine("Warning: FuncInfo.convertParameters() - externCall being ignored // (unimplemented)"); if (numRequiredArgs() > callSig.numArgs()) { ScigolTreeParser.semanticError( callSig.getDefinitionLocation(), "not enough arguments for function " + this + " in call with signature " + callSig); } if (callSig.numArgs() > numArgs()) { ScigolTreeParser.semanticError( callSig.getDefinitionLocation(), "too many arguments for function " + this + " in call with signature " + callSig); } final Object[] convertedArgs = new Object[numArgs()]; // for each formal param for (int a = 0; a < numArgs(); a++) { if (a < callSig.numArgs()) { // if param supplied Object arg = ((args[a] instanceof Value) ? (((Value) args[a]).getValue()) : args[a]); // convert from Value if // necessary TypeSpec argType = TypeSpec.typeOf(arg); if (!argType.isAny()) { // implicit conversion from any always // exists // does an implicit conversion from the argType to the // parameter type exist? if (!TypeManager.existsImplicitConversion(argType, _paramTypes[a], new Value(arg))) { ScigolTreeParser.semanticError( callSig.getDefinitionLocation(), "argument " + a + " (" + _paramNames[a] + ") to func with signature " + this + " is of type '" + argType + "' which is incompatible with parameter type '" + _paramTypes[a] + "'"); } } else { arg = TypeSpec.unwrapAny(arg); argType = TypeSpec.typeOf(arg); } // conversion final Value convertedArg = TypeManager.performImplicitConversion(argType, _paramTypes[a], new Value(arg)); if (convertedArg == null) { ScigolTreeParser.semanticError( callSig.getDefinitionLocation(), "argument " + a + " (" + _paramNames[a] + ") to func with signature " + this + " is of type '" + argType + "' which cannot be converted into the required parameter type '" + _paramTypes[a] + "'"); } convertedArgs[a] = convertedArg.getValue(); } else { // not supplied // do we have a default value? if (!_paramHasDefault[a]) { ScigolTreeParser.semanticError( callSig.getDefinitionLocation(), "in call to function " + this + ", no argument was supplied for parameter " + _paramNames[a] + " (which has no default)"); } // use default convertedArgs[a] = _paramDefaults[a]; } } // for each param return convertedArgs; }