Ejemplo n.º 1
0
bool gmCodeGenPrivate::GenExprConstant(const gmCodeTreeNode * a_node, gmByteCodeGen * a_byteCode)
{
  GM_ASSERT(a_node->m_type == CTNT_EXPRESSION && a_node->m_subType == CTNET_CONSTANT);

  switch(a_node->m_subTypeType)
  {
    case CTNCT_INT : // INT
    {
      if(a_node->m_data.m_iValue == 0)
      {
        a_byteCode->Emit(BC_PUSHINT0);
      }
      else if(a_node->m_data.m_iValue == 1)
      {
        a_byteCode->Emit(BC_PUSHINT1);
      }
      else
      {
#if 1 // 32bit Integers
        a_byteCode->Emit(BC_PUSHINT, *((gmint *) &a_node->m_data.m_iValue));
#else
        a_byteCode->EmitPtr(BC_PUSHINT, *((gmptr *) &a_node->m_data.m_iValue));
#endif
      }
      break;
    }
    case CTNCT_FLOAT : // FLOAT
    {
      a_byteCode->Emit(BC_PUSHFP, *((gmuint32 *) ((void *) &a_node->m_data.m_fValue)));
      break;
    }
    case CTNCT_STRING : // STRING
    {
      a_byteCode->EmitPtr(BC_PUSHSTR, m_hooks->GetStringId(a_node->m_data.m_string));
      break;
    }
    case CTNCT_NULL : // NULL
    {
      a_byteCode->Emit(BC_PUSHNULL);
      break;
    }
    default:
    {
      if(m_log) m_log->LogEntry("unkown constant type");
      return false;
    }
  }
  
  return true;
}
Ejemplo n.º 2
0
bool gmCodeGenPrivate::GenExprOpDot(const gmCodeTreeNode * a_node, gmByteCodeGen * a_byteCode)
{
  GM_ASSERT(a_node->m_type == CTNT_EXPRESSION && a_node->m_subType == CTNET_OPERATION && a_node->m_subTypeType == CTNOT_DOT);

  if(!Generate(a_node->m_children[0], a_byteCode)) return false;

  // make sure child 1 is an identifier
  const gmCodeTreeNode * id = a_node->m_children[1];
  if(id && id->m_type == CTNT_EXPRESSION && id->m_subType == CTNET_IDENTIFIER)
  {
    return a_byteCode->EmitPtr(BC_GETDOT, m_hooks->GetSymbolId(a_node->m_children[1]->m_data.m_string));
  }

  if(m_log) m_log->LogEntry("error (%d) illegal dot operator", a_node->m_lineNumber);
  return false;
}
Ejemplo n.º 3
0
bool gmCodeGenPrivate::GenStmtContinue(const gmCodeTreeNode * a_node, gmByteCodeGen * a_byteCode)
{
  GM_ASSERT(a_node->m_type == CTNT_STATEMENT && a_node->m_subType == CTNST_CONTINUE);

  if(m_currentLoop >= 0)
  {
    a_byteCode->Emit(BC_BRA);
    Patch * patch = &m_patches.InsertLast();
    patch->m_address = a_byteCode->Skip(sizeof(gmptr)); // NOTE: Using gmptr size addresses
    patch->m_next = m_loopStack[m_currentLoop].m_continues;
    m_loopStack[m_currentLoop].m_continues = m_patches.Count()-1;
    return true;
  }

  if(m_log) m_log->LogEntry("error (%d) illegal continue statement", a_node->m_lineNumber);
  return false;
}
Ejemplo n.º 4
0
bool gmCodeGenPrivate::GenExprOpShift(const gmCodeTreeNode * a_node, gmByteCodeGen * a_byteCode)
{
  GM_ASSERT(a_node->m_type == CTNT_EXPRESSION && a_node->m_subType == CTNET_OPERATION);

  if(!Generate(a_node->m_children[0], a_byteCode)) return false;
  if(!Generate(a_node->m_children[1], a_byteCode)) return false;

  switch(a_node->m_subTypeType)
  {
    case CTNOT_SHIFT_LEFT :  return a_byteCode->Emit(BC_BIT_SHL);
    case CTNOT_SHIFT_RIGHT : return a_byteCode->Emit(BC_BIT_SHR);
    default :
    {
      if(m_log) m_log->LogEntry("error (%d) unkown shift operator", a_node->m_lineNumber);
    }
  }
  return false;
}
Ejemplo n.º 5
0
bool gmCodeGenPrivate::GenExprOpUnary(const gmCodeTreeNode * a_node, gmByteCodeGen * a_byteCode)
{
  GM_ASSERT(a_node->m_type == CTNT_EXPRESSION && a_node->m_subType == CTNET_OPERATION);

  if(!Generate(a_node->m_children[0], a_byteCode)) return false;

  switch(a_node->m_subTypeType)
  {
    case CTNOT_UNARY_PLUS :       return a_byteCode->Emit(BC_OP_POS);
    case CTNOT_UNARY_MINUS :      return a_byteCode->Emit(BC_OP_NEG);
    case CTNOT_UNARY_NOT :        return a_byteCode->Emit(BC_OP_NOT);
    case CTNOT_UNARY_COMPLEMENT : return a_byteCode->Emit(BC_BIT_INV);
    default :
    {
      if(m_log) m_log->LogEntry("error (%d) unkown operator", a_node->m_lineNumber);
    }
  }
  return false;
}
Ejemplo n.º 6
0
bool gmCodeGenPrivate::GenExprOpAr(const gmCodeTreeNode * a_node, gmByteCodeGen * a_byteCode)
{
  GM_ASSERT(a_node->m_type == CTNT_EXPRESSION && a_node->m_subType == CTNET_OPERATION);

  if(!Generate(a_node->m_children[0], a_byteCode)) return false;
  if(!Generate(a_node->m_children[1], a_byteCode)) return false;

  switch(a_node->m_subTypeType)
  {
    case CTNOT_TIMES : return a_byteCode->Emit(BC_OP_MUL);
    case CTNOT_DIVIDE : return a_byteCode->Emit(BC_OP_DIV);
    case CTNOT_REM : return a_byteCode->Emit(BC_OP_REM);
    case CTNOT_ADD : return a_byteCode->Emit(BC_OP_ADD);
    case CTNOT_MINUS : return a_byteCode->Emit(BC_OP_SUB);
    default :
    {
      if(m_log) m_log->LogEntry("error (%d) unkown arithmatic operator", a_node->m_lineNumber);
    }
  }
  return false;
}
Ejemplo n.º 7
0
bool gmCodeGenPrivate::GenExprOpComparison(const gmCodeTreeNode * a_node, gmByteCodeGen * a_byteCode)
{
  GM_ASSERT(a_node->m_type == CTNT_EXPRESSION && a_node->m_subType == CTNET_OPERATION);

  if(!Generate(a_node->m_children[0], a_byteCode)) return false;
  if(!Generate(a_node->m_children[1], a_byteCode)) return false;

  switch(a_node->m_subTypeType)
  {
    case CTNOT_LT :  return a_byteCode->Emit(BC_OP_LT);
    case CTNOT_GT :  return a_byteCode->Emit(BC_OP_GT);
    case CTNOT_LTE : return a_byteCode->Emit(BC_OP_LTE);
    case CTNOT_GTE : return a_byteCode->Emit(BC_OP_GTE);
    case CTNOT_EQ :  return a_byteCode->Emit(BC_OP_EQ);
    case CTNOT_NEQ : return a_byteCode->Emit(BC_OP_NEQ);
    default :
    {
      if(m_log) m_log->LogEntry("error (%d) unkown comparison operator", a_node->m_lineNumber);
    }
  }
  return false;
}
Ejemplo n.º 8
0
bool gmCodeGenPrivate::GenExprIdentifier(const gmCodeTreeNode * a_node, gmByteCodeGen * a_byteCode)
{
  GM_ASSERT(a_node->m_type == CTNT_EXPRESSION && a_node->m_subType == CTNET_IDENTIFIER);

  // if local, get local regardless
  // if member, get this
  // if global, get global
  // get global

  if((a_node->m_flags & gmCodeTreeNode::CTN_MEMBER) > 0)
  {
    return a_byteCode->EmitPtr(BC_GETTHIS, m_hooks->GetSymbolId(a_node->m_data.m_string));
  }

  gmCodeTreeVariableType type;
  int offset = m_currentFunction->GetVariableOffset(a_node->m_data.m_string, type);

  if(offset >= 0 && type == CTVT_LOCAL)
  {
    return a_byteCode->Emit(BC_GETLOCAL, (gmuint32) offset);
  }
  else if(offset != -2)
  {
    if(type == CTVT_MEMBER)
    {
      return a_byteCode->EmitPtr(BC_GETTHIS, m_hooks->GetSymbolId(a_node->m_data.m_string));
    }
    else if(type == CTVT_GLOBAL)
    {
      return a_byteCode->EmitPtr(BC_GETGLOBAL, m_hooks->GetSymbolId(a_node->m_data.m_string));
    }
    if(m_log) m_log->LogEntry("internal error");
    return false;
  }

  return a_byteCode->EmitPtr(BC_GETGLOBAL, m_hooks->GetSymbolId(a_node->m_data.m_string));
}
Ejemplo n.º 9
0
bool gmCodeGenPrivate::GenExprFunction(const gmCodeTreeNode * a_node, gmByteCodeGen * a_byteCode)
{
  GM_ASSERT(a_node->m_type == CTNT_EXPRESSION && a_node->m_subType == CTNET_FUNCTION);

  gmptr id = m_hooks->GetFunctionId();
  a_byteCode->EmitPtr(BC_PUSHFN, id);

  // Create the function
  PushFunction();

  // Get a debug function name as the name of the variable the function is assigned to
  if(m_debug && a_node->m_parent && a_node->m_parent->m_type == CTNT_EXPRESSION && a_node->m_parent->m_subType == CTNET_OPERATION &&
     (a_node->m_parent->m_subTypeType == CTNOT_ASSIGN || a_node->m_parent->m_subTypeType == CTNOT_ASSIGN_FIELD) && a_node->m_parent->m_children[1] == a_node)
  {
    const gmCodeTreeNode * debugName = a_node->m_parent->m_children[0];
    if(debugName && debugName->m_type == CTNT_EXPRESSION && debugName->m_subType == CTNET_IDENTIFIER)
    {
    }
    else if(debugName->m_type == CTNT_EXPRESSION && debugName->m_subType == CTNET_OPERATION && 
            debugName->m_subTypeType == CTNOT_DOT)
    {
      debugName = debugName->m_children[1];
    }
    else
    {
      debugName = NULL;
    }

    if(debugName)
    {
      GM_ASSERT(debugName->m_type == CTNT_EXPRESSION && debugName->m_subType == CTNET_IDENTIFIER);
      m_currentFunction->m_debugName = debugName->m_data.m_string;
    }
  }

  // Parameters
  const gmCodeTreeNode * params = a_node->m_children[0];
  int numParams = 0;
  while(params)
  {
    const gmCodeTreeNode * param = params->m_children[0];
    GM_ASSERT(param->m_type == CTNT_EXPRESSION && param->m_subType == CTNET_IDENTIFIER);
    if(m_currentFunction->SetVariableType(param->m_data.m_string, CTVT_LOCAL) != numParams)
    {
      if(m_log) m_log->LogEntry("error (%d) parameter %s already declared", param->m_lineNumber, param->m_data.m_string);
      PopFunction();
      return false;
    }
    ++numParams;
    params = params->m_sibling;
  }

  // Generate the code
  bool res = Generate(a_node->m_children[1], &m_currentFunction->m_byteCode);

  // Generate a return incase the function didnt have one.
  m_currentFunction->m_byteCode.Emit(BC_RET);

  if(res)
  {
    // Create a locals table
    const char ** locals = NULL;
    if(m_debug)
    {
      locals = (const char **) alloca(sizeof(const char *) * m_currentFunction->m_numLocals);
      memset(locals, 0, sizeof(const char *) * m_currentFunction->m_numLocals);

      for(gmuint v = 0; v < m_currentFunction->m_variables.Count(); ++v)
      {
        Variable &variable = m_currentFunction->m_variables[v];
        if(variable.m_offset != -1)
        {
          locals[variable.m_offset] = variable.m_symbol;
        }
      }
    }

    // Add the function to the hooks.

    gmSortDebugLines(m_currentFunction->m_lineInfo);
    
    gmFunctionInfo info;
    info.m_id = id;
    info.m_root = false;
    info.m_byteCode = m_currentFunction->m_byteCode.GetData();
    info.m_byteCodeLength = m_currentFunction->m_byteCode.Tell();
    info.m_numParams = numParams;
    info.m_numLocals = m_currentFunction->m_numLocals - numParams;
    info.m_symbols = locals;
    info.m_maxStackSize = m_currentFunction->m_byteCode.GetMaxTos();
    info.m_lineInfoCount = m_currentFunction->m_lineInfo.Count();
    info.m_lineInfo = m_currentFunction->m_lineInfo.GetData();
    info.m_debugName = m_currentFunction->m_debugName;
    m_hooks->AddFunction(info);

    //gmByteCodePrint(stdout, info.m_byteCode, info.m_byteCodeLength);
  }

  PopFunction();
  
  return res;
}
Ejemplo n.º 10
0
bool gmCodeGenPrivate::Generate(const gmCodeTreeNode * a_node, gmByteCodeGen * a_byteCode, bool a_siblings)
{
  bool res = true;

  while(a_node)
  {
    // record line number
    static int s_line = 0;
    if(m_currentFunction) m_currentFunction->m_currentLine = a_node->m_lineNumber;

    // if we are in debug, emit a BC_LINE instruction
    if(m_debug && (s_line != a_node->m_lineNumber) && 
       !(a_node->m_type == CTNT_STATEMENT && a_node->m_subType == CTNST_COMPOUND))
    {
      a_byteCode->Emit(BC_LINE);
      s_line = a_node->m_lineNumber;
    }

    switch(a_node->m_type)
    {
      case CTNT_DECLARATION :
      {
        switch(a_node->m_subType)
        {
          case CTNDT_VARIABLE : res = GenDeclVariable(a_node, a_byteCode); break;
          default: 
          {
            GM_ASSERT(false);
            return false;
          }
        }
        break;
      }
      case CTNT_STATEMENT :
      {
        switch(a_node->m_subType)
        {
          case CTNST_RETURN : res = GenStmtReturn(a_node, a_byteCode); break;
          case CTNST_BREAK : res = GenStmtBreak(a_node, a_byteCode); break;
          case CTNST_CONTINUE : res = GenStmtContinue(a_node, a_byteCode); break;
          case CTNST_FOR : res = GenStmtFor(a_node, a_byteCode); break;
          case CTNST_FOREACH : res = GenStmtForEach(a_node, a_byteCode); break;
          case CTNST_WHILE : res = GenStmtWhile(a_node, a_byteCode); break;
          case CTNST_DOWHILE : res = GenStmtDoWhile(a_node, a_byteCode); break;
          case CTNST_IF : res = GenStmtIf(a_node, a_byteCode); break;
          case CTNST_COMPOUND : res = GenStmtCompound(a_node, a_byteCode); break;
#if GM_USE_FORK
          case CTNST_FORK : res = GenStmtFork(a_node, a_byteCode); break;
#else //GM_USE_FORK
          case CTNST_FORK: // Unsupported, but tokens exist
          {
            if(m_log && m_currentFunction)
            {
              m_log->LogEntry("error (%d) 'fork' instruction not supported", m_currentFunction->m_currentLine);
            }
            return false;
          }
#endif //GM_USE_FORK
          default: 
          {
            GM_ASSERT(false);
            return false;
          }
        }
        break;
      }
      case CTNT_EXPRESSION : 
      {
        switch(a_node->m_subType)
        {
          case CTNET_OPERATION : 
          {
            switch(a_node->m_subTypeType)
            {
              case CTNOT_DOT :              res = GenExprOpDot(a_node, a_byteCode); break;
              case CTNOT_UNARY_PLUS :
              case CTNOT_UNARY_MINUS :
              case CTNOT_UNARY_COMPLEMENT :
              case CTNOT_UNARY_NOT : res = GenExprOpUnary(a_node, a_byteCode); break;
              case CTNOT_ARRAY_INDEX :      res = GenExprOpArrayIndex(a_node, a_byteCode); break;
              case CTNOT_TIMES :
              case CTNOT_DIVIDE :
              case CTNOT_REM :
              case CTNOT_MINUS :
              case CTNOT_ADD :              res = GenExprOpAr(a_node, a_byteCode); break;
              case CTNOT_SHIFT_LEFT :
              case CTNOT_SHIFT_RIGHT :      res = GenExprOpShift(a_node, a_byteCode); break;
              case CTNOT_LT :
              case CTNOT_GT :
              case CTNOT_LTE :
              case CTNOT_GTE :
              case CTNOT_EQ :
              case CTNOT_NEQ :              res = GenExprOpComparison(a_node, a_byteCode); break;
              case CTNOT_BIT_AND :
              case CTNOT_BIT_XOR :
              case CTNOT_BIT_OR :           res = GenExprOpBitwise(a_node, a_byteCode); break;
              case CTNOT_AND :              res = GenExprOpAnd(a_node, a_byteCode); break;
              case CTNOT_OR :               res = GenExprOpOr(a_node, a_byteCode); break;
              case CTNOT_ASSIGN :           res = GenExprOpAssign(a_node, a_byteCode); break;
              default:
              {
                GM_ASSERT(false);
                return false;
              }
            }
            break;
          }
          case CTNET_CONSTANT : res = GenExprConstant(a_node, a_byteCode); break;
          case CTNET_IDENTIFIER : res = GenExprIdentifier(a_node, a_byteCode); break;
          case CTNET_CALL : res = GenExprCall(a_node, a_byteCode); break;
          case CTNET_THIS : res = GenExprThis(a_node, a_byteCode); break;
          case CTNET_FUNCTION : res = GenExprFunction(a_node, a_byteCode); break;
          case CTNET_TABLE : res = GenExprTable(a_node, a_byteCode); break;
          default :
          {
            GM_ASSERT(false);
            return false;
          }
        }

        break;
      }
      default: 
      {
        GM_ASSERT(false);
        return false;
      }
    }

    if(!res) 
    {
      return false;
    }

    if((a_node->m_flags & gmCodeTreeNode::CTN_POP) > 0)
    {
      a_byteCode->Emit(BC_POP);
    }

    if(a_siblings)
    {
      a_node = a_node->m_sibling;
    }
    else a_node = NULL;
  }
  return true;
}
Ejemplo n.º 11
0
bool gmCodeGenPrivate::GenExprOpAssign(const gmCodeTreeNode * a_node, gmByteCodeGen * a_byteCode)
{
  GM_ASSERT(a_node->m_type == CTNT_EXPRESSION && a_node->m_subType == CTNET_OPERATION);

  // value on left hand side must be an l-value... ie, a dot, array or identifier.
  const gmCodeTreeNode * lValue = a_node->m_children[0];
  int type = 0;

  if(lValue->m_type == CTNT_EXPRESSION && lValue->m_subType == CTNET_OPERATION && lValue->m_subTypeType == CTNOT_DOT)
  {
    // Generate half l-value
    if(!Generate(lValue->m_children[0], a_byteCode)) return false;
    type = 0;
  }
  else if(lValue->m_type == CTNT_EXPRESSION && lValue->m_subType == CTNET_OPERATION && lValue->m_subTypeType == CTNOT_ARRAY_INDEX)
  {
    // Generate half l-value
    if(!Generate(lValue->m_children[0], a_byteCode)) return false;
    if(!Generate(lValue->m_children[1], a_byteCode)) return false;
    type = 1;
  }
  else if(lValue->m_type == CTNT_EXPRESSION && lValue->m_subType == CTNET_IDENTIFIER)
  {
    type = 2;
  }
  else
  {
    if(m_log) m_log->LogEntry("error (%d) illegal l-value for '=' operator", a_node->m_lineNumber);
    return false;
  }

  // Generate r-value
  if(!Generate(a_node->m_children[1], a_byteCode)) return false;

  // complete assignment
  if(type == 0)
  {
    a_byteCode->EmitPtr(BC_SETDOT, m_hooks->GetSymbolId(lValue->m_children[1]->m_data.m_string));
  }
  else if(type == 1)
  {
    a_byteCode->Emit(BC_SETIND);
  }
  else if(type == 2)
  {
    gmCodeTreeVariableType vtype;
    int offset = m_currentFunction->GetVariableOffset(lValue->m_data.m_string, vtype);

    // if local, set local regardless
    // if member set this
    // if global, set global
    // set and add local

    if((lValue->m_flags & gmCodeTreeNode::CTN_MEMBER) > 0)
    {
      return a_byteCode->EmitPtr(BC_SETTHIS, m_hooks->GetSymbolId(lValue->m_data.m_string));
    }
    if(offset >= 0 && vtype == CTVT_LOCAL)
    {
      return a_byteCode->Emit(BC_SETLOCAL, (gmuint32) offset);
    }
    else if(offset == -1)
    {
      if(vtype == CTVT_MEMBER)
      {
        return a_byteCode->EmitPtr(BC_SETTHIS, m_hooks->GetSymbolId(lValue->m_data.m_string));
      }
      else if(vtype == CTVT_GLOBAL)
      {
        return a_byteCode->EmitPtr(BC_SETGLOBAL, m_hooks->GetSymbolId(lValue->m_data.m_string));
      }
      if(m_log) m_log->LogEntry("internal error");
      return false;
    }

    offset = m_currentFunction->SetVariableType(lValue->m_data.m_string, CTVT_LOCAL);
    return a_byteCode->Emit(BC_SETLOCAL, (gmuint32) offset);
  }
  else
  {
    // paranoia
    if(m_log) m_log->LogEntry("internal error");
    return false;
  }

  return true;
}
Ejemplo n.º 12
0
bool gmCodeGenPrivate::GenExprOpPreIncDec(const gmCodeTreeNode * a_node, gmByteCodeGen * a_byteCode)
{
  GM_ASSERT(a_node->m_type == CTNT_EXPRESSION && a_node->m_subType == CTNET_OPERATION);

  // Make sure child 0 is an l-value
  const gmCodeTreeNode * lValue = a_node->m_children[0];
  int type = 0;

  if(lValue->m_type == CTNT_EXPRESSION && lValue->m_subType == CTNET_OPERATION && lValue->m_subTypeType == CTNOT_DOT)
  {
    // Generate half l-value
    if(!Generate(lValue->m_children[0], a_byteCode)) return false;
    a_byteCode->Emit(BC_DUP);
    a_byteCode->EmitPtr(BC_GETDOT, m_hooks->GetSymbolId(lValue->m_children[1]->m_data.m_string));
    type = 0;
  }
  else if(lValue->m_type == CTNT_EXPRESSION && lValue->m_subType == CTNET_OPERATION && lValue->m_subTypeType == CTNOT_ARRAY_INDEX)
  {
    // Generate half l-value
    if(!Generate(lValue->m_children[0], a_byteCode)) return false;
    if(!Generate(lValue->m_children[1], a_byteCode)) return false;
    a_byteCode->Emit(BC_DUP2);
    a_byteCode->Emit(BC_GETIND);
    type = 1;
  }
  else if(lValue->m_type == CTNT_EXPRESSION && lValue->m_subType == CTNET_IDENTIFIER)
  {
    if(!Generate(lValue, a_byteCode)) return false;
    type = 2;
  }
  else
  {
    if(m_log) m_log->LogEntry("illegal l-value for '++/--' operator, line %d", a_node->m_lineNumber);
    return false;
  }

  // Perform inc/dec
  switch(a_node->m_subTypeType)
  {
    case CTNOT_PRE_INC : a_byteCode->Emit(BC_OP_INC); break;
    case CTNOT_PRE_DEC : a_byteCode->Emit(BC_OP_DEC); break;
    default :
    {
      if(m_log) m_log->LogEntry("unkown operator");
      return false;
    }
  }

  // Write back the value
  if(type == 0)
  {
    int offset = m_currentFunction->SetVariableType(s_tempVarName0, CTVT_LOCAL);
    a_byteCode->Emit(BC_DUP);
    a_byteCode->Emit(BC_SETLOCAL, (gmuint32) offset);
    a_byteCode->EmitPtr(BC_SETDOT, m_hooks->GetSymbolId(lValue->m_children[1]->m_data.m_string));
    a_byteCode->Emit(BC_GETLOCAL, (gmuint32) offset);
  }
  else if(type == 1)
  {
    int offset = m_currentFunction->SetVariableType(s_tempVarName0, CTVT_LOCAL);
    a_byteCode->Emit(BC_DUP);
    a_byteCode->Emit(BC_SETLOCAL, (gmuint32) offset);
    a_byteCode->Emit(BC_SETIND);
    a_byteCode->Emit(BC_GETLOCAL, (gmuint32) offset);
  }
  else if(type == 2)
  {
    a_byteCode->Emit(BC_DUP);
    gmCodeTreeVariableType vtype;
    int offset = m_currentFunction->GetVariableOffset(lValue->m_data.m_string, vtype);

    // if local, set local regardless
    // if member set this
    // if global, set global
    // set and add local

    if((lValue->m_flags & gmCodeTreeNode::CTN_MEMBER) > 0)
    {
      return a_byteCode->EmitPtr(BC_SETTHIS, m_hooks->GetSymbolId(lValue->m_data.m_string));
    }

    if(offset >= 0 && vtype == CTVT_LOCAL)
    {
      return a_byteCode->Emit(BC_SETLOCAL, (gmuint32) offset);
    }
    else if(offset == -1)
    {
      if(vtype == CTVT_MEMBER)
      {
        return a_byteCode->EmitPtr(BC_SETTHIS, m_hooks->GetSymbolId(lValue->m_data.m_string));
      }
      else if(vtype == CTVT_GLOBAL)
      {
        return a_byteCode->EmitPtr(BC_SETGLOBAL, m_hooks->GetSymbolId(lValue->m_data.m_string));
      }
      if(m_log) m_log->LogEntry("internal error");
      return false;
    }

    offset = m_currentFunction->SetVariableType(lValue->m_data.m_string, CTVT_LOCAL);
    return a_byteCode->Emit(BC_SETLOCAL, (gmuint32) offset);
  }
  else
  {
    // paranoia
    if(m_log) m_log->LogEntry("internal error");
    return false;
  }

  return true;
}