コード例 #1
0
ファイル: name-resolver.cpp プロジェクト: LittleKu/sourcepawn
VarDecl *
NameResolver::HandleVarDecl(NameToken name, TypeSpecifier &spec, Expression *init)
{
  Scope *scope = getOrCreateScope();

  // :TODO: set variadic info
  VarDecl *var = new (pool_) VarDecl(name, init);

  // Note: the parser has already bound |var->init()| at this point, meaning
  // that aside from globals it should be impossible to self-initialize like:
  //    int x = x;
  //
  // :TODO: do check this for globals.
  VariableSymbol *sym = new (pool_) VariableSymbol(var, scope, var->name());
  registerSymbol(sym);
  var->setSymbol(sym);

  // Set this before we evaluate the type, since it determines whether or not
  // a const on a parameter is meaningless.
  if (spec.isByRef()) {
    assert(scope->kind() == Scope::Argument && sym->isArgument());
    sym->storage_flags() |= StorageFlags::byref;
  }

  // See the comment in TypeResolver::visitVarDecl for why we do not want to
  // infer sizes from literals for arguments.
  if (init &&
      !scope->isArgument() &&
      ((init->isArrayLiteral() && init->asArrayLiteral()->isFixedArrayLiteral()) ||
       (init->isStringLiteral())))
  {
    // Wait until the type resolution pass to figure this out. We still have
    // to precompute the base though.
    if (Type *type = resolveBase(spec))
      spec.setResolvedBaseType(type);
    var->te() = TypeExpr(new (pool_) TypeSpecifier(spec));
  } else {
    VarDeclSpecHelper helper(var, nullptr);
    var->te() = resolve(spec, &helper);
  }

  if (var->te().resolved()) {
    sym->setType(var->te().resolved());

    // We need to check this both here and in lazy resolution, which is gross,
    // but I don't see any obvious way to simplify it yet.
    if (spec.isByRef() && sym->type()->passesByReference()) {
      cc_.report(spec.byRefLoc(), rmsg::type_cannot_be_ref)
        << sym->type();
    }
  }

  // Even if we were able to resolve the type, if we have to resolve a constant
  // value, we'll have to add it to the resolver queue.
  if (!var->te().resolved() || sym->canUseInConstExpr())
    tr_.addPending(var);

  return var;
}
コード例 #2
0
ファイル: old-sema.cpp プロジェクト: LittleKu/sourcepawn
void
SemanticAnalysis::visitNameProxy(NameProxy *proxy)
{
  Symbol *sym = proxy->sym();
  VariableSymbol *var = sym->asVariable();

  // If we see that a symbol is a function literal, then we bypass the scope
  // chain operations entirely and hardcode the function literal.
  if (sym->isFunction()) {
    assert(sym->scope()->kind() == Scope::Global);
    hir_ = new (pool_) HFunction(proxy, sym->asFunction());
    return;
  }

  if (value_context_ == kLValue) {
    // Egads! We're being asked to construct an l-value instead of an r-value.
    *outp_ = LValue(var);
    return;
  }

  Scope *in = sym->scope();
  switch (in->kind()) {
    case Scope::Global:
      hir_ = new (pool_) HGlobal(proxy, var);
      return;

    case Scope::Function:
    {
      assert(var->storage() == VariableSymbol::Arg);
      // Since we're in an r-value context, we need to strip the reference type.
      Type *type = var->type();
      if (type->isReference())
        type = type->toReference()->contained();
      hir_ = new (pool_) HLocal(proxy, type, var);
      return;
    }

    default:
      assert(in->kind() == Scope::Block);
      assert(var->storage() == VariableSymbol::Local);
      hir_ = new (pool_) HLocal(proxy, var->type(), var);
      return;
  }
}
コード例 #3
0
void
TypeResolver::visitVarDecl(VarDecl *node)
{
  VariableSymbol *sym = node->sym();

  assert(!sym->type());

  Type* type;
  if (TypeSpecifier *spec = node->te().spec()) {
    // We always infer sizes for postdims in variable scope. In argument
    // scope, we don't want something like:
    //
    //    f(x[] = {}), or
    //
    // To infer as int[0]. However, this should be illegal:
    //
    //    f(int x[] = {})
    //
    // So we simply never infer dimensions for arguments.
    //
    // Note: we should not be able to recurse from inside this block. If it
    // could, we'd have to mark spec as resolving earlier.
    Vector<int> literal_dims;
    if (Expression *init = node->initialization()) {
      if (spec->hasPostDims() && !sym->isArgument()) {
        // Compute the dimensions of initializers in case the declaration type
        // requires inference.
        if (ArrayLiteral *lit = init->asArrayLiteral()) {
          literal_dims = fixedArrayLiteralDimensions(spec, lit);
        } else if (StringLiteral *lit = init->asStringLiteral()) {
          literal_dims.append(lit->arrayLength());
        }
      }
    }

    VarDeclSpecHelper helper(node, &literal_dims);
    type = resolveType(node->te(), &helper);
  } else {
    type = node->te().resolved();
  }

  if (!assignTypeToSymbol(sym, type))
    return;

  if (sym->isConstExpr() || !sym->canUseInConstExpr())
    return;

  // If we're currently trying to resolve this variable's constant
  // expression, report an error.
  if (sym->isResolvingConstExpr()) {
    cc_.report(node->loc(), rmsg::recursive_constexpr)
      << sym->name();

    // Pawn requires that const variables have constexprs, so we just set a
    // default one to quell as many other errors as we can. In the future we
    // may want to lax this restriction.
    sym->setConstExpr(DefaultValueForPlainType(sym->type()));
    return;
  }

  // We got a constexpr with no initialization. Just assume it's 0, but
  // report an error as SP1 does.
  if (!node->initialization()) {
    cc_.report(node->loc(), rmsg::constant_var_needs_constexpr)
      << sym->name();
    sym->setConstExpr(DefaultValueForPlainType(sym->type()));
    return;
  }

  sym->setResolvingConstExpr();

  // In Pawn, a const var *must* be a constexpr. We only care about this for
  // ints/floats since constexprs aren't really relevant yet otherwise.
  BoxedValue box;
  ConstantEvaluator ceval(cc_, this, ConstantEvaluator::Required);
  switch (ceval.Evaluate(node->initialization(), &box)) {
    case ConstantEvaluator::Ok:
      break;
    case ConstantEvaluator::NotConstant:
      cc_.report(node->loc(), rmsg::constant_var_needs_constexpr)
        << sym->name();
      // FALLTHROUGH.
    case ConstantEvaluator::TypeError:
      // Error has already been reported.
      box = DefaultValueForPlainType(sym->type());
      break;
    default:
      assert(false);
  }

  // :TODO: type check box

  sym->setConstExpr(box);
}