Package ch.njol.skript.lang.function

Source Code of ch.njol.skript.lang.function.Functions$FunctionData

/*
*   This file is part of Skript.
*
*  Skript is free software: you can redistribute it and/or modify
*  it under the terms of the GNU General Public License as published by
*  the Free Software Foundation, either version 3 of the License, or
*  (at your option) any later version.
*
*  Skript is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
*
*  You should have received a copy of the GNU General Public License
*  along with Skript.  If not, see <http://www.gnu.org/licenses/>.
*
*
* Copyright 2011-2013 Peter Güttinger
*
*/

package ch.njol.skript.lang.function;

import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.eclipse.jdt.annotation.Nullable;

import ch.njol.skript.Skript;
import ch.njol.skript.SkriptAPIException;
import ch.njol.skript.classes.ClassInfo;
import ch.njol.skript.config.SectionNode;
import ch.njol.skript.lang.ParseContext;
import ch.njol.skript.lang.SkriptParser;
import ch.njol.skript.registrations.Classes;
import ch.njol.skript.util.Utils;
import ch.njol.util.NonNullPair;
import ch.njol.util.StringUtils;

/**
* @author Peter Güttinger
*/
public abstract class Functions {
  private Functions() {}
 
  final static class FunctionData {
    final Function<?> function;
    final Collection<FunctionReference<?>> calls = new ArrayList<FunctionReference<?>>();
   
    public FunctionData(final Function<?> function) {
      this.function = function;
    }
  }
 
  @Nullable
  public static ScriptFunction<?> currentFunction = null;
 
  final static Map<String, FunctionData> functions = new HashMap<String, FunctionData>();
 
  public final static void registerFunction(final JavaFunction<?> function) {
    Skript.checkAcceptRegistrations();
    if (!function.name.matches(functionNamePattern))
      throw new SkriptAPIException("Invalid function name '" + function.name + "'");
    if (functions.containsKey(function.name))
      throw new SkriptAPIException("Duplicate function " + function.name);
    functions.put(function.name, new FunctionData(function));
  }
 
  final static void registerCaller(final FunctionReference<?> r) {
    final FunctionData d = functions.get(r.functionName);
    assert d != null;
    d.calls.add(r);
  }
 
  public final static String functionNamePattern = "[\\p{IsAlphabetic}_]+";
 
  @SuppressWarnings("null")
  private final static Pattern functionPattern = Pattern.compile("function (" + functionNamePattern + ")\\((.*)\\)(?: :: (.+))?", Pattern.CASE_INSENSITIVE),
      paramPattern = Pattern.compile("\\s*(.+?)\\s*:\\s*(.+?)(?:\\s*=\\s*(.+))?\\s*");
 
  @SuppressWarnings("unchecked")
  @Nullable
  public final static Function<?> loadFunction(final SectionNode node) {
    final String definition = node.getKey();
    assert definition != null;
    final Matcher m = functionPattern.matcher(definition);
    if (!m.matches())
      return error("Invalid function definition. Please check for typos and that the function's name only contains letters and underscores. Refer to the documentation for more information.");
    final String name = "" + m.group(1);
    final String args = m.group(2);
    final String returnType = m.group(3);
    final List<Parameter<?>> params = new ArrayList<Parameter<?>>();
    int j = 0;
    for (int i = 0; i <= args.length(); i = SkriptParser.next(args, i, ParseContext.DEFAULT)) {
      if (i == -1)
        return error("Invalid text/variables/parentheses in the arguments of this function");
      if (i == args.length() || args.charAt(i) == ',') {
        final String arg = args.substring(j, i);
        final Matcher n = paramPattern.matcher(arg);
        if (!n.matches())
          return error("The " + StringUtils.fancyOrderNumber(params.size() + 1) + " argument's definition is invalid. It should look like 'name: type' or 'name: type = default value'.");
        final String paramName = "" + n.group(1);
        for (final Parameter<?> p : params) {
          if (p.name.toLowerCase(Locale.ENGLISH).equals(paramName.toLowerCase(Locale.ENGLISH)))
            return error("Each argument's name must be unique, but the name '" + paramName + "' occurs at least twice.");
        }
        ClassInfo<?> c;
        c = Classes.getClassInfoFromUserInput("" + n.group(2));
        final NonNullPair<String, Boolean> pl = Utils.getEnglishPlural("" + n.group(2));
        if (c == null)
          c = Classes.getClassInfoFromUserInput(pl.getFirst());
        if (c == null)
          return error("Cannot recognise the type '" + n.group(2) + "'");
        final Parameter<?> p = Parameter.newInstance(paramName, c, !pl.getSecond(), n.group(3));
        if (p == null)
          return null;
        params.add(p);
       
        j = i + 1;
      }
      if (i == args.length())
        break;
    }
    ClassInfo<?> c;
    final NonNullPair<String, Boolean> p;
    if (returnType == null) {
      c = null;
      p = null;
    } else {
      c = Classes.getClassInfoFromUserInput("" + returnType);
      p = Utils.getEnglishPlural("" + returnType);
      if (c == null)
        c = Classes.getClassInfoFromUserInput(p.getFirst());
      if (c == null) {
        Skript.error("Cannot recognise the type '" + returnType + "'");
        return null;
      }
    }
   
    if (Skript.debug() || node.debug())
      Skript.debug("function " + name + "(" + StringUtils.join(params, ", ") + ")" + (c != null && p != null ? " :: " + Utils.toEnglishPlural(c.getCodeName(), p.getSecond()) : "") + ":");
   
    @SuppressWarnings("null")
    final Function<?> f = new ScriptFunction<Object>(name, params.toArray(new Parameter[params.size()]), node, (ClassInfo<Object>) c, p == null ? false : !p.getSecond());
//    functions.put(name, new FunctionData(f)); // in constructor
    return f;
  }
 
  @Nullable
  private final static Function<?> error(final String error) {
    Skript.error(error);
    return null;
  }
 
  @Nullable
  public final static Function<?> getFunction(final String name) {
    final FunctionData d = functions.get(name);
    if (d == null)
      return null;
    return d.function;
  }
 
  private final static Collection<FunctionReference<?>> toValidate = new ArrayList<FunctionReference<?>>();
 
  /**
   * Remember to call {@link #validateFunctions()} after calling this
   *
   * @param script
   * @return
   */
  public final static int clearFunctions(final File script) {
    int r = 0;
    final Iterator<FunctionData> iter = functions.values().iterator();
    while (iter.hasNext()) {
      final FunctionData d = iter.next();
      if (d.function instanceof ScriptFunction && script.equals(((ScriptFunction<?>) d.function).trigger.getScript())) {
        iter.remove();
        r++;
        for (final FunctionReference<?> c : d.calls)
          toValidate.add(c);
      }
    }
    return r;
  }
 
  public final static void validateFunctions() {
    for (final FunctionReference<?> c : toValidate)
      c.validateFunction(false);
    toValidate.clear();
  }
 
  public final static void clearFunctions() {
    functions.clear();
  }
 
}
TOP

Related Classes of ch.njol.skript.lang.function.Functions$FunctionData

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.