Package dtool.parser

Source Code of dtool.parser.DeeParser_Parameters$AmbiguousParameter

/*******************************************************************************
* Copyright (c) 2013, 2013 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*     Bruno Medeiros - initial API and implementation
*******************************************************************************/
package dtool.parser;

import static dtool.util.NewUtils.lazyInitArrayList;
import static melnorme.utilbox.core.Assert.AssertNamespace.assertNotNull;
import static melnorme.utilbox.core.Assert.AssertNamespace.assertTrue;
import static melnorme.utilbox.core.Assert.AssertNamespace.assertUnreachable;
import static melnorme.utilbox.core.CoreUtil.blindCast;

import java.util.ArrayList;

import melnorme.lang.tooling.ast.SourceRange;
import melnorme.utilbox.core.CoreUtil;
import dtool.ast.ASTNode;
import dtool.ast.definitions.CStyleVarArgsParameter;
import dtool.ast.definitions.DefUnit.ProtoDefSymbol;
import dtool.ast.definitions.FunctionParameter;
import dtool.ast.definitions.IFunctionParameter;
import dtool.ast.definitions.IFunctionParameter.FunctionParamAttribKinds;
import dtool.ast.definitions.NamelessParameter;
import dtool.ast.definitions.TemplateAliasParam;
import dtool.ast.definitions.TemplateParameter;
import dtool.ast.definitions.TemplateThisParam;
import dtool.ast.definitions.TemplateTupleParam;
import dtool.ast.definitions.TemplateTypeParam;
import dtool.ast.definitions.TemplateValueParam;
import dtool.ast.expressions.ExpInfix.InfixOpType;
import dtool.ast.expressions.Expression;
import dtool.ast.expressions.Resolvable;
import dtool.ast.references.RefTypeModifier;
import dtool.ast.references.RefTypeModifier.TypeModifierKinds;
import dtool.ast.references.Reference;
import dtool.parser.common.LexElement;
import dtool.util.ArrayView;

public abstract class DeeParser_Parameters extends DeeParser_RefOrExp {

  protected static enum TplOrFnMode { TPL, FN, AMBIG }
 
  /** Helper class to parse function and template parameters */
  public final class DeeParser_RuleParameters {
   
    public TplOrFnMode mode;
    public ArrayList<Object> params;
   
    public DeeParser_RuleParameters(TplOrFnMode mode) {
      this.mode = mode;
    }
   
    public boolean isAmbiguous() {
      return mode == TplOrFnMode.AMBIG;
    }
   
    public DeeParser_RuleParameters parseParameters(ParseHelper parse) {
      return parse(parse, false);
    }
   
    public DeeParser_RuleParameters parse(ParseHelper parse, boolean isOptional) {
      if(parse.consume(DeeTokens.OPEN_PARENS, isOptional, true) == false)
        return this;
      parseParameterList(true);
      parse.consumeRequired(DeeTokens.CLOSE_PARENS);
      return this;
    }
   
    public void parseParameterList(boolean first) {
      params = new ArrayList<Object>();
     
      while(true) {
        Object param = parseParameter(first && lookAhead() != DeeTokens.COMMA);
       
        if(param == null) {
          break;
        }
        params.add(param);
        first = false;
       
        if(tryConsume(DeeTokens.COMMA)) {
          continue;
        }
        break;
      }
    }
   
    public Object parseParameter() {
      return parseParameter(false);
    }
    public Object parseParameter(boolean returnNullOnMissing) {
      ParseHelper parse = new ParseHelper(lookAheadElement());
     
      if(mode != TplOrFnMode.TPL && tryConsume(DeeTokens.TRIPLE_DOT)) {
        setMode(TplOrFnMode.FN);
        return parse.conclude(new CStyleVarArgsParameter());
      }
     
      if(mode != TplOrFnMode.FN && lookAhead() == DeeTokens.KW_ALIAS) {
        setMode(TplOrFnMode.TPL);
        return parseTemplateAliasParameter_start();
      }
     
      if(mode != TplOrFnMode.FN && tryConsume(DeeTokens.KW_THIS)) {
        setMode(TplOrFnMode.TPL);
        ProtoDefSymbol defId = parseDefId();
        return parse.conclude(new TemplateThisParam(defId));
      }
     
      ArrayList<LexElement> attribs = null;
      if(mode != TplOrFnMode.TPL) {
        while(true) {
          FunctionParamAttribKinds paramAttrib = FunctionParamAttribKinds.fromToken(lookAhead());
          if(paramAttrib == null || isTypeModifier(lookAhead()) && lookAhead(1) == DeeTokens.OPEN_PARENS)
            break;
         
          LexElement attribToken = consumeLookAhead();
          attribs = lazyInitArrayList(attribs);
          attribs.add(attribToken);
         
          if(!isTypeModifier(attribToken.type)) {
            setMode(TplOrFnMode.FN);
          }
        }
      }
     
      return new AmbiguousParameter().parseAmbiguousParam(this, returnNullOnMissing, parse.nodeStart, attribs);
    }
   
   
    protected void setMode(TplOrFnMode newMode) {
      if(mode == newMode)
        return;
      assertTrue(mode == TplOrFnMode.AMBIG);
     
      mode = newMode;
      if(params == null)
        return;
     
      ArrayList<AmbiguousParameter> oldParams = blindCast(params);
      params = new ArrayList<Object>();
      for (AmbiguousParameter param : oldParams) {
        params.add(mode == TplOrFnMode.FN ? param.convertToFunction() : param.convertToTemplate());
      }
    }
   
    public final ArrayView<IFunctionParameter> getAsFunctionParameters() {
      assertTrue(mode == TplOrFnMode.FN);
      return arrayView(CoreUtil.<ArrayList<IFunctionParameter>>blindCast(params));
    }
   
    public final ArrayView<IFunctionParameter> toFunctionParameters() {
      assertTrue(isAmbiguous());
      setMode(TplOrFnMode.FN);
      return getAsFunctionParameters();
    }
   
    public final ArrayView<TemplateParameter> getAsTemplateParameters() {
      assertTrue(mode == TplOrFnMode.TPL);
      return arrayView(CoreUtil.<ArrayList<TemplateParameter>>blindCast(params));
    }
   
    public final ArrayView<TemplateParameter> toTemplateParameters() {
      assertTrue(isAmbiguous());
      setMode(TplOrFnMode.TPL);
      return getAsTemplateParameters();
    }
  }
 
  protected class AmbiguousParameter {
   
    ArrayList<LexElement> attribs;
   
    Reference ref;
    ProtoDefSymbol defId = null;
    Reference typeSpecialization = null;
    Expression valueSpecialization = null;
    TypeOrExpResult paramDefault = new TypeOrExpResult(null, null);
    boolean isVariadic = false;
   
    SourceRange sr;
   
    public Object parseAmbiguousParam(DeeParser_RuleParameters params, boolean returnNullOnMissing,
      int nodeStart, ArrayList<LexElement> attribs) {
      this.attribs = attribs;
     
      // Possible outcomes from this point
      // NamelessParam or TemplateTypeParam
      // NamelessParam(variadic) or TemplateTupleParam
      // FunctionParameter or TemplateValueParam (isValueParam = true)
     
      parsing: {
        NodeResult<Reference> refResult = parseTypeReference();
        ref = refResult.node;
        if(refResult.ruleBroken) {
          break parsing;
        }
        if(ref == null) {
          if(attribs == null && returnNullOnMissing) { // No Parameter at all
            return null;
          }
          ref = parseMissingTypeReference(true);
          break parsing;
        }
       
        if(lookAhead() == DeeTokens.IDENTIFIER) {
          defId = parseDefId();
        } else {
          if(!(couldHaveBeenParsedAsId(ref) && attribs == null)) {
            if(params.mode == TplOrFnMode.TPL) {
              assertTrue(attribs == null);
              defId = parseDefId(); // will create a missing defId;
            } else {
              params.setMode(TplOrFnMode.FN); // Can only be NamelessParam
            }
          }
        }
       
        if((defId == null) || (defId != null && params.mode != TplOrFnMode.TPL) ) {
          if(tryConsume(DeeTokens.TRIPLE_DOT)) {
            if(defId != null) {
              params.setMode(TplOrFnMode.FN); //FunctionParameter
            }
            isVariadic = true;
            break parsing;
          }
        }
       
        if(params.mode != TplOrFnMode.FN && tryConsume(DeeTokens.COLON)) {
          params.setMode(TplOrFnMode.TPL); // TemplateTypeParam or TemplateValueParam
          if(defId == null) {
            typeSpecialization = parseTypeReference_ToMissing().node;
          } else {
            valueSpecialization = parseExpression_toMissing(InfixOpType.CONDITIONAL);
          }
        }
        if(tryConsume(DeeTokens.ASSIGN)) {
          parseParamDefault(params);
        }
      }
     
      assertTrue(defId == null ? valueSpecialization == null : typeSpecialization == null);
      assertTrue(defId != null ? !paramDefault.isRefOnly() : true);
     
      sr = SourceRange.srStartToEnd(nodeStart, getSourcePosition());
      switch (params.mode) { default: throw assertUnreachable();
      case AMBIG: return this;
      case TPL: return convertToTemplate();
      case FN: return convertToFunction();
      }
    }
   
    public void parseParamDefault(DeeParser_RuleParameters params) {
      if(params.mode == TplOrFnMode.FN || defId != null) {
        paramDefault = new TypeOrExpResult(null, result(false, parseAssignExpression_toMissing()));
      } else if(params.mode == TplOrFnMode.TPL) {
        if(defId == null) {
          paramDefault = new TypeOrExpResult(parseTypeReference_ToMissing(), null);
        } else {
          paramDefault = new TypeOrExpResult(null, result(false, parseAssignExpression_toMissing()));
        }
      } else {
        paramDefault = parseTypeOrExpression(InfixOpType.ASSIGN);
        if(paramDefault.isNull()) {
          paramDefault = new TypeOrExpResult(
            parseTypeReference_ToMissing(),
            result(false, parseAssignExpression_toMissing()));
        } else if(paramDefault.isExpOnly() && defId == null) {
          params.setMode(TplOrFnMode.FN); //NamelessParameter
        else if(paramDefault.isRefOnly()) {
          params.setMode(TplOrFnMode.TPL);
        }
      }
    }
   
    public IFunctionParameter convertToFunction() {
      if(defId == null) {
        return conclude(sr,
          new NamelessParameter(arrayViewG(attribs), ref, paramDefault.toExpression().node, isVariadic));
      }
      return conclude(sr,
        new FunctionParameter(arrayViewG(attribs), ref, defId, paramDefault.toExpression().node, isVariadic));
    }
   
    public TemplateParameter convertToTemplate() {
      if(attribs != null)  {
       
        for (int i = attribs.size()-1; i >= 0 ; i--) {
          LexElement attribToken = attribs.get(i);
          TypeModifierKinds modifier = assertNotNull(determineTypeModifier(attribToken.type));
          ref = concludeNode(srBounds(attribToken.getStartPos(), ref.getEndPos(),
            new RefTypeModifier(modifier, ref, false)));
        }
      }
      if(defId == null && couldHaveBeenParsedAsId(ref)) {
        defId = convertRefIdToDef(ref);
        return conclude(sr, isVariadic ?
          new TemplateTupleParam(defId) :
          new TemplateTypeParam(defId, typeSpecialization, paramDefault.toReference().node));
      } else {
        defId = defId != null ? defId : createEmptyDefSymbol(ref.getEndPos());
        return conclude(sr,
          new TemplateValueParam(ref, defId, valueSpecialization, paramDefault.toExpression().node));
      }
    }
  }
 
  public static ProtoDefSymbol createEmptyDefSymbol(int position) {
    return new ProtoDefSymbol("", srAt(position), null);
  }
 
  protected ASTNode parseTemplateAliasParameter_start() {
    consumeLookAhead(DeeTokens.KW_ALIAS);
    ParseHelper parse = new ParseHelper();
   
    ProtoDefSymbol defId;
    Resolvable init = null;
    Resolvable specialization = null;
   
    parsing: {
      defId = parse.checkResult(parseDefId());
      if(parse.ruleBroken) break parsing;
     
      if(tryConsume(DeeTokens.COLON)) {
        NodeResult<Resolvable> typeOrCondExp = parseTypeOrExpression(InfixOpType.CONDITIONAL, true);
        specialization = nullTypeOrExpToParseMissing(typeOrCondExp.node);
      }
      if(tryConsume(DeeTokens.ASSIGN)) {
        init = nullTypeOrExpToParseMissing(parseTypeOrAssignExpression(true).node);
      }
    }
   
    return parse.conclude(new TemplateAliasParam(defId, specialization, init));
  }
 
}
TOP

Related Classes of dtool.parser.DeeParser_Parameters$AmbiguousParameter

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.