Пример #1
0
 protected void Visit(ASTNode node)
 {
     if (node == null)
         return;
     else if (node is CLASS_DECLARATION) {
         CLASS_DECLARATION cd = (CLASS_DECLARATION)node;
         if (cd.name == "__MAIN")
             return;
         constructorFound = false;
         foreach (Statement stmt in cd.stmt_list)
             Visit(stmt);
         // if no user defined constructor is found, add one
         ArrayList modifiers, parameters;
         StatementList stmt_list;
         Statement ctorDecl;
         if (!constructorFound) {
             modifiers = new ArrayList();
             modifiers.Add(PHP.Core.Modifiers.PUBLIC);
             parameters = new ArrayList();
             stmt_list = new StatementList();
             ctorDecl = new FUNCTION_DECLARATION(modifiers, false, "__construct", parameters, stmt_list, 0, 0);
             cd.stmt_list.Add(ctorDecl);
         }
         // in every case, add a static constructor
         modifiers = new ArrayList();
         modifiers.Add(PHP.Core.Modifiers.PUBLIC);
         modifiers.Add(PHP.Core.Modifiers.STATIC);
         parameters = new ArrayList();
         stmt_list = new StatementList();
         ctorDecl = new FUNCTION_DECLARATION(modifiers, false, "__constructStatic", parameters, stmt_list, 0, 0);
         cd.stmt_list.Add(ctorDecl);
     }
     else if (node is FUNCTION_DECLARATION) {
         FUNCTION_DECLARATION fd = (FUNCTION_DECLARATION)node;
         if (fd.name == "__construct")
             constructorFound = true;
     }
 }
Пример #2
0
 public void insert(string name, int kind, ASTNode node)
 {
     SymbolTableEntry entry = new SymbolTableEntry(name, kind, node);
     // a new class member?
     if (kind == SymbolTable.CLASS_VARIABLE) {
         if (classMembers.Contains(name))
             Report.Error(306, name);
         classMembers.Add(name);
     }
     // no symbol with this name exists, so add it
     if (entries[name] == null) {
         Hashtable value = new Hashtable();
         value[kind] = entry;
         entries[name] = value;
     }
     // a symbol with this name already exists
     else {
         Hashtable value = (Hashtable)entries[name];
         // but with another kind, so add it
         if (value[kind] == null)
             value[kind] = entry;
         // with kind reserved word, class, class variable or function, so report error
         else
             switch (kind) {
                 case SymbolTable.RESERVED_WORD: Report.Error(201, name, node.line, node.column); break;
                 case SymbolTable.CLASS: Report.Error(202, name, node.line, node.column); break;
                 case SymbolTable.CLASS_VARIABLE: Report.Error(204, name, node.line, node.column); break;
                 case SymbolTable.FUNCTION: Report.Error(211, name, node.line, node.column); break;
             }
     }
 }
Пример #3
0
 public SymbolTableEntry(string name, int kind, ASTNode node)
 {
     this.name = name;
     this.kind = kind;
     this.node = node;
 }
Пример #4
0
 public void insertLocal(string name, int kind, ASTNode node)
 {
     cur_scope.insert(name, kind, node);
 }
Пример #5
0
 public void insertGlobal(string name, int kind, ASTNode node)
 {
     getTopScope().insert(name, kind, node);
 }
Пример #6
0
 protected void Visit(ASTNode node)
 {
     if (node == null)
         return;
     else if (node is CLASS_DECLARATION) {
         CLASS_DECLARATION cd = (CLASS_DECLARATION)node;
         // process statements of class
         SymbolTable.getInstance().cur_scope = cd.scope;
         foreach (Statement stmt in cd.stmt_list)
             Visit(stmt);
     }
     else if (node is CLASS_VARIABLE_DECLARATION) {
         CLASS_VARIABLE_DECLARATION cvd = (CLASS_VARIABLE_DECLARATION)node;
         // process all values assigned
         foreach (Expression expr in cvd.values)
             Visit(expr);
     }
     else if (node is FUNCTION_DECLARATION) {
         FUNCTION_DECLARATION fd = (FUNCTION_DECLARATION)node;
         // process parameters and statements of function
         SymbolTable.getInstance().cur_scope = fd.scope;
         foreach (PARAMETER_DECLARATION pd in fd.parameters)
             Visit(pd);
         foreach (Statement stmt in fd.stmt_list)
             Visit(stmt);
     }
     else if (node is PARAMETER_DECLARATION) {
         PARAMETER_DECLARATION pd = (PARAMETER_DECLARATION)node;
         // process default value
         Visit(pd.default_value);
     }
     else if (node is IF) {
         // process if statement
         IF i = (IF)node;
         Visit(i.expr);
         Visit(i.stmt);
         // process else if statements
         foreach (ELSEIF e in i.elseif_list)
             Visit(e);
         // process else statement
         Visit(i.else_stmt);
     }
     else if (node is ELSEIF) {
         // process if statement
         ELSEIF e = (ELSEIF)node;
         Visit(e.expr);
         Visit(e.stmt);
     }
     else if (node is WHILE) {
         WHILE w = (WHILE)node;
         // process while expression and statement
         Visit(w.expr);
         Visit(w.stmt);
     }
     else if (node is DO) {
         DO d = (DO)node;
         // process do expression and statement
         Visit(d.stmt);
         Visit(d.expr);
     }
     else if (node is FOR) {
         FOR f = (FOR)node;
         // process for expressions and statement
         foreach (Expression e in f.expr_list1)
             Visit(e);
         foreach (Expression e2 in f.expr_list2)
             Visit(e2);
         Visit(f.stmt);
         foreach (Expression e3 in f.expr_list3)
             Visit(e3);
     }
     else if (node is FOREACH) {
         FOREACH f = (FOREACH)node;
         // process foreach expressions and statement
         if (f.key != null && f.key is FUNCTION_CALL)
             Report.Warn(406, ((FUNCTION_CALL)f.key).function_name, f.key.line, f.key.column);
         if (f.value is FUNCTION_CALL)
             Report.Warn(406, ((FUNCTION_CALL)f.value).function_name, f.value.column, f.value.line);
         Visit(f.stmt);
     }
     else if (node is BLOCK) {
         BLOCK b = (BLOCK)node;
         // process statements of block
         foreach (Statement stmt in b.stmt_list)
             Visit(stmt);
     }
     else if (node is StatementList) {
         StatementList s = (StatementList)node;
         // process statements of block
         foreach (Statement stmt in s)
             Visit(stmt);
     }
     else if (node is ECHO) {
         ECHO e = (ECHO)node;
         // process echo expressions
         foreach (Expression e2 in e.expr_list)
             Visit(e2);
     }
     else if (node is BREAK) {
         BREAK b = (BREAK)node;
         // process expression
         Visit(b.expr);
     }
     else if (node is CONTINUE) {
         CONTINUE c = (CONTINUE)node;
         // process expression
         Visit(c.expr);
     }
     else if (node is RETURN) {
         RETURN r = (RETURN)node;
         // process expression
         Visit(r.expr);
     }
     else if (node is EXPRESSION_AS_STATEMENT) {
         EXPRESSION_AS_STATEMENT eas = (EXPRESSION_AS_STATEMENT)node;
         // process expression
         Visit(eas.expr);
     }
     else if (node is CLONE) {
         CLONE c = (CLONE)node;
         // process expression
         Visit(c.expr);
     }
     else if (node is PAAMAYIM_NEKUDOTAYIM) {
         PAAMAYIM_NEKUDOTAYIM pn = (PAAMAYIM_NEKUDOTAYIM)node;
         // process expression
         Visit(pn.expr);
     }
     else if (node is OBJECT_OPERATOR) {
         OBJECT_OPERATOR oo = (OBJECT_OPERATOR)node;
         // process left part
         Visit(oo.expr1);
         // process right part
         Visit(oo.expr2);
     }
     else if (node is EQUALS) {
         EQUALS e = (EQUALS)node;
         // process expressions
         Visit(e.expr1);
         Visit(e.expr2);
     }
     else if (node is VARIABLE) {
         VARIABLE var = (VARIABLE)node;
         // process offset, if available
         if (var.offset != null)
             Visit(var.offset);
     }
     else if (node is OFFSET) {
         OFFSET o = (OFFSET)node;
         // process offset expression
         Visit(o.value);
     }
     else if (node is FUNCTION_CALL) {
         FUNCTION_CALL fc = (FUNCTION_CALL)node;
         // process parameters
         foreach (Expression expr in fc.parameters)
             Visit(expr);
     }
     else if (node is INSTANCEOF) {
         INSTANCEOF i = (INSTANCEOF)node;
         // process expression
         Visit(i.expr);
     }
     else if (node is ARRAY) {
         ARRAY a = (ARRAY)node;
         // process array pairs
         foreach (ARRAY_PAIR ap in a.array_pair_list) {
             Visit(ap.key);
             Visit(ap.value);
         }
     }
     else if (node is UnaryExpression) {
         UnaryExpression ue = (UnaryExpression)node;
         // process expression
         Visit(ue.expr);
     }
     else if (node is BinaryExpression) {
         BinaryExpression be = (BinaryExpression)node;
         // process expressions
         Visit(be.expr1);
         Visit(be.expr2);
     }
     else if (node is TernaryExpression) {
         TernaryExpression te = (TernaryExpression)node;
         // process expressions
         Visit(te.expr1);
         Visit(te.expr2);
         Visit(te.expr3);
     }
     else if (node is Expression) {
         Expression e = (Expression)node;
         if (e is VARIABLE)
             Visit((VARIABLE)e);
         else if (e is FUNCTION_CALL)
             Visit((FUNCTION_CALL)e);
         else if (e is ARRAY)
             Visit((ARRAY)e);
         else if (e is UnaryExpression)
             Visit((UnaryExpression)e);
         else if (e is BinaryExpression)
             Visit((BinaryExpression)e);
         else if (e is TernaryExpression)
             Visit((TernaryExpression)e);
     }
 }
Пример #7
0
 protected void Visit(ASTNode node)
 {
     if (node == null)
         return;
     else if (node is CLASS_DECLARATION) {
         CLASS_DECLARATION cd = (CLASS_DECLARATION)node;
         foreach (Statement stmt in cd.stmt_list)
             Visit(stmt);
     }
     else if (node is FUNCTION_DECLARATION) {
         FUNCTION_DECLARATION fd = (FUNCTION_DECLARATION)node;
         bool returnReached = false;
         StatementList newStmtList = new StatementList();
         // copy each statement to newStmtList until top return is reached
         foreach (Statement stmt in fd.stmt_list) {
             if (stmt is RETURN) {
                 newStmtList.Add(stmt);
                 returnReached = true;
                 break;
             }
             else
                 newStmtList.Add(stmt);
         }
         // if there was no return statement, add one
         if (!returnReached)
             newStmtList.Add(new RETURN(null, 0, 0));
         // replace statement list of function with new one
         fd.stmt_list = newStmtList;
     }
 }
Пример #8
0
 protected void Visit(ASTNode node)
 {
     if (node == null)
         return;
     else if (node is CLASS_DECLARATION)
         modifiedStmtList.Add((Statement)node);
     else if (node is FUNCTION_DECLARATION) {
         FUNCTION_DECLARATION fd = (FUNCTION_DECLARATION)node;
         ArrayList modifiers = new ArrayList();
         modifiers.Add(PHP.Core.Modifiers.PUBLIC);
         modifiers.Add(PHP.Core.Modifiers.STATIC);
         fd.modifiers = modifiers;
         cd__MAIN.stmt_list.Add(fd);
     }
     else
         fd__MAIN.stmt_list.Add((Statement)node);
 }
Пример #9
0
 protected void Visit(ASTNode node)
 {
     if (node == null)
         return;
     else if (node is CLASS_DECLARATION) {
         CLASS_DECLARATION cd = (CLASS_DECLARATION)node;
         foreach (Statement stmt in cd.stmt_list)
             Visit(stmt);
     }
     else if (node is FUNCTION_DECLARATION) {
         FUNCTION_DECLARATION fd = (FUNCTION_DECLARATION)node;
         foreach (Statement stmt in fd.stmt_list)
             Visit(stmt);
     }
     else if (node is BLOCK) {
         BLOCK b = (BLOCK)node;
         foreach (Statement stmt in b.stmt_list)
             Visit(stmt);
     }
     else if (node is IF) {
         IF i = (IF)node;
         Visit(i.stmt);
     }
     else if (node is ELSEIF) {
         ELSEIF e = (ELSEIF)node;
         Visit(e.stmt);
     }
     else if (node is WHILE) {
         WHILE w = (WHILE)node;
         level++;
         Visit(w.stmt);
         level--;
     }
     else if (node is DO) {
         DO d = (DO)node;
         level++;
         Visit(d.stmt);
         level--;
     }
     else if (node is FOR) {
         FOR f = (FOR)node;
         level++;
         Visit(f.stmt);
         level--;
     }
     else if (node is FOREACH) {
         FOREACH f = (FOREACH)node;
         level++;
         Visit(f.stmt);
         level--;
     }
     else if (node is SWITCH) {
         SWITCH s = (SWITCH)node;
         level++;
         foreach (ASTNode node2 in s.switch_case_list) {
             if (node2 is CASE)
                 Visit((CASE)node2);
             else if (node2 is DEFAULT)
                 Visit((DEFAULT)node2);
         }
         level--;
     }
     else if (node is CASE) {
         CASE c = (CASE)node;
         Visit(c.stmt);
     }
     else if (node is DEFAULT) {
         DEFAULT d = (DEFAULT)node;
         Visit(d.stmt);
     }
     else if (node is BREAK) {
         if (level == 0)
             Report.Error(501, node.line, node.column);
     }
     else if (node is CONTINUE) {
         if (level == 0)
             Report.Error(501, node.line, node.column);
     }
 }
Пример #10
0
 protected void Visit(ASTNode node)
 {
     if (node == null)
         return;
     else if (node is CLASS_DECLARATION) {
         cd = (CLASS_DECLARATION)node;
         // check if class extends a final class
         if (cd.extends != null) {
             SymbolTableEntry parentCdEntry = SymbolTable.getInstance().lookupGlobal(cd.extends.ToLower(), SymbolTable.CLASS);
             CLASS_DECLARATION parentCd = (CLASS_DECLARATION)parentCdEntry.node;
             if (parentCd.modifier == Modifiers.FINAL)
                 Report.Error(101, parentCd.name, cd.line, cd.column);
         }
         // create type builder
         TypeAttributes modifier = TypeAttributes.Class;
         if (cd.modifier == PHP.Core.Modifiers.PUBLIC)
             modifier |= TypeAttributes.Public;
         //else if (cd.modifier == PHP.Core.Modifiers.ABSTRACT)
         //	modifier |= TypeAttributes.Abstract;
         else if (cd.modifier == PHP.Core.Modifiers.FINAL)
             modifier |= TypeAttributes.Sealed;
         Type parent;
         if (cd.extends == null || typesAlreadyProcessed[cd.extends] == null) {
             if (cd.name == "__MAIN")
                 parent = typeof(object);
             else
                 parent = PHPObject;
         }
         else
             parent = (Type)typesAlreadyProcessed[cd.extends];
         cd.typBld = PEmitter.modBld.DefineType(cd.name, modifier, parent);
         typesAlreadyProcessed.Add(cd.name, cd.typBld);
         // insert class symbol (which is case insensitive)
         SymbolTable.getInstance().insertGlobal(cd.name.ToLower(), SymbolTable.CLASS, cd);
         // process each statement within class
         SymbolTable.getInstance().openScope();
         cd.scope = SymbolTable.getInstance().cur_scope;
         foreach (Statement stmt in cd.stmt_list)
             Visit(stmt);
         SymbolTable.getInstance().closeScope();
         cd = null;
     }
     else if (node is CLASS_VARIABLE_DECLARATION) {
         CLASS_VARIABLE_DECLARATION cvd = (CLASS_VARIABLE_DECLARATION)node;
         // create field builders
         FieldAttributes modifiers = 0;
         if (cvd.modifiers.Count == 0)
             modifiers = FieldAttributes.Public | FieldAttributes.Static;
         else if (cvd.modifiers.Contains(Modifiers.CONST))
             modifiers = FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.InitOnly;
         else if (!cvd.modifiers.Contains(PHP.Core.Modifiers.PUBLIC) && !cvd.modifiers.Contains(PHP.Core.Modifiers.PROTECTED) && !cvd.modifiers.Contains(PHP.Core.Modifiers.PRIVATE))
             modifiers = FieldAttributes.Public;
         else {
             ArrayList tmpModifiers = (ArrayList)cvd.modifiers.Clone();
             if (cvd.modifiers.Contains(PHP.Core.Modifiers.PUBLIC)) {
                 modifiers = FieldAttributes.Public;
                 tmpModifiers.Remove(PHP.Core.Modifiers.PUBLIC);
             }
             else if (cvd.modifiers.Contains(PHP.Core.Modifiers.PROTECTED)) {
                 modifiers = FieldAttributes.Family;
                 tmpModifiers.Remove(PHP.Core.Modifiers.PROTECTED);
             }
             else if (cvd.modifiers.Contains(PHP.Core.Modifiers.PRIVATE)) {
                 modifiers = FieldAttributes.Private;
                 tmpModifiers.Remove(PHP.Core.Modifiers.PRIVATE);
             }
             if (tmpModifiers.Contains(PHP.Core.Modifiers.PUBLIC) || tmpModifiers.Contains(PHP.Core.Modifiers.PROTECTED) || tmpModifiers.Contains(PHP.Core.Modifiers.PRIVATE))
                 Report.Error(105, cvd.line, cvd.column);
         }
         foreach (int modifier in cvd.modifiers) {
             switch (modifier) {
                 case PHP.Core.Modifiers.STATIC: modifiers |= FieldAttributes.Static; break;
                 //case PHP.Core.Modifiers.ABSTRACT: Report.Error(103, "abstract", cvd.line, cvd.column); break;
                 case PHP.Core.Modifiers.FINAL: Report.Error(103, "abstract", cvd.line, cvd.column); break;
             }
         }
         cvd.fieldBuilders = new ArrayList();
         foreach (string name in cvd.names) {
             cvd.fieldBuilders.Add(cd.typBld.DefineField(name, PHPMixed, modifiers));
             // insert member symbol
             SymbolTable.getInstance().insertLocal(name, SymbolTable.CLASS_VARIABLE, cvd);
         }
     }
     else if (node is FUNCTION_DECLARATION) {
         fd = (FUNCTION_DECLARATION)node;
         // check if function overrides a final function with the same name
         CLASS_DECLARATION tmpCd = cd;
         while (tmpCd.extends != null) {
             SymbolTableEntry parentCdEntry = SymbolTable.getInstance().lookupGlobal(cd.extends.ToLower(), SymbolTable.CLASS);
             tmpCd = (CLASS_DECLARATION)parentCdEntry.node;
             SymbolTableEntry superFdEntry = tmpCd.scope.lookup(fd.name.ToLower(), SymbolTable.FUNCTION);
             if (superFdEntry != null) {
                 FUNCTION_DECLARATION superFd = (FUNCTION_DECLARATION)superFdEntry.node;
                 if (superFd.modifiers.Contains(Modifiers.FINAL)) {
                     StringBuilder parameters = new StringBuilder();
                     foreach (PARAMETER_DECLARATION pd in superFd.parameters) {
                         if (pd.type != null) {
                             parameters.Append(pd.type);
                             parameters.Append(" ");
                         }
                         parameters.Append(pd.name);
                         parameters.Append(", ");
                     }
                     if (parameters.Length > 0)
                         parameters.Remove(parameters.Length - 2, 2);
                     Report.Error(102, tmpCd.name + "::" + superFd.name + "(" + parameters.ToString() + ")", fd.line, fd.column);
                 }
             }
         }
         // create constructor and method builders
         MethodAttributes modifiers = 0;
         if (fd.modifiers.Count == 0)
             modifiers = MethodAttributes.Public;
         else if (!fd.modifiers.Contains(PHP.Core.Modifiers.PUBLIC) && !fd.modifiers.Contains(PHP.Core.Modifiers.PROTECTED) && !fd.modifiers.Contains(PHP.Core.Modifiers.PRIVATE))
             modifiers = MethodAttributes.Public;
         else {
             ArrayList tmpModifiers = (ArrayList)fd.modifiers.Clone();
             if (fd.modifiers.Contains(PHP.Core.Modifiers.PUBLIC)) {
                 modifiers = MethodAttributes.Public;
                 tmpModifiers.Remove(PHP.Core.Modifiers.PUBLIC);
             }
             else if (fd.modifiers.Contains(PHP.Core.Modifiers.PROTECTED)) {
                 modifiers = MethodAttributes.Family;
                 tmpModifiers.Remove(PHP.Core.Modifiers.PROTECTED);
             }
             else if (fd.modifiers.Contains(PHP.Core.Modifiers.PRIVATE)) {
                 modifiers = MethodAttributes.Private;
                 tmpModifiers.Remove(PHP.Core.Modifiers.PRIVATE);
             }
             if (tmpModifiers.Contains(PHP.Core.Modifiers.PUBLIC) || tmpModifiers.Contains(PHP.Core.Modifiers.PROTECTED) || tmpModifiers.Contains(PHP.Core.Modifiers.PRIVATE))
                 Report.Error(105, fd.line, fd.column);
         }
         foreach (int modifier in fd.modifiers) {
             if (fd.name == "__construct")
                 switch (modifier) {
                     case PHP.Core.Modifiers.STATIC: Report.Error(104, "static", fd.line, fd.column); break;
                     //case PHP.Core.Modifiers.ABSTRACT: Report.Error(104, "abstract", fd.line, fd.column); break;
                     case PHP.Core.Modifiers.FINAL: modifiers |= MethodAttributes.Final; break;
                 }
             else if (fd.name == "__constructStatic")
                 modifiers |= MethodAttributes.Static;
             else
                 switch (modifier) {
                     case PHP.Core.Modifiers.STATIC: modifiers |= MethodAttributes.Static; break;
                     //case PHP.Core.Modifiers.ABSTRACT: modifiers |= MethodAttributes.Abstract; break;
                     case PHP.Core.Modifiers.FINAL: modifiers |= MethodAttributes.Final; break;
                 }
         }
         Type[] parameterTypes = new Type[fd.parameters.Count];
         for (int i = 0; i < parameterTypes.Length; i++)
             parameterTypes[i] = PHPMixed;
         Type returnType;
         if (fd.name == "__MAIN")
             returnType = typeof(void);
         else
             returnType = PHPMixed;
         if (fd.name == "__construct" || fd.name == "__constructStatic")
             fd.ctrBld = cd.typBld.DefineConstructor(modifiers, CallingConventions.Standard, parameterTypes);
         else
             fd.mthBld = cd.typBld.DefineMethod(fd.name, modifiers, returnType, parameterTypes);
         // at beginning of script
         if (fd.name == "__MAIN") {
             mainMethod = fd.mthBld;
             // disable warnings, if desired
             if (!Report.warningsEnabled) {
                 mPHPRuntime = Assembly.LoadFrom("mPHPRuntime.dll");
                 Type report = mPHPRuntime.GetType("PHP.Core.Report");
                 fd.mthBld.GetILGenerator().Emit(OpCodes.Ldc_I4_0);
                 fd.mthBld.GetILGenerator().Emit(OpCodes.Stsfld, report.GetField("warningsEnabled"));
             }
             // initialize local settings to en-US
             fd.mthBld.GetILGenerator().Emit(OpCodes.Call, PHPCoreLang.GetMethod("Init", Type.EmptyTypes));
         }
         // insert function symbol (which is case insensitive)
         SymbolTable.getInstance().insertLocal(fd.name.ToLower(), SymbolTable.FUNCTION, fd);
         // remember scope
         SymbolTable.getInstance().openScope();
         fd.scope = SymbolTable.getInstance().cur_scope;
         SymbolTable.getInstance().closeScope();
         fd = null;
     }
 }
Пример #11
0
        protected void Visit(ASTNode node)
        {
            if (node == null)
                return;
            else if (node is CLASS_DECLARATION) {
                cd = (CLASS_DECLARATION)node;
                // process each statement of class
                foreach (Statement stmt in cd.stmt_list)
                    Visit(stmt);
                // bake the class
                cd.typ = cd.typBld.CreateType();
                cd = null;
            }
            else if (node is FUNCTION_DECLARATION) {
                fd = (FUNCTION_DECLARATION)node;
                // get ILGenerator and check if this is a static function or not
                bool staticFunction;
                if (fd.name == "__construct" || fd.name == "__constructStatic") {
                    ilGen = fd.ctrBld.GetILGenerator();
                    staticFunction = fd.ctrBld.IsStatic;
                }
                else {
                    ilGen = fd.mthBld.GetILGenerator();
                    staticFunction = fd.mthBld.IsStatic;
                }
                // in constructors, store initial class member values
                if (fd.name == "__construct" || fd.name == "__constructStatic") {
                    CLASS_DECLARATION tmpCd = cd;
                    ArrayList namesAlreadyAdded = new ArrayList();
                    do { // fetch class variable declarations of current class
                        ArrayList classVarDecls = tmpCd.scope.lookup(SymbolTable.CLASS_VARIABLE);
                        foreach (SymbolTableEntry cvdEntry in classVarDecls) {
                            CLASS_VARIABLE_DECLARATION cvd = (CLASS_VARIABLE_DECLARATION)cvdEntry.node;
                            for (int i = 0; i < cvd.names.Count; i++) {
                                FieldBuilder fb = (FieldBuilder)cvd.fieldBuilders[i];
                                string name = (string)cvd.names[i];
                                Expression value = cvd.values.Get(i);
                                // only process names not already added
                                if (namesAlreadyAdded.Contains(name))
                                    continue;
                                bool cvdIsVisible = tmpCd == cd || !cvd.modifiers.Contains(Modifiers.PRIVATE);
                                bool cvdIsStatic = cvd.modifiers.Contains(Modifiers.STATIC) || cvd.modifiers.Contains(Modifiers.CONST);
                                // in a static constructor, store initial static class member values
                                if (fd.name == "__constructStatic" && cvdIsVisible && cvdIsStatic) {
                                    if (value == null)
                                        ilGen.Emit(OpCodes.Newobj, PHPNull.GetConstructor(Type.EmptyTypes));
                                    else
                                        Visit(value);
                                    ilGen.Emit(OpCodes.Stsfld, fb);
                                    namesAlreadyAdded.Add(name);
                                }
                                // in a local constructor, store initial local class member values
                                if (fd.name == "__construct" && cvdIsVisible && !cvdIsStatic) {
                                    ilGen.Emit(OpCodes.Ldarg_0);
                                    if (value == null)
                                        ilGen.Emit(OpCodes.Newobj, PHPNull.GetConstructor(Type.EmptyTypes));
                                    else
                                        Visit(value);
                                    ilGen.Emit(OpCodes.Stfld, fb);
                                    namesAlreadyAdded.Add(name);
                                }
                            }
                        }
                        // fetch parent class declaration
                        if (tmpCd.extends == null)
                            tmpCd = null;
                        else {
                            SymbolTableEntry parentCdEntry = SymbolTable.getInstance().lookupGlobal(tmpCd.extends.ToLower(), SymbolTable.CLASS);
                            tmpCd = (CLASS_DECLARATION)parentCdEntry.node;
                        }
                    } while (tmpCd != null);

                }
                // store parameters passed as local variable
                PARAMETER_DECLARATION pd;
                for (int i = 0; i < fd.parameters.Count; i++) {
                    pd = (PARAMETER_DECLARATION)fd.parameters[i];
                    // push value passed
                    ilGen.Emit(OpCodes.Ldarg, i + (staticFunction ? 0 : 1));
                    // if value passed is Null, use default value, if available
                    if (pd.default_value != null) {
                        Label skip = ilGen.DefineLabel();
                        ilGen.Emit(OpCodes.Dup);
                        ilGen.Emit(OpCodes.Isinst, PHPNull);
                        ilGen.Emit(OpCodes.Brfalse, skip);
                        ilGen.Emit(OpCodes.Pop);
                        Visit(pd.default_value);
                        ilGen.MarkLabel(skip);
                    }
                    // check if class type hint is ok
                    if (pd.type != null) {
                        ilGen.Emit(OpCodes.Dup);
                        ilGen.Emit(OpCodes.Ldstr, pd.type);
                        ilGen.Emit(OpCodes.Ldc_I4_0);
                        ilGen.Emit(OpCodes.Ldc_I4_1);
                        ilGen.Emit(OpCodes.Call, typeof(Type).GetMethod("GetType", new Type[] { typeof(string), typeof(bool), typeof(bool) }));
                        ilGen.Emit(OpCodes.Ldc_I4, i + (staticFunction ? 1 : 2));
                        ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("CheckTypeHint", new Type[] { PHPMixed, typeof(Type), typeof(int) }));
                    }
                    // store
                    StoreToVariable(pd.name);
                }
                // process statements
                if (fd.stmt_list.Count() == 0)
                    ilGen.Emit(OpCodes.Nop);
                else
                    foreach (Statement stmt in fd.stmt_list)
                        Visit(stmt);
                ilGen = null;
                fd = null;
            }
            else if (node is GLOBAL) {
                GLOBAL g = (GLOBAL)node;
                foreach (VARIABLE var in g.var_list)
                    fd.scope.globalVariables.Add(var.name);
            }
            else if (node is STATIC_DECLARATION) {
                STATIC_DECLARATION sd = (STATIC_DECLARATION)node;
                foreach (Expression expr in sd.expr_list) {
                    if (expr is VARIABLE) {
                        ilGen.Emit(OpCodes.Newobj, PHPNull.GetConstructor(Type.EmptyTypes));
                        StoreToStaticVariable(((VARIABLE)expr).name);
                    }
                    if (expr is EQUALS) {
                        Visit(((EQUALS)expr).expr2);
                        StoreToStaticVariable(((VARIABLE)((EQUALS)expr).expr1).name);
                    }
                }
            }
            else if (node is ECHO) {
                ECHO e = (ECHO)node;
                foreach (Expression e2 in e.expr_list) {
                    Visit(e2);
                    ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("Echo", new Type[] { PHPMixed }));
                }
            }
            else if (node is BLOCK) {
                BLOCK b = (BLOCK)node;
                foreach (Statement stmt in b.stmt_list)
                    Visit(stmt);
            }
            else if (node is StatementList) {
                StatementList s = (StatementList)node;
                // process statements of block
                foreach (Statement stmt in s)
                    Visit(stmt);
            }
            else if (node is IF) {
                IF i = (IF)node;
                Label nextCheck = ilGen.DefineLabel();
                Label endIf = ilGen.DefineLabel();
                // process if statement
                Visit(i.expr);
                ilGen.Emit(OpCodes.Call, PHPCoreConvert.GetMethod("ToValueBool", new Type[] { PHPMixed }));
                ilGen.Emit(OpCodes.Brfalse, nextCheck);
                Visit(i.stmt);
                ilGen.Emit(OpCodes.Br, endIf);
                ilGen.MarkLabel(nextCheck);
                // process elseif statements
                foreach (ELSEIF e in i.elseif_list) {
                    //Visit(e);
                    ELSEIF ei = (ELSEIF)node;
                    Label nextCheck2 = ilGen.DefineLabel();
                    // process else statement
                    Visit(ei.expr);
                    ilGen.Emit(OpCodes.Call, PHPCoreConvert.GetMethod("ToValueBool", new Type[] { PHPMixed }));
                    ilGen.Emit(OpCodes.Brfalse, nextCheck2);
                    Visit(ei.stmt);
                    ilGen.Emit(OpCodes.Br, endIf);
                    ilGen.MarkLabel(nextCheck2);
                }
                // process else statement
                Visit(i.else_stmt);
                // done
                ilGen.MarkLabel(endIf);
                endIf = new Label();
            }
            else if (node is WHILE) {
                WHILE w = (WHILE)node;
                enterLoop = ilGen.DefineLabel();
                exitLoop = ilGen.DefineLabel();
                ilGen.MarkLabel(enterLoop);
                Visit(w.expr);
                ilGen.Emit(OpCodes.Call, PHPCoreConvert.GetMethod("ToValueBool", new Type[] { PHPMixed }));
                ilGen.Emit(OpCodes.Brfalse, exitLoop);
                Visit(w.stmt);
                ilGen.Emit(OpCodes.Br, enterLoop);
                ilGen.MarkLabel(exitLoop);
            }
            else if (node is DO) {
                DO d = (DO)node;
                enterLoop = ilGen.DefineLabel();
                exitLoop = ilGen.DefineLabel();
                ilGen.MarkLabel(enterLoop);
                Visit(d.stmt);
                Visit(d.expr);
                ilGen.Emit(OpCodes.Call, PHPCoreConvert.GetMethod("ToValueBool", new Type[] { PHPMixed }));
                ilGen.Emit(OpCodes.Brfalse, exitLoop);
                ilGen.Emit(OpCodes.Br, enterLoop);
                ilGen.MarkLabel(exitLoop);
            }
            else if (node is FOR) {
                FOR f = (FOR)node;
                enterLoop = ilGen.DefineLabel();
                exitLoop = ilGen.DefineLabel();
                foreach (Expression expr in f.expr_list1) {
                    Visit(expr);
                    // pop to treat for expression(s) 1 as statement(s)
                    ilGen.Emit(OpCodes.Pop);
                }
                ilGen.MarkLabel(enterLoop);
                IEnumerator ienum = f.expr_list2.GetEnumerator();
                bool hasMore = ienum.MoveNext();
                while (hasMore) {
                    Visit((Expression)ienum.Current);
                    hasMore = ienum.MoveNext();
                    if (hasMore)
                        // if more than one expression 2, pop all except last one to only decide on last one for jumping
                        ilGen.Emit(OpCodes.Pop);
                }
                // if for expression 2 is empty, the loop should run indefinitely
                if (f.expr_list2.Count() > 0) {
                    ilGen.Emit(OpCodes.Call, PHPCoreConvert.GetMethod("ToValueBool", new Type[] { PHPMixed }));
                    ilGen.Emit(OpCodes.Brfalse, exitLoop);
                }
                Visit(f.stmt);
                foreach (Expression expr in f.expr_list3) {
                    Visit(expr);
                    // pop to treat for expression(s) 3 as statement(s)
                    ilGen.Emit(OpCodes.Pop);
                }
                ilGen.Emit(OpCodes.Br, enterLoop);
                ilGen.MarkLabel(exitLoop);
            }
            else if (node is FOREACH) {
                FOREACH f = (FOREACH)node;
                if (f.key != null && f.key is FUNCTION_CALL)
                    Report.Error(408, f.key.line, f.key.column);
                if (f.value is FUNCTION_CALL)
                    Report.Error(408, f.value.line, f.value.column);
                enterLoop = ilGen.DefineLabel();
                exitLoop = ilGen.DefineLabel();
                Label warn = ilGen.DefineLabel();
                // push array reference
                Visit(f.array);
                // if type is not array, jump to end
                ilGen.Emit(OpCodes.Dup);
                ilGen.Emit(OpCodes.Isinst, PHPArray);
                ilGen.Emit(OpCodes.Brfalse, warn);
                // if array is not referenced, clone to acheive value semantics
                if (!(f.value is REFERENCE))
                    ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("Clone", new Type[] { PHPMixed }));
                // declare key and value variable
                string valueName;
                if (f.value is VARIABLE)
                    valueName = ((VARIABLE)f.value).name;
                else
                    valueName = ((VARIABLE)((REFERENCE)f.value).variable).name;
                if (f.key != null) {
                    ilGen.Emit(OpCodes.Ldnull);
                    StoreToVariable(((VARIABLE)f.key).name);
                }
                ilGen.Emit(OpCodes.Ldnull);
                StoreToVariable(valueName);
                // reset public array pointer
                ilGen.Emit(OpCodes.Dup);
                ilGen.Emit(OpCodes.Callvirt, PHPArray.GetMethod("Reset", Type.EmptyTypes));
                ilGen.Emit(OpCodes.Pop);
                // enter loop
                ilGen.MarkLabel(enterLoop);
                // check if public array pointer is inside the array
                ilGen.Emit(OpCodes.Dup);
                ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("CurrentIsValid", new Type[] { PHPArray }));
                // if not, exit loop
                ilGen.Emit(OpCodes.Brfalse, exitLoop);
                // if key variable declared, push current key of array and store to key variable
                if (f.key != null) {
                    ilGen.Emit(OpCodes.Dup);
                    ilGen.Emit(OpCodes.Callvirt, PHPArray.GetMethod("Key", Type.EmptyTypes));
                    StoreToVariable(((VARIABLE)f.key).name);
                }
                // push current value of array and store to value variable
                ilGen.Emit(OpCodes.Dup);
                ilGen.Emit(OpCodes.Callvirt, PHPArray.GetMethod("Current", Type.EmptyTypes));
                StoreToVariable(valueName);
                // process foreach statement
                Visit(f.stmt);
                // load value variable and store as current value of array
                ilGen.Emit(OpCodes.Dup);
                ilGen.Emit(OpCodes.Dup);
                ilGen.Emit(OpCodes.Callvirt, PHPArray.GetMethod("Key", Type.EmptyTypes));
                LoadFromVariable(valueName);
                ilGen.Emit(OpCodes.Callvirt, PHPArray.GetMethod("Append", new Type[] { PHPMixed, PHPMixed }));
                // advance public array pointer
                ilGen.Emit(OpCodes.Dup);
                ilGen.Emit(OpCodes.Callvirt, PHPArray.GetMethod("Next", Type.EmptyTypes));
                ilGen.Emit(OpCodes.Pop);
                // and reenter loop
                ilGen.Emit(OpCodes.Br, enterLoop);
                // report invalid argument
                ilGen.MarkLabel(warn);
                ilGen.Emit(OpCodes.Ldc_I4, 407);
                ilGen.Emit(OpCodes.Ldc_I4, f.line);
                ilGen.Emit(OpCodes.Ldc_I4, f.column);
                ilGen.Emit(OpCodes.Call, mPHPRuntime.GetType("PHP.Core.Report").GetMethod("Warn", new Type[] { typeof(int), typeof(int), typeof(int) }));
                // pop array reference
                ilGen.MarkLabel(exitLoop);
                ilGen.Emit(OpCodes.Pop);
            }
            else if (node is SWITCH) {
                SWITCH s = (SWITCH)node;
                enterLoop = ilGen.DefineLabel();
                exitLoop = ilGen.DefineLabel();
                // push switch expression and enter loop
                Visit(s.expr);
                ilGen.MarkLabel(enterLoop);
                // process case and default statements
                foreach (ASTNode node2 in s.switch_case_list) {
                    if (node2 is CASE)
                        Visit((CASE)node2);
                    else if (node2 is DEFAULT)
                        Visit((DEFAULT)node2);
                }
                // done
                ilGen.MarkLabel(exitLoop);
                ilGen.Emit(OpCodes.Pop);
                ilGen.Emit(OpCodes.Ldc_I4_0);
                ilGen.Emit(OpCodes.Stsfld, PHPCoreRuntime.GetField("switchInProgress"));
            }
            else if (node is CASE) {
                CASE c = (CASE)node;
                Label processCase = ilGen.DefineLabel();
                Label nextCase = ilGen.DefineLabel();
                // if statements already processing, process this one as well
                ilGen.Emit(OpCodes.Ldsfld, PHPCoreRuntime.GetField("switchInProgress"));
                ilGen.Emit(OpCodes.Brtrue, processCase);
                // else if case expression doesn't equal switch expression, jump to next case
                ilGen.Emit(OpCodes.Dup);
                Visit(c.expr);
                ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("IsEqual", new Type[] { PHPMixed, PHPMixed }));
                ilGen.Emit(OpCodes.Call, PHPCoreConvert.GetMethod("ToValueBool", new Type[] { PHPMixed }));
                ilGen.Emit(OpCodes.Brfalse, nextCase);
                // else start processing switch statements
                ilGen.Emit(OpCodes.Ldc_I4_1);
                ilGen.Emit(OpCodes.Stsfld, PHPCoreRuntime.GetField("switchInProgress"));
                // process case statement
                ilGen.MarkLabel(processCase);
                Visit(c.stmt);
                // mark start of next case
                ilGen.MarkLabel(nextCase);
            }
            else if (node is DEFAULT) {
                DEFAULT d = (DEFAULT)node;
                // process default statement
                ilGen.Emit(OpCodes.Ldc_I4_1);
                ilGen.Emit(OpCodes.Stsfld, PHPCoreRuntime.GetField("switchInProgress"));
                Visit(d.stmt);
            }
            else if (node is BREAK) {
                BREAK b = (BREAK)node;
                ilGen.Emit(OpCodes.Br, exitLoop);
            }
            else if (node is CONTINUE) {
                CONTINUE c = (CONTINUE)node;
                ilGen.Emit(OpCodes.Br, enterLoop);
            }
            else if (node is RETURN) {
                RETURN r = (RETURN)node;
                if (fd.name != "__MAIN" && fd.name != "__construct" && fd.name != "__constructStatic") {
                    // if no return value specified, use Null as return value; otherwise use return value specified
                    if (r.expr == null)
                        ilGen.Emit(OpCodes.Newobj, PHPNull.GetConstructor(Type.EmptyTypes));
                    else
                        Visit(r.expr);
                }
                ilGen.Emit(OpCodes.Ret);
            }
            else if (node is UNSET) {
                UNSET u = (UNSET)node;
                // unset variables
                for (int i = 0; i < u.var_list.Count(); i++) {
                    if (u.var_list.Get(i) is FUNCTION_CALL)
                        Report.Error(408, u.var_list.Get(i).line, u.var_list.Get(i).column);
                    VARIABLE var = (VARIABLE)u.var_list.Get(i);
                    // regular variable, so unset
                    if (var.offset == null) {
                        ilGen.Emit(OpCodes.Ldstr, var.name);
                        ilGen.Emit(OpCodes.Newobj, PHPString.GetConstructor(new Type[] { typeof(string) }));
                        ilGen.Emit(OpCodes.Call, PHPCoreRuntime.GetMethod("UnsetVariable", new Type[] { PHPMixed }));
                    }
                    // array item, so remove from array
                    else if (var.offset.kind == OFFSET.SQUARE) {
                        LoadFromVariable(var.name);
                        // convert to Array (in case the variable was unset)
                        ilGen.Emit(OpCodes.Call, PHPCoreConvert.GetMethod("ToArray", new Type[] { PHPMixed }));
                        if (var.offset.value == null)
                            ilGen.Emit(OpCodes.Ldnull);
                        else
                            Visit(var.offset);
                        ilGen.Emit(OpCodes.Callvirt, PHPArray.GetMethod("Remove", new Type[] { PHPMixed }));
                    }
                }
            }
            else if (node is EXPRESSION_AS_STATEMENT) {
                EXPRESSION_AS_STATEMENT eas = (EXPRESSION_AS_STATEMENT)node;
                Visit(eas.expr);
                ilGen.Emit(OpCodes.Pop);
            }
            else if (node is VARIABLE) {
                VARIABLE var = (VARIABLE)node;
                // get desired variable value
                LoadFromVariable(var.name);
                // process offset, if available
                if (var.offset != null) {
                    // this is an array
                    if (var.offset.kind == OFFSET.SQUARE) {
                        if (var.offset.value == null)
                            ilGen.Emit(OpCodes.Ldnull);
                        else
                            Visit(var.offset);
                        ilGen.Emit(OpCodes.Ldc_I4, OFFSET.SQUARE);
                        ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("Offset", new Type[] { PHPMixed, PHPMixed, typeof(int) }));
                    }
                }
            }
            else if (node is REFERENCE) {
                REFERENCE r = (REFERENCE)node;
                // process enclosed variable or function call
                if (r.variable is VARIABLE)
                    Visit((VARIABLE)r.variable);
                else if (r.variable is FUNCTION_CALL)
                    Visit((FUNCTION_CALL)r.variable);
            }
            else if (node is OFFSET) {
                OFFSET o = (OFFSET)node;
                // process offset expression
                Visit(o.value);
            }
            else if (node is FUNCTION_CALL) {
                FUNCTION_CALL fc = (FUNCTION_CALL)node;
                // catch predefined functions
                if (fc.function_name.ToLower() == "define") {
                    PushParameters(fc.parameters, 3);
                    ilGen.Emit(OpCodes.Call, PHPCoreRuntime.GetMethod("DefineConstant", new Type[] { PHPMixed, PHPMixed, PHPMixed }));
                }
                // otherwise call user defined function
                else {
                    // look in global scope as calls to functions in user defined classed are handled by object operator or paamayim nekudotayim
                    SymbolTable st = SymbolTable.getInstance();
                    SymbolTableEntry entry = cd.scope.lookup(fc.function_name.ToLower(), SymbolTable.FUNCTION);
                    if (entry == null)
                        Report.Error(212, fc.function_name, fc.line, fc.column);
                    FUNCTION_DECLARATION fd = (FUNCTION_DECLARATION)entry.node;
                    // pass parameters (only as many as needed)
                    int parametersPassedActually = (int)Math.Min(fd.parameters.Count, fc.parameters.Count());
                    for (int i = 0; i < parametersPassedActually; i++) {
                        PARAMETER_DECLARATION pd = (PARAMETER_DECLARATION)fd.parameters[i];
                        Expression expr = (Expression)fc.parameters.Get(i);
                        Visit(expr);
                        // clone if value semantics is desired
                        if (!pd.by_reference && !(expr is REFERENCE))
                            ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("Clone", new Type[] { PHPMixed }));
                    }
                    // if less parameters actually passed then necessary, pass Null objects instead
                    for (int i = parametersPassedActually; i < fd.parameters.Count; i++) {
                        PARAMETER_DECLARATION pd = (PARAMETER_DECLARATION)fd.parameters[i];
                        if (pd.default_value == null)
                            Report.Warn(300, System.Convert.ToString(i + 1), fc.line, fc.column);
                        ilGen.Emit(OpCodes.Newobj, PHPNull.GetConstructor(Type.EmptyTypes));
                    }
                    // ensure parameters passed by reference are variables
                    for (int i = 0; i < parametersPassedActually; i++) {
                        PARAMETER_DECLARATION pd = (PARAMETER_DECLARATION)fd.parameters[i];
                        Expression variableSupplied = (Expression)fc.parameters.Get(i);
                        if (pd.by_reference || variableSupplied is REFERENCE)
                            if (!(variableSupplied is VARIABLE || variableSupplied is REFERENCE))
                                Report.Error(301, System.Convert.ToString(i + 1), variableSupplied.line, variableSupplied.column);
                    }
                    // add function call to call trace
                    ilGen.Emit(OpCodes.Ldstr, cd.name + "->" + fc.function_name);
                    ilGen.Emit(OpCodes.Call, PHPCoreRuntime.GetMethod("AddFunctionCallToTrace", new Type[] { typeof(string) }));
                    // if an object operator in progress, call instance function
                    if (objectOperatorInProgress)
                        ilGen.Emit(OpCodes.Call, fd.mthBld);
                    // else call static function
                    else
                        ilGen.Emit(OpCodes.Call, fd.mthBld);
                    // remove function call from call trace
                    ilGen.Emit(OpCodes.Call, PHPCoreRuntime.GetMethod("RemoveFunctionCallFromTrace", Type.EmptyTypes));
                }
            }
            else if (node is NEW) {
                NEW n = (NEW)node;
                SymbolTableEntry cdEntry = SymbolTable.getInstance().lookupGlobal(n.type.ToLower(), SymbolTable.CLASS);
                if (cdEntry == null)
                    Report.Error(203, n.type, n.line, n.column);
                CLASS_DECLARATION cd = (CLASS_DECLARATION)cdEntry.node;
                SymbolTableEntry ctorEntry = cd.scope.lookup("__construct", SymbolTable.FUNCTION);
                FUNCTION_DECLARATION ctorDecl = (FUNCTION_DECLARATION)ctorEntry.node;
                // pass parameters (only as many as needed)
                int parametersPassedActually = (int)Math.Min(ctorDecl.parameters.Count, n.ctor_args.Count());
                for (int i = 0; i < parametersPassedActually; i++) {
                    Expression expr = (Expression)n.ctor_args.Get(i);
                    Visit(expr);
                }
                // if less parameters actually passed then necessary, pass Null objects instead
                for (int i = parametersPassedActually; i < ctorDecl.parameters.Count; i++) {
                    PARAMETER_DECLARATION pd = (PARAMETER_DECLARATION)ctorDecl.parameters[i];
                    if (pd.default_value == null)
                        Report.Warn(300, System.Convert.ToString(i + 1), n.line, n.column);
                    ilGen.Emit(OpCodes.Newobj, PHPNull.GetConstructor(Type.EmptyTypes));
                }
                // ensure parameters passed by reference are vairables
                for (int i = 0; i < parametersPassedActually; i++) {
                    PARAMETER_DECLARATION pd = (PARAMETER_DECLARATION)ctorDecl.parameters[i];
                    Expression variableSupplied = (Expression)n.ctor_args.Get(i);
                    if (pd.by_reference || variableSupplied is REFERENCE)
                        if (!(variableSupplied is VARIABLE || variableSupplied is REFERENCE))
                            Report.Error(301, System.Convert.ToString(i + 1), variableSupplied.line, variableSupplied.column);
                }
                // add constructor call to call trace
                ilGen.Emit(OpCodes.Ldstr, n.type + "->__construct");
                ilGen.Emit(OpCodes.Call, PHPCoreRuntime.GetMethod("AddFunctionCallToTrace", new Type[] { typeof(string) }));
                // call constructor
                ilGen.Emit(OpCodes.Newobj, ctorDecl.ctrBld);
                // remove constructor call from call trace
                ilGen.Emit(OpCodes.Call, PHPCoreRuntime.GetMethod("RemoveFunctionCallFromTrace", Type.EmptyTypes));
            }
            else if (node is INSTANCEOF) {
                INSTANCEOF i = (INSTANCEOF)node;
                Visit(i.expr);
                ilGen.Emit(OpCodes.Ldstr, i.type);
                ilGen.Emit(OpCodes.Ldc_I4_0);
                ilGen.Emit(OpCodes.Ldc_I4_1);
                ilGen.Emit(OpCodes.Call, typeof(Type).GetMethod("GetType", new Type[] { typeof(string), typeof(bool), typeof(bool) }));
                ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("Instanceof", new Type[] { PHPMixed, typeof(Type) }));
            }
            else if (node is ARRAY) {
                ARRAY a = (ARRAY)node;
                // create new empty array
                ilGen.Emit(OpCodes.Newobj, PHPArray.GetConstructor(Type.EmptyTypes));
                // process array pairs
                foreach (ARRAY_PAIR ap in a.array_pair_list) {
                    // duplicate reference to array (in order not to loose it after append)
                    ilGen.Emit(OpCodes.Dup);
                    // process key
                    if (ap.key == null)
                        ilGen.Emit(OpCodes.Ldnull);
                    else
                        Visit(ap.key);
                    // process value
                    if (ap.value is REFERENCE)
                        if (((REFERENCE)ap.value).variable is FUNCTION_CALL)
                            Report.Error(408, ap.line, ap.column);
                    Visit(ap.value);
                    ilGen.Emit(OpCodes.Callvirt, PHPArray.GetMethod("Append", new Type[] { PHPMixed, PHPMixed }));
                }
            }
            else if (node is INC) {
                INC i = (INC)node;
                if (i.expr is FUNCTION_CALL)
                    Report.Error(408, i.expr.line, i.expr.column);
                LoadFromVariable(((VARIABLE)i.expr).name);
                if (i.kind == 1) {
                    ilGen.Emit(OpCodes.Dup);
                    ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("Clone", new Type[] { PHPMixed }));
                }
                ilGen.Emit(OpCodes.Ldc_I4_1);
                ilGen.Emit(OpCodes.Newobj, PHPInteger.GetConstructor(new Type[] { typeof(int) }));
                ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("Plus", new Type[] { PHPMixed, PHPMixed }));
                if (i.kind == 0) {
                    ilGen.Emit(OpCodes.Dup);
                    ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("Clone", new Type[] { PHPMixed }));
                }
                StoreToVariable(((VARIABLE)i.expr).name);
            }
            else if (node is DEC) {
                DEC d = (DEC)node;
                if (d.expr is FUNCTION_CALL)
                    Report.Error(408, d.expr.line, d.expr.column);
                LoadFromVariable(((VARIABLE)d.expr).name);
                if (d.kind == 1)
                    ilGen.Emit(OpCodes.Dup);
                ilGen.Emit(OpCodes.Ldc_I4_1);
                ilGen.Emit(OpCodes.Newobj, PHPInteger.GetConstructor(new Type[] { typeof(int) }));
                ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("Minus", new Type[] { PHPMixed, PHPMixed }));
                if (d.kind == 0)
                    ilGen.Emit(OpCodes.Dup);
                StoreToVariable(((VARIABLE)d.expr).name);
            }
            else if (node is BOOLEAN_NOT) {
                BOOLEAN_NOT bn = (BOOLEAN_NOT)node;
                Visit(bn.expr);
                ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("BooleanNot", new Type[] { PHPMixed }));
            }
            else if (node is NOT) {
                NOT n = (NOT)node;
                Visit(n.expr);
                ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("Not", new Type[] { PHPMixed }));
            }
            else if (node is EXIT) {
                EXIT e = (EXIT)node;
                if (e.expr == null)
                    ilGen.Emit(OpCodes.Newobj, PHPNull.GetConstructor(Type.EmptyTypes));
                else
                    Visit(e.expr);
                ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("Exit", new Type[] { PHPMixed }));
            }
            else if (node is PRINT) {
                PRINT p = (PRINT)node;
                Visit(p.expr);
                ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("Print", new Type[] { PHPMixed }));
            }
            else if (node is BOOL_CAST) {
                BOOL_CAST bc = (BOOL_CAST)node;
                Visit(bc.expr);
                ilGen.Emit(OpCodes.Call, PHPCoreConvert.GetMethod("ToBoolean", new Type[] { PHPMixed }));
            }
            else if (node is INT_CAST) {
                INT_CAST ic = (INT_CAST)node;
                Visit(ic.expr);
                ilGen.Emit(OpCodes.Call, PHPCoreConvert.GetMethod("ToInteger", new Type[] { PHPMixed }));
            }
            else if (node is DOUBLE_CAST) {
                DOUBLE_CAST dc = (DOUBLE_CAST)node;
                Visit(dc.expr);
                ilGen.Emit(OpCodes.Call, PHPCoreConvert.GetMethod("ToDouble", new Type[] { PHPMixed }));
            }
            else if (node is STRING_CAST) {
                STRING_CAST sc = (STRING_CAST)node;
                Visit(sc.expr);
                ilGen.Emit(OpCodes.Call, PHPCoreConvert.GetMethod("ToString", new Type[] { PHPMixed }));
            }
            else if (node is ARRAY_CAST) {
                ARRAY_CAST ac = (ARRAY_CAST)node;
                Visit(ac.expr);
                ilGen.Emit(OpCodes.Call, PHPCoreConvert.GetMethod("ToArray", new Type[] { PHPMixed }));
            }
            else if (node is OBJECT_CAST) {
                OBJECT_CAST oc = (OBJECT_CAST)node;
                Visit(oc.expr);
                ilGen.Emit(OpCodes.Call, PHPCoreConvert.GetMethod("ToObject", new Type[] { PHPMixed }));
            }
            else if (node is CLONE) {
                CLONE c = (CLONE)node;
                Visit(c.expr);
                ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("Clone", new Type[] { PHPMixed }));
            }
            else if (node is PAAMAYIM_NEKUDOTAYIM) {
                PAAMAYIM_NEKUDOTAYIM pn = (PAAMAYIM_NEKUDOTAYIM)node;
                LoadFromPaamayimNekudotayim(pn);
            }
            else if (node is OBJECT_OPERATOR) {
                OBJECT_OPERATOR oo = (OBJECT_OPERATOR)node;
                LoadFromObjectOperator(oo);
            }
            else if (node is EQUALS) {
                EQUALS e = (EQUALS)node;
                if (e.expr1 is FUNCTION_CALL)
                    Report.Error(408, e.expr1.line, e.expr1.column);
                // push assigned value as result of this equals expression
                Visit(e.expr2);
                // store to an object operator expression
                if (e.expr1 is OBJECT_OPERATOR)
                    StoreToObjectOperator((OBJECT_OPERATOR)e.expr1, e.expr2);
                // store to an object operator expression
                else if (e.expr1 is PAAMAYIM_NEKUDOTAYIM)
                    StoreToPaamayimNekudotayim((PAAMAYIM_NEKUDOTAYIM)e.expr1, e.expr2);
                // store to a variable expression
                else if (e.expr1 is VARIABLE) {
                    VARIABLE var = (VARIABLE)e.expr1;
                    // determine value or reference semantis
                    bool referenceSemantics = false;
                    // if assigned expr is a reference
                    if (e.expr2 is REFERENCE) {
                        REFERENCE r = (REFERENCE)e.expr2;
                        // and a variable is called, it's reference semantics
                        if (r.variable is VARIABLE)
                            referenceSemantics = true;
                        // and a function not returnung a reference is called, it's reference semantics
                        if (r.variable is FUNCTION_CALL) {
                            SymbolTableEntry entry = SymbolTable.getInstance().lookup(((FUNCTION_CALL)r.variable).function_name.ToLower(), SymbolTable.FUNCTION);
                            FUNCTION_DECLARATION fd = (FUNCTION_DECLARATION)entry.node;
                            if (fd.return_by_reference)
                                referenceSemantics = true;
                        }
                    }
                    // if there is no offset, just store to that variable
                    if (var.offset == null) {
                        ilGen.Emit(OpCodes.Dup);
                        if (!referenceSemantics)
                            ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("Clone", new Type[] { PHPMixed }));
                        StoreToVariable(var.name);
                    }
                    // if there is an array offset, load array and store to specified place of that array
                    else if (var.offset.kind == OFFSET.SQUARE) {
                        LoadFromVariable(var.name);
                        // if array loaded is null, create a new one and store
                        Label skip = ilGen.DefineLabel();
                        ilGen.Emit(OpCodes.Isinst, PHPNull);
                        ilGen.Emit(OpCodes.Brfalse, skip);
                        ilGen.Emit(OpCodes.Newobj, PHPArray.GetConstructor(Type.EmptyTypes));
                        StoreToVariable(var.name);
                        ilGen.MarkLabel(skip);
                        LoadFromVariable(var.name);
                        // convert to Array (in case the variable was unset)
                        ilGen.Emit(OpCodes.Call, PHPCoreConvert.GetMethod("ToArray", new Type[] { PHPMixed }));
                        // if value of offset is null, push null to automatically calculate key
                        if (var.offset.value == null)
                            ilGen.Emit(OpCodes.Ldnull);
                        // if a value is given, push that value
                        else
                            Visit(var.offset.value);
                        Visit(e.expr2);
                        if (!referenceSemantics)
                            ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("Clone", new Type[] { PHPMixed }));
                        ilGen.Emit(OpCodes.Callvirt, PHPArray.GetMethod("Append", new Type[] { PHPMixed, PHPMixed }));
                    }
                }
            }
            else if (node is PLUS_EQUAL) {
                PLUS_EQUAL pe = (PLUS_EQUAL)node;
                if (pe.expr1 is FUNCTION_CALL)
                    Report.Error(408, pe.expr1.line, pe.expr1.column);
                LoadFromVariable(((VARIABLE)pe.expr1).name);
                Visit(pe.expr2);
                ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("Plus", new Type[] { PHPMixed, PHPMixed }));
                ilGen.Emit(OpCodes.Dup);
                StoreToVariable(((VARIABLE)pe.expr1).name);
            }
            else if (node is MINUS_EQUAL) {
                MINUS_EQUAL me = (MINUS_EQUAL)node;
                if (me.expr1 is FUNCTION_CALL)
                    Report.Error(408, me.expr1.line, me.expr1.column);
                LoadFromVariable(((VARIABLE)me.expr1).name);
                Visit(me.expr2);
                ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("Minus", new Type[] { PHPMixed, PHPMixed }));
                ilGen.Emit(OpCodes.Dup);
                StoreToVariable(((VARIABLE)me.expr1).name);
            }
            else if (node is MUL_EQUAL) {
                MUL_EQUAL me = (MUL_EQUAL)node;
                if (me.expr1 is FUNCTION_CALL)
                    Report.Error(408, me.expr1.line, me.expr1.column);
                LoadFromVariable(((VARIABLE)me.expr1).name);
                Visit(me.expr2);
                ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("Mul", new Type[] { PHPMixed, PHPMixed }));
                ilGen.Emit(OpCodes.Dup);
                StoreToVariable(((VARIABLE)me.expr1).name);
            }
            else if (node is DIV_EQUAL) {
                DIV_EQUAL de = (DIV_EQUAL)node;
                if (de.expr1 is FUNCTION_CALL)
                    Report.Error(408, de.expr1.line, de.expr1.column);
                LoadFromVariable(((VARIABLE)de.expr1).name);
                Visit(de.expr2);
                ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("Div", new Type[] { PHPMixed, PHPMixed }));
                ilGen.Emit(OpCodes.Dup);
                StoreToVariable(((VARIABLE)de.expr1).name);
            }
            else if (node is CONCAT_EQUAL) {
                CONCAT_EQUAL ce = (CONCAT_EQUAL)node;
                if (ce.expr1 is FUNCTION_CALL)
                    Report.Error(408, ce.expr1.line, ce.expr1.column);
                LoadFromVariable(((VARIABLE)ce.expr1).name);
                Visit(ce.expr2);
                ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("Concat", new Type[] { PHPMixed, PHPMixed }));
                ilGen.Emit(OpCodes.Dup);
                StoreToVariable(((VARIABLE)ce.expr1).name);
            }
            else if (node is MOD_EQUAL) {
                MOD_EQUAL me = (MOD_EQUAL)node;
                if (me.expr1 is FUNCTION_CALL)
                    Report.Error(408, me.expr1.line, me.expr1.column);
                LoadFromVariable(((VARIABLE)me.expr1).name);
                Visit(me.expr2);
                ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("Mod", new Type[] { PHPMixed, PHPMixed }));
                ilGen.Emit(OpCodes.Dup);
                StoreToVariable(((VARIABLE)me.expr1).name);
            }
            else if (node is AND_EQUAL) {
                AND_EQUAL ae = (AND_EQUAL)node;
                if (ae.expr1 is FUNCTION_CALL)
                    Report.Error(408, ae.expr1.line, ae.expr1.column);
                LoadFromVariable(((VARIABLE)ae.expr1).name);
                Visit(ae.expr2);
                ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("And", new Type[] { PHPMixed, PHPMixed }));
                ilGen.Emit(OpCodes.Dup);
                StoreToVariable(((VARIABLE)ae.expr1).name);
            }
            else if (node is OR_EQUAL) {
                OR_EQUAL oe = (OR_EQUAL)node;
                if (oe.expr1 is FUNCTION_CALL)
                    Report.Error(408, oe.expr1.line, oe.expr1.column);
                LoadFromVariable(((VARIABLE)oe.expr1).name);
                Visit(oe.expr2);
                ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("Or", new Type[] { PHPMixed, PHPMixed }));
                ilGen.Emit(OpCodes.Dup);
                StoreToVariable(((VARIABLE)oe.expr1).name);
            }
            else if (node is XOR_EQUAL) {
                XOR_EQUAL xe = (XOR_EQUAL)node;
                if (xe.expr1 is FUNCTION_CALL)
                    Report.Error(408, xe.expr1.line, xe.expr1.column);
                LoadFromVariable(((VARIABLE)xe.expr1).name);
                Visit(xe.expr2);
                ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("Xor", new Type[] { PHPMixed, PHPMixed }));
                ilGen.Emit(OpCodes.Dup);
                StoreToVariable(((VARIABLE)xe.expr1).name);
            }
            else if (node is SL_EQUAL) {
                SL_EQUAL se = (SL_EQUAL)node;
                if (se.expr1 is FUNCTION_CALL)
                    Report.Error(408, se.expr1.line, se.expr1.column);
                LoadFromVariable(((VARIABLE)se.expr1).name);
                Visit(se.expr2);
                ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("Sl", new Type[] { PHPMixed, PHPMixed }));
                ilGen.Emit(OpCodes.Dup);
                StoreToVariable(((VARIABLE)se.expr1).name);
            }
            else if (node is SR_EQUAL) {
                SR_EQUAL se = (SR_EQUAL)node;
                if (se.expr1 is FUNCTION_CALL)
                    Report.Error(408, se.expr1.line, se.expr1.column);
                LoadFromVariable(((VARIABLE)se.expr1).name);
                Visit(se.expr2);
                ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("Sr", new Type[] { PHPMixed, PHPMixed }));
                ilGen.Emit(OpCodes.Dup);
                StoreToVariable(((VARIABLE)se.expr1).name);
            }
            else if (node is BOOLEAN_AND) {
                BOOLEAN_AND ba = (BOOLEAN_AND)node;
                Visit(ba.expr1);
                Visit(ba.expr2);
                ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("BooleanAnd", new Type[] { PHPMixed, PHPMixed }));
            }
            else if (node is BOOLEAN_OR) {
                BOOLEAN_OR bo = (BOOLEAN_OR)node;
                Visit(bo.expr1);
                Visit(bo.expr2);
                ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("BooleanOr", new Type[] { PHPMixed, PHPMixed }));
            }
            else if (node is LOGICAL_AND) {
                LOGICAL_AND la = (LOGICAL_AND)node;
                Visit(la.expr1);
                Visit(la.expr2);
                ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("LogicalAnd", new Type[] { PHPMixed, PHPMixed }));
            }
            else if (node is LOGICAL_OR) {
                LOGICAL_OR lo = (LOGICAL_OR)node;
                Visit(lo.expr1);
                Visit(lo.expr2);
                ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("LogicalOr", new Type[] { PHPMixed, PHPMixed }));
            }
            else if (node is LOGICAL_XOR) {
                LOGICAL_XOR lx = (LOGICAL_XOR)node;
                Visit(lx.expr1);
                Visit(lx.expr2);
                ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("LogicalXor", new Type[] { PHPMixed, PHPMixed }));
            }
            else if (node is CONCAT) {
                CONCAT c = (CONCAT)node;
                Visit(c.expr1);
                Visit(c.expr2);
                ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("Concat", new Type[] { PHPMixed, PHPMixed }));
            }
            else if (node is PLUS) {
                PLUS p = (PLUS)node;
                Visit(p.expr1);
                Visit(p.expr2);
                ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("Plus", new Type[] { PHPMixed, PHPMixed }));
            }
            else if (node is MINUS) {
                MINUS m = (MINUS)node;
                Visit(m.expr1);
                Visit(m.expr2);
                ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("Minus", new Type[] { PHPMixed, PHPMixed }));
            }
            else if (node is TIMES) {
                TIMES t = (TIMES)node;
                Visit(t.expr1);
                Visit(t.expr2);
                ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("Times", new Type[] { PHPMixed, PHPMixed }));
            }
            else if (node is DIV) {
                DIV d = (DIV)node;
                Visit(d.expr1);
                Visit(d.expr2);
                ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("Div", new Type[] { PHPMixed, PHPMixed }));
            }
            else if (node is MOD) {
                MOD m = (MOD)node;
                Visit(m.expr1);
                Visit(m.expr2);
                ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("Mod", new Type[] { PHPMixed, PHPMixed }));
            }
            else if (node is AND) {
                AND a = (AND)node;
                Visit(a.expr1);
                Visit(a.expr2);
                ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("And", new Type[] { PHPMixed, PHPMixed }));
            }
            else if (node is OR) {
                OR o = (OR)node;
                Visit(o.expr1);
                Visit(o.expr2);
                ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("Or", new Type[] { PHPMixed, PHPMixed }));
            }
            else if (node is XOR) {
                XOR x = (XOR)node;
                Visit(x.expr1);
                Visit(x.expr2);
                ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("Xor", new Type[] { PHPMixed, PHPMixed }));
            }
            else if (node is SL) {
                SL s = (SL)node;
                Visit(s.expr1);
                Visit(s.expr2);
                ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("Sl", new Type[] { PHPMixed, PHPMixed }));
            }
            else if (node is SR) {
                SL s = (SL)node;
                Visit(s.expr1);
                Visit(s.expr2);
                ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("Sr", new Type[] { PHPMixed, PHPMixed }));
            }
            else if (node is IS_EQUAL) {
                IS_EQUAL ie = (IS_EQUAL)node;
                Visit(ie.expr1);
                Visit(ie.expr2);
                ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("IsEqual", new Type[] { PHPMixed, PHPMixed }));
            }
            else if (node is IS_NOT_EQUAL) {
                IS_NOT_EQUAL ine = (IS_NOT_EQUAL)node;
                Visit(ine.expr1);
                Visit(ine.expr2);
                ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("IsNotEqual", new Type[] { PHPMixed, PHPMixed }));
            }
            else if (node is IS_IDENTICAL) {
                IS_IDENTICAL ii = (IS_IDENTICAL)node;
                Visit(ii.expr1);
                Visit(ii.expr2);
                ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("IsIdentical", new Type[] { PHPMixed, PHPMixed }));
            }
            else if (node is IS_NOT_IDENTICAL) {
                IS_NOT_IDENTICAL ini = (IS_NOT_IDENTICAL)node;
                Visit(ini.expr1);
                Visit(ini.expr2);
                ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("IsNotIdentical", new Type[] { PHPMixed, PHPMixed }));
            }
            else if (node is LOWER) {
                LOWER l = (LOWER)node;
                Visit(l.expr1);
                Visit(l.expr2);
                ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("Lower", new Type[] { PHPMixed, PHPMixed }));
            }
            else if (node is IS_LOWER_OR_EQUAL) {
                IS_LOWER_OR_EQUAL iloe = (IS_LOWER_OR_EQUAL)node;
                Visit(iloe.expr1);
                Visit(iloe.expr2);
                ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("IsLowerOrEqual", new Type[] { PHPMixed, PHPMixed }));
            }
            else if (node is GREATER) {
                GREATER g = (GREATER)node;
                Visit(g.expr1);
                Visit(g.expr2);
                ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("Greater", new Type[] { PHPMixed, PHPMixed }));
            }
            else if (node is IS_GREATER_OR_EQUAL) {
                IS_GREATER_OR_EQUAL igoe = (IS_GREATER_OR_EQUAL)node;
                Visit(igoe.expr1);
                Visit(igoe.expr2);
                ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("IsGreaterOrEqual", new Type[] { PHPMixed, PHPMixed }));
            }
            else if (node is IF_EXPR) {
                IF_EXPR ie = (IF_EXPR)node;
                Label falseBranch = ilGen.DefineLabel();
                Label mergeBranches = ilGen.DefineLabel();
                Visit(ie.expr1);
                ilGen.Emit(OpCodes.Call, PHPCoreConvert.GetMethod("ToValueBool", new Type[] { PHPMixed }));
                ilGen.Emit(OpCodes.Brfalse, falseBranch);
                Visit(ie.expr2);
                ilGen.Emit(OpCodes.Br, mergeBranches);
                ilGen.MarkLabel(falseBranch);
                Visit(ie.expr3);
                ilGen.MarkLabel(mergeBranches);
            }
            else if (node is LNUMBER_SCALAR) {
                LNUMBER_SCALAR ls = (LNUMBER_SCALAR)node;
                ilGen.Emit(OpCodes.Ldc_I4, ls.value);
                ilGen.Emit(OpCodes.Newobj, PHPInteger.GetConstructor(new Type[] { typeof(int) }));
            }
            else if (node is DNUMBER_SCALAR) {
                DNUMBER_SCALAR ds = (DNUMBER_SCALAR)node;
                ilGen.Emit(OpCodes.Ldc_R8, ds.value);
                ilGen.Emit(OpCodes.Newobj, PHPDouble.GetConstructor(new Type[] { typeof(double) }));
            }
            else if (node is STRING_SCALAR) {
                STRING_SCALAR ss = (STRING_SCALAR)node;
                if (ss.value.ToLower() == "true") {
                    ilGen.Emit(OpCodes.Ldc_I4_1);
                    ilGen.Emit(OpCodes.Newobj, PHPBoolean.GetConstructor(new Type[] { typeof(bool) }));
                }
                else if (ss.value.ToLower() == "false") {
                    ilGen.Emit(OpCodes.Ldc_I4_0);
                    ilGen.Emit(OpCodes.Newobj, PHPBoolean.GetConstructor(new Type[] { typeof(bool) }));
                }
                else {
                    ilGen.Emit(OpCodes.Ldstr, ss.value);
                    ilGen.Emit(OpCodes.Newobj, PHPString.GetConstructor(new Type[] { typeof(string) }));
                }
            }
            else if (node is SINGLE_QUOTES) {
                SINGLE_QUOTES sq = (SINGLE_QUOTES)node;
                StringBuilder result = new StringBuilder();
                foreach (object o in sq.encaps_list) {
                    if (o is string)
                        result.Append((string)o);
                    else if (o is VARIABLE) {
                        result.Append('$');
                        result.Append(((VARIABLE)o).name);
                    }
                }
                ilGen.Emit(OpCodes.Ldstr, result.ToString());
                ilGen.Emit(OpCodes.Newobj, PHPString.GetConstructor(new Type[] { typeof(string) }));
            }
            else if (node is DOUBLE_QUOTES) {
                DOUBLE_QUOTES dq = (DOUBLE_QUOTES)node;
                StringBuilder output = new StringBuilder();
                bool concat = false;
                foreach (object o in dq.encaps_list) {
                    if (o is string)
                        output.Append((string)o);
                    else {
                        // push substring between last variable and current one and concat, if necessary
                        if (output.Length > 0) {
                            ilGen.Emit(OpCodes.Ldstr, output.ToString());
                            ilGen.Emit(OpCodes.Newobj, PHPString.GetConstructor(new Type[] { typeof(string) }));
                            if (concat)
                                ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("Concat", new Type[] { PHPMixed, PHPMixed }));
                            concat = true;
                            output = new StringBuilder();
                        }
                        // push variable value
                        if (o is VARIABLE)
                            Visit((VARIABLE)o);
                        // or push object operator result
                        else if (o is OBJECT_OPERATOR)
                            Visit((OBJECT_OPERATOR)o);
                        // or push Null
                        else
                            ilGen.Emit(OpCodes.Newobj, PHPNull.GetConstructor(Type.EmptyTypes));
                        // concat, if necessary
                        if (concat)
                            ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("Concat", new Type[] { PHPMixed, PHPMixed }));
                        concat = true;
                    }
                }
                // push substring after last variable and concat, if necessary
                if (output.Length > 0) {
                    ilGen.Emit(OpCodes.Ldstr, output.ToString());
                    ilGen.Emit(OpCodes.Newobj, PHPString.GetConstructor(new Type[] { typeof(string) }));
                    if (concat)
                        ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("Concat", new Type[] { PHPMixed, PHPMixed }));
                    output = null;
                }
            }
            else if (node is HEREDOC) {
                HEREDOC h = (HEREDOC)node;
                StringBuilder output = new StringBuilder();
                bool concat = false;
                foreach (object o in h.encaps_list) {
                    if (o is string)
                        output.Append((string)o);
                    else {
                        // push substring between last variable and current one and concat, if necessary
                        if (output.Length > 0) {
                            ilGen.Emit(OpCodes.Ldstr, output.ToString());
                            ilGen.Emit(OpCodes.Newobj, PHPString.GetConstructor(new Type[] { typeof(string) }));
                            if (concat)
                                ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("Concat", new Type[] { PHPMixed, PHPMixed }));
                            concat = true;
                            output = new StringBuilder();
                        }
                        // push variable value
                        if (o is VARIABLE)
                            Visit((VARIABLE)o);
                        // or push object operator result
                        else if (o is OBJECT_OPERATOR)
                            Visit((OBJECT_OPERATOR)o);
                        // or push Null
                        else
                            ilGen.Emit(OpCodes.Newobj, PHPNull.GetConstructor(Type.EmptyTypes));
                        // concat, if necessary
                        if (concat)
                            ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("Concat", new Type[] { PHPMixed, PHPMixed }));
                        concat = true;
                    }
                }
                // push substring after last variable and concat, if necessary
                if (output.Length > 0) {
                    ilGen.Emit(OpCodes.Ldstr, output.ToString());
                    ilGen.Emit(OpCodes.Newobj, PHPString.GetConstructor(new Type[] { typeof(string) }));
                    if (concat)
                        ilGen.Emit(OpCodes.Call, PHPCoreLang.GetMethod("Concat", new Type[] { PHPMixed, PHPMixed }));
                    output = null;
                }
            }
            else if (node is CONSTANT) {
                CONSTANT c = (CONSTANT)node;
                // push constant value
                ilGen.Emit(OpCodes.Ldstr, c.name);
                ilGen.Emit(OpCodes.Newobj, PHPString.GetConstructor(new Type[] { typeof(string) }));
                ilGen.Emit(OpCodes.Call, PHPCoreRuntime.GetMethod("GetConstant", new Type[] { PHPMixed }));
            }
            else if (node is UnaryExpression) {
                UnaryExpression ue = (UnaryExpression)node;
                // process expression
                Visit(ue.expr);
            }
            else if (node is BinaryExpression) {
                BinaryExpression be = (BinaryExpression)node;
                // process expressions
                Visit(be.expr1);
                Visit(be.expr2);
            }
            else if (node is TernaryExpression) {
                TernaryExpression te = (TernaryExpression)node;
                // process expressions
                Visit(te.expr1);
                Visit(te.expr2);
                Visit(te.expr3);
            }
            else if (node is Expression) {
                Expression e = (Expression)node;
                if (e is VARIABLE)
                    Visit((VARIABLE)e);
                else if (e is FUNCTION_CALL)
                    Visit((FUNCTION_CALL)e);
                else if (e is ARRAY)
                    Visit((ARRAY)e);
                else if (e is UnaryExpression)
                    Visit((UnaryExpression)e);
                else if (e is BinaryExpression)
                    Visit((BinaryExpression)e);
                else if (e is TernaryExpression)
                    Visit((TernaryExpression)e);
            }
        }