logo

class

compiler::CheckParamDefs

sys::Obj
  compiler::CompilerSupport
    compiler::CompilerStep
      compiler::CheckParamDefs
//
// Copyright (c) 2006, Brian Frank and Andy Frank
// Licensed under the Academic Free License version 3.0
//
// History:
//   20 Jun 06  Brian Frank  Creation
//    1 Oct 06  Brian Frank  Port from Java to Fan
//

**
** CheckParamDefs is used to process all the parameter default
** expressions for all the methods.  What we are looking for is
** default expressions which use default expressions before it
** which require us to insert a store instruction.
**
class CheckParamDefs : CompilerStep
{

  new make(Compiler compiler)
    : super(compiler)
  {
  }

  override Void run()
  {
    walk(types, VisitDepth.slotDef)
  }

  override Void visitMethodDef(MethodDef m)
  {
    // unless there are two or more defaults don't bother
    params := m.paramDefs
    num := params.size
    if (num <= 1 || params[-2].def == null)
      return

    // if a def expr calculates a local used after it,
    // then we need to insert a store (local set)
    (num-1).times |Int i|
    {
      if (params[i].def == null) return
      if (usedInSuccDef(params, i))
      {
        param := params[i]
        var   := m.vars[i]
        loc   := param.location

        if (!param.name.equals(var.name)) throw err("invalid state", loc)

        param.def = BinaryExpr.makeAssign(LocalVarExpr.make(loc, var), param.def, true)
      }
    }
  }

  Bool usedInSuccDef(ParamDef[] params, Int index)
  {
    this.name = params[index].name
    for (i:=index+1; i<params.size; ++i)
    {
      this.used = false
      params[i].def.walk(this)
      if (this.used) return true
    }
    return false
  }

  override Expr visitExpr(Expr expr)
  {
    if (expr.id === ExprId.localVar)
    {
      local := (LocalVarExpr)expr
      if (name == local.var.name) used = true
    }
    return expr
  }

  Str name
  Bool used

}