Package anvil.script

Source Code of anvil.script.Grammar

/*
* $Id: Grammar.java,v 1.7 2002/09/16 08:05:03 jkl Exp $
*
* Copyright (c) 2002 Njet Communications Ltd. All Rights Reserved.
*
* Use is subject to license terms, as defined in
* Anvil Sofware License, Version 1.1. See LICENSE
* file, or http://njet.org/license-1.1.txt
*/
package anvil.script;

import java.util.ArrayList;
import java.util.StringTokenizer;
import anvil.core.Any;
import anvil.ErrorListener;
import anvil.Location;
import anvil.script.statements.Statement;
import anvil.script.statements.FunctionStatement;
import anvil.script.expression.ConstantNode;
import anvil.script.expression.Expression;
import anvil.script.expression.ExpressionList;
import anvil.script.expression.Node;
import anvil.script.expression.StringBufferNode;
import anvil.script.parser.ExpressionParser;
import anvil.script.parser.NestedParser;
import anvil.script.parser.ParserBase;
import anvil.script.parser.TemplateParser;
import anvil.util.Conversions;

/**
* class Grammar
*
* @author: Jani Lehtim�ki
*/
public class Grammar
{

  public static final boolean isValidIdentifier(String name)
  {
    return isValidIdentifier(name, false);
  }
   

  public static final boolean isValidIdentifier(String name, boolean allowDot)
  {
    if (name == null) {
      return false;
    }
 
    int n = name.length();
    if (n == 0) {
      return false;
    }
   
    char ch = name.charAt(0);
    if (ch == '$' || !Character.isJavaIdentifierStart(ch)) {
      return false;
    }
   
    for (int i=1; i<n; i++) {
      ch = name.charAt(i);
      if (ch == '$' || !Character.isJavaIdentifierPart(ch)) {
        if (!allowDot || ch != '.') {
          return false;
        }
      }
    }
   
    return true;
  }


  public static final Expression parseExpression(String expression, Location location, TemplateParser parser)
  {
    return doParseExpression(ExpressionParser.TYPE_VALUE, expression, location, parser);
  }  


  public static final Expression parseAssignmentExpression(String expression, Location location, TemplateParser parser)
  {
    return doParseExpression(ExpressionParser.TYPE_ASSIGNMENT, expression, location, parser);
  }  


  public static final Expression parseStandaloneExpression(String expression, Location location, TemplateParser parser)
  {
    return doParseExpression(ExpressionParser.TYPE_STANDALONE, expression, location, parser);
  }  


  public static final Expression parseAssignableExpression(String expression, Location location, TemplateParser parser)
  {
    return doParseExpression(ExpressionParser.TYPE_ASSIGNABLE, expression, location, parser);
  }  



  public static final Expression[] parseForeachExpression(String expression, Location location, TemplateParser parser)
  {
    if (expression != null) {
      ExpressionParser expressionParser = new ExpressionParser(parser, location, expression);
      return expressionParser.parseForeachExpression();
    } else {
      parser.error(location, "Expression attribute missing");
      return new Expression[0];   
    }
  }  

 

  public static final Expression doParseExpression(int type, String expression, Location location, TemplateParser parser)
  {
    if (expression != null) {
      ExpressionParser expressionParser =
        new ExpressionParser(parser, location, expression);
      return expressionParser.parseExpression(type);
    } else {
      parser.error(location, "Expression attribute missing");
      return Expression.NULL;
    }
  }  


  public static final Node parseString(ParserBase parser, Location location, String image)
  {
    if (image.indexOf("${") >= 0) {
      ArrayList sections = new ArrayList();
      StringBuffer buffer = new StringBuffer();
      int n = image.length();
      char ch;
      for(int i=0; i<n; i++) {
        ch = image.charAt(i);
        if ((i+2<n) && (ch == '$') && (image.charAt(i+1) == '{')) {
          if (buffer.length()>0) {
            sections.add(new ConstantNode(Conversions.unescape(buffer.toString(), false)));
          }
          buffer.setLength(0);
         
          boolean singleQuote = false;
          boolean doubleQuote = false;
          int nesting = 1;
          int startIndex = i + 2;

          i++;
          while(i+1<n && nesting>0) {
            ch = image.charAt(++i);
            switch(ch) {
            case '{':
              if (!singleQuote || !doubleQuote) {
                nesting++;
              }
              buffer.append(ch);
              break;
            case '}':
              if (!singleQuote || !doubleQuote) {
                nesting--;
              }
              if (nesting>0) {
                buffer.append(ch);
              }
              break;
            case '\\':
              if (i+1<n) {
                char ch2 = image.charAt(++i);
                if (ch2 == '}' || ch2 == '{') {
                  buffer.append(ch2);
                } else {
                  buffer.append(ch);
                  buffer.append(ch2);
                }
              }
              break;
            case '\'':
              if (doubleQuote == false) {
                singleQuote = !singleQuote;
              }
              buffer.append(ch);
              break;
            case '"':
              if (singleQuote == false) {
                doubleQuote = !doubleQuote;
              }
              buffer.append(ch);
              break;
             
            default:
              buffer.append(ch);
            }
          }
         
          NestedParser expressionParser =
            new NestedParser(parser, location, buffer.toString(), startIndex);
           
          Expression expression = expressionParser.parseExpression();
         
          if (expression.isConstant()) {
            sections.add(new ConstantNode(expression.eval().toString()));
          } else {
            Node child = expression.getChild(0);
            if (child != null) {
              sections.add(child);
            }
          }
          buffer.setLength(0);
         
        } else {
          buffer.append(ch);
        }
      }
     
      if (buffer.length()>0) {
        sections.add(new ConstantNode(Conversions.unescape(buffer.toString(), false)));
      }
     
      n = sections.size();
      ExpressionList list = new ExpressionList(n);
      for(int i=0; i<n; i++) {
        list.setChild(i, (Node)sections.get(i));
      }
      return new StringBufferNode(list);
     
    } else {
      return new ConstantNode(Conversions.unescape(image, false));
    }
   
  }


  public static void checkInstanceAccess(ErrorListener listener,
    Location location, Statement context, ClassType target)
  {
    ClassType context_class = null;
    if (context != null) {
      context_class = context.getClassStatement();
    }
    while(target != null) {
      ClassType[] required = target.getEnclosingClasses();
      int n = required.length;
      if (n>0) {
        if (context.isStaticRegion()) {
          listener.error(location, "Attempting to access instance of class '"+target+"' from static region");
          return;
        }
      }

      for(int i=0; i<n; i++) {
        boolean found = false;
        ClassType parent = required[i];

        Type type = context_class;
        while(type != null) {
          if (type == parent) {
            found = true;
            break;
          }
          type = type.getParent();
        }
    
        /*if (!found) {
          ClassType clazz = context_class;
          while(clazz != null) {
            if (clazz == parent) {
              found = true;
              break;
            }
            clazz = clazz.getBaseClass();
          }
        }*/
       
        if (!found) {
          listener.error(location, "Instance of enclosing '"+parent+"' of '"+target+"' is not accessible here");
        }
      }
      target = target.getBaseClass();
    }
  }
 

  public static void checkInstanceAmbiguity(ErrorListener listener,
    Location location, ClassType context, Type member)
  {
    boolean accessible = false;
    Type member_parent = member.getParent();
    ClassType clazz = context;
    while(clazz != null) {
      if (clazz == member_parent) {
        ClassType[] parents = context.getEnclosingClasses();
        int n = parents.length;
        for(int i=0; i<n; i++) {
          if (parents[i] == member_parent) {
            listener.error(location, "Ambiguous reference to '" + member + "' inherited from class '" +
              member_parent+"'. Explicit qualification is required.");
            return;
          }
        }
        return;
      }
      clazz = clazz.getBaseClass();
    }
  } 

  public static final Name parseDottedName(String dottedname)
  {
    return parseDottedName(null, null, dottedname);
  }


  public static final Name parseDottedName(ErrorListener listener, Location location, String dottedname)
  {
    dottedname = dottedname.trim();
    Name name = new Name();
    boolean valid = true;
    StringTokenizer tokenizer = new StringTokenizer(dottedname, ".");
    while(tokenizer.hasMoreTokens()) {
      String image = tokenizer.nextToken().trim();
      if (!Grammar.isValidIdentifier(image)) {
        if (listener != null) {
          listener.error(location, "Syntax error, symbol '"+image+"' is invalid");
        }
        valid = false;
      }
      name.add(image);
    }
    if (valid) {
      return name;
    } else {
      return null;
    }
  } 
 
  public static final Name[] parseDottedNames(ErrorListener listener, Location location, String dottednames)
  {
    boolean valid = true;
    StringTokenizer tokenizer = new StringTokenizer(dottednames, ",");
    ArrayList list = new ArrayList();
    while(tokenizer.hasMoreTokens()) {
      Name name = parseDottedName(listener, location, tokenizer.nextToken());
      if (name != null) {
        list.add(name);
      } else {
        valid = false;
      }
    }
    if (valid) {
      return (Name[])list.toArray(new Name[list.size()]);
    } else {
      return null;
    }
  }

 
  public static final Name[] parseImportNames(ErrorListener listener, Location location, String names)
  {
    boolean valid = true;
    names = names.replace('\t', ' ');
    names = names.replace('\r', ' ');
    names = names.replace('\n', ' ');
    StringTokenizer tokenizer = new StringTokenizer(names, ",");
    ArrayList list = new ArrayList();
    while(tokenizer.hasMoreTokens()) {
      String token = tokenizer.nextToken() + ' ';
      String as = null;
      boolean star = false;
      int i = token.indexOf(" as ");
      if (i>0) {
        as = token.substring(i+4).trim();
        if (!isValidIdentifier(as)) {
          listener.error(location, "Name '"+as+"' is not a valid identifier");
        }
        token = token.substring(0, i).trim();
      } else {
        token = token.trim();
      }
      if (token.endsWith("*")) {
        if (as != null) {
          listener.error(location,"Syntax error: 'as' and '*' may not be used together in import");
        }
        star = true;
        token = token.substring(0, token.length()-2).trim();
        if (token.endsWith(".")) {
          token = token.substring(0, token.length()-1);
        }
      }
      Name name = parseDottedName(listener, location, token);
      if (name != null) {
        name.setAs(as);
        if (star) {
          name.enableStar();
        }
        list.add(name);
      } else {
        valid = false;
      }
    }
    if (valid) {
      return (Name[])list.toArray(new Name[list.size()]);
    } else {
      return null;
    }
  }
 
 
  public static final int countEscapeDepth(FunctionStatement context, Statement target)
  {
    int depth = 0;
    Statement target_parent = target.getFunctionStatement().getContext();
    while(context != null) {
      if (context == target) {
        break;
      }
      if (context == target_parent) {
        depth--;
        break;
      }
      depth++;
      context = context.getContext();
    }
    if (context == null) {
      return -1;
    }
    return depth;
  }
 
 
  public static Type follow(Scope scope, String name)
  {
    int start = 0;
    int n = name.length();
   
    while(true) {
      int end = name.indexOf('.', start+1);
      if (end == -1) {
        end = name.length();
      }
     
      Type type = scope.lookupDeclaration(name.substring(start, end));
      if (type == null) {
        return null;
      }
     
      if (end < n) {
        if (type instanceof Scope) {
          scope = (Scope)type;
        } else {
          return null;
        }
      } else {
        return type;
      }
     
      start = end + 1;
    }
  }
 
 
  public static final String buildQualifiedName(Type type)
  {
    StringBuffer buffer = new StringBuffer(32);
    if (buildQualifiedName0(buffer, (Scope)type.getParent())) {
      buffer.append('.');
    }
    buffer.append(type.getName());
    return buffer.toString();
  }


  private static final boolean buildQualifiedName0(StringBuffer buffer, Scope scope)
  {
    if (scope == null) {
      return false;
    }
    if (scope.getType() == Type.MODULE) {
      return false;
    }
    if (buildQualifiedName0(buffer, scope.getParent())) {
      buffer.append('.');
    }
    buffer.append(scope.getName());
    return true;
  }
 
 
  public static final Module getModuleOf(Type type)
  {
    if (type.getType() == Type.MODULE) {
      return (Module)type;
    }
    Scope scope = type.getParent();
    while(scope != null) {
      if (scope.getType() == Type.MODULE) {
        return (Module)scope;
      }
      scope = scope.getParent();
    }
    return null;
  }

 
 
}
TOP

Related Classes of anvil.script.Grammar

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.