示例#1
0
        //Compiling a regular function call.
        private ExprData CompileFunctionCall(ElaJuxtaposition v, LabelMap map, Hints hints)
        {
            var ed = ExprData.Empty;
            var bf = default(ElaNameReference);
            var sv = default(ScopeVar);

            if (!map.HasContext && TryOptimizeConstructor(v, map))
            {
                return(ed);
            }

            if (!map.HasContext && v.Target.Type == ElaNodeType.NameReference)
            {
                bf = (ElaNameReference)v.Target;
                sv = GetVariable(bf.Name, bf.Line, bf.Column);

                //If the target is one of the built-in application function we need to transform this
                //to a regular function call, e.g. 'x |> f' is translated into 'f x' by manually creating
                //an appropriates AST node. This is done to simplify compilation - so that all optimization
                //of a regular function call would be applied to pipes as well.
                if ((sv.Flags & ElaVariableFlags.Builtin) == ElaVariableFlags.Builtin)
                {
                    var k = (ElaBuiltinKind)sv.Data;

                    if (v.Parameters.Count == 2)
                    {
                        if (k == ElaBuiltinKind.BackwardPipe)
                        {
                            var fc = new ElaJuxtaposition {
                                Target = v.Parameters[0]
                            };
                            fc.SetLinePragma(v.Line, v.Column);
                            fc.Parameters.Add(v.Parameters[1]);
                            return(CompileFunctionCall(fc, map, hints));
                        }
                        else if (k == ElaBuiltinKind.ForwardPipe)
                        {
                            var fc = new ElaJuxtaposition {
                                Target = v.Parameters[1]
                            };
                            fc.SetLinePragma(v.Line, v.Column);
                            fc.Parameters.Add(v.Parameters[0]);
                            return(CompileFunctionCall(fc, map, hints));
                        }
                        else if (k == ElaBuiltinKind.LogicalOr)
                        {
                            CompileLogicalOr(v, v.Parameters[0], v.Parameters[1], map, hints);
                            return(ed);
                        }
                        else if (k == ElaBuiltinKind.LogicalAnd)
                        {
                            CompileLogicalAnd(v, v.Parameters[0], v.Parameters[1], map, hints);
                            return(ed);
                        }
                        else if (k == ElaBuiltinKind.Seq)
                        {
                            CompileSeq(v, v.Parameters[0], v.Parameters[1], map, hints);
                            return(ed);
                        }
                    }
                }
            }

            //We can't apply tail call optimization for the context bound call
            var tail = (hints & Hints.Tail) == Hints.Tail && !map.HasContext;
            var len  = v.Parameters.Count;

            //Compile arguments to which a function is applied
            for (var i = 0; i < len; i++)
            {
                CompileExpression(v.Parameters[len - i - 1], map, Hints.None, v);
            }

            //If this a tail call and we effectively call the same function we are currently in,
            //than do not emit an actual function call, just do a goto. (Tail recursion optimization).
            if (tail && map.FunctionName != null && map.FunctionName == v.GetName() &&
                map.FunctionParameters == len && map.FunctionScope == GetScope(map.FunctionName) &&
                (sv.Flags & ElaVariableFlags.ClassFun) != ElaVariableFlags.ClassFun)
            {
                AddLinePragma(v);
                cw.Emit(Op.Br, map.FunStart);
                return(ed);
            }

            if (bf != null)
            {
                if (v.Parameters[0].Type == ElaNodeType.Primitive &&
                    bf.Line == v.Parameters[0].Line && bf.Column + bf.Name.Length == v.Parameters[0].Column &&
                    ((ElaPrimitive)v.Parameters[0]).Value.IsNegative())
                {
                    var par = ((ElaPrimitive)v.Parameters[0]).Value.ToString();
                    AddWarning(map, ElaCompilerWarning.NegationAmbiguity, v, bf.Name, par);
                    AddHint(ElaCompilerHint.AddSpaceApplication, v, bf.Name, par, par.TrimStart('-'));
                }

                //The target is one of built-in functions and therefore can be inlined for optimization.
                if ((sv.Flags & ElaVariableFlags.Builtin) == ElaVariableFlags.Builtin)
                {
                    var kind = (ElaBuiltinKind)sv.Data;
                    var pars = BuiltinParams(kind);

                    //We inline built-ins only when all arguments are provided
                    //If this is not the case a built-in is compiled into a function in-place
                    //and than called.
                    if (len != pars)
                    {
                        AddLinePragma(bf);
                        CompileBuiltin(kind, v.Target, map, bf.Name);

                        if (v.FlipParameters)
                        {
                            cw.Emit(Op.Flip);
                        }

                        for (var i = 0; i < len; i++)
                        {
                            cw.Emit(Op.Call);
                        }
                    }
                    else
                    {
                        CompileBuiltinInline(kind, v.Target, map, hints);
                    }

                    ed = new ExprData(DataKind.BuiltinError, sv.Data);
                    return(ed);
                }
                else
                {
                    //Regular situation, just push a target name
                    AddLinePragma(v.Target);
                    PushVar(sv);

                    if ((sv.VariableFlags & ElaVariableFlags.Function) == ElaVariableFlags.Function)
                    {
                        ed = new ExprData(DataKind.FunParams, sv.Data);
                    }
                    else if ((sv.VariableFlags & ElaVariableFlags.ObjectLiteral) == ElaVariableFlags.ObjectLiteral)
                    {
                        ed = new ExprData(DataKind.VarType, (Int32)ElaVariableFlags.ObjectLiteral);
                    }
                }
            }
            else
            {
                ed = CompileExpression(v.Target, map, Hints.None, v);
            }

            //Why it comes from AST? Because parser do not save the difference between pre-, post- and infix applications.
            //However Ela does support left and right sections for operators - and for such cases an additional flag is used
            //to signal about a section.
            if (v.FlipParameters)
            {
                cw.Emit(Op.Flip);
            }

            //It means that we are trying to call "not a function". Ela is a dynamic language, still it's worth to generate
            //a warning in such a case.
            if (ed.Type == DataKind.VarType)
            {
                AddWarning(map, ElaCompilerWarning.FunctionInvalidType, v.Target, FormatNode(v.Target));
            }

            AddLinePragma(v);

            for (var i = 0; i < len; i++)
            {
                var last = i == v.Parameters.Count - 1;

                //Use a tail call if this function call is a tail expression and optimizations are enabled.
                if (last && tail && opt)
                {
                    cw.Emit(Op.Callt);
                }
                else
                {
                    cw.Emit(Op.Call);
                }
            }

            return(ed);
        }
示例#2
0
        //Compiling a regular function call.
        private ExprData CompileFunctionCall(ElaJuxtaposition v, LabelMap map, Hints hints)
        {
            var ed = ExprData.Empty;
            var bf = default(ElaNameReference);
            var sv = default(ScopeVar);

            if (!map.HasContext && TryOptimizeConstructor(v, map))
                return ed;

            if (!map.HasContext && v.Target.Type == ElaNodeType.NameReference)
            {
                bf = (ElaNameReference)v.Target;
                sv = GetVariable(bf.Name, bf.Line, bf.Column);

                //If the target is one of the built-in application function we need to transform this
                //to a regular function call, e.g. 'x |> f' is translated into 'f x' by manually creating
                //an appropriates AST node. This is done to simplify compilation - so that all optimization
                //of a regular function call would be applied to pipes as well.
                if ((sv.Flags & ElaVariableFlags.Builtin) == ElaVariableFlags.Builtin)
                {
                    var k = (ElaBuiltinKind)sv.Data;

                    if (v.Parameters.Count == 2)
                    {
                        if (k == ElaBuiltinKind.BackwardPipe)
                        {
                            var fc = new ElaJuxtaposition { Target = v.Parameters[0] };
                            fc.SetLinePragma(v.Line, v.Column);
                            fc.Parameters.Add(v.Parameters[1]);
                            return CompileFunctionCall(fc, map, hints);
                        }
                        else if (k == ElaBuiltinKind.ForwardPipe)
                        {
                            var fc = new ElaJuxtaposition { Target = v.Parameters[1] };
                            fc.SetLinePragma(v.Line, v.Column);
                            fc.Parameters.Add(v.Parameters[0]);
                            return CompileFunctionCall(fc, map, hints);
                        }
                        else if (k == ElaBuiltinKind.LogicalOr)
                        {
                            CompileLogicalOr(v, v.Parameters[0], v.Parameters[1], map, hints);
                            return ed;
                        }
                        else if (k == ElaBuiltinKind.LogicalAnd)
                        {
                            CompileLogicalAnd(v, v.Parameters[0], v.Parameters[1], map, hints);
                            return ed;
                        }
                        else if (k == ElaBuiltinKind.Seq)
                        {
                            CompileSeq(v, v.Parameters[0], v.Parameters[1], map, hints);
                            return ed;
                        }
                    }
                }
            }

            //We can't apply tail call optimization for the context bound call
            var tail = (hints & Hints.Tail) == Hints.Tail && !map.HasContext;
            var len = v.Parameters.Count;

            //Compile arguments to which a function is applied
            for (var i = 0; i < len; i++)
                CompileExpression(v.Parameters[len - i - 1], map, Hints.None, v);

            //If this a tail call and we effectively call the same function we are currently in,
            //than do not emit an actual function call, just do a goto. (Tail recursion optimization).
            if (tail && map.FunctionName != null && map.FunctionName == v.GetName() &&
                map.FunctionParameters == len && map.FunctionScope == GetScope(map.FunctionName)
                && (sv.Flags & ElaVariableFlags.ClassFun) != ElaVariableFlags.ClassFun)
            {
                AddLinePragma(v);
                cw.Emit(Op.Br, map.FunStart);
                return ed;
            }

            if (bf != null)
            {
                if (v.Parameters[0].Type == ElaNodeType.Primitive &&
                    bf.Line == v.Parameters[0].Line && bf.Column + bf.Name.Length == v.Parameters[0].Column &&
                    ((ElaPrimitive)v.Parameters[0]).Value.IsNegative())
                {
                    var par = ((ElaPrimitive)v.Parameters[0]).Value.ToString();
                    AddWarning(ElaCompilerWarning.NegationAmbiguity, v, bf.Name, par);
                    AddHint(ElaCompilerHint.AddSpaceApplication, v, bf.Name, par, par.TrimStart('-'));
                }

                //The target is one of built-in functions and therefore can be inlined for optimization.
                if ((sv.Flags & ElaVariableFlags.Builtin) == ElaVariableFlags.Builtin)
                {
                    var kind = (ElaBuiltinKind)sv.Data;
                    var pars = BuiltinParams(kind);

                    //We inline built-ins only when all arguments are provided
                    //If this is not the case a built-in is compiled into a function in-place
                    //and than called.
                    if (len != pars)
                    {
                        AddLinePragma(bf);
                        CompileBuiltin(kind, v.Target, map, bf.Name);

                        if (v.FlipParameters)
                            cw.Emit(Op.Flip);

                        for (var i = 0; i < len; i++)
                            cw.Emit(Op.Call);
                    }
                    else
                        CompileBuiltinInline(kind, v.Target, map, hints);

                    return ed;
                }
                else
                {
                    //Regular situation, just push a target name
                    AddLinePragma(v.Target);
                    PushVar(sv);

                    if ((sv.VariableFlags & ElaVariableFlags.Function) == ElaVariableFlags.Function)
                        ed = new ExprData(DataKind.FunParams, sv.Data);
                    else if ((sv.VariableFlags & ElaVariableFlags.ObjectLiteral) == ElaVariableFlags.ObjectLiteral)
                        ed = new ExprData(DataKind.VarType, (Int32)ElaVariableFlags.ObjectLiteral);
                }
            }
            else
                ed = CompileExpression(v.Target, map, Hints.None, v);

            //Why it comes from AST? Because parser do not save the difference between pre-, post- and infix applications.
            //However Ela does support left and right sections for operators - and for such cases an additional flag is used
            //to signal about a section.
            if (v.FlipParameters)
                cw.Emit(Op.Flip);

            //It means that we are trying to call "not a function". Ela is a dynamic language, still it's worth to generate
            //a warning in such a case.
            if (ed.Type == DataKind.VarType)
                AddWarning(ElaCompilerWarning.FunctionInvalidType, v.Target, FormatNode(v.Target));

            AddLinePragma(v);

            for (var i = 0; i < len; i++)
            {
                var last = i == v.Parameters.Count - 1;

                //Use a tail call if this function call is a tail expression and optimizations are enabled.
                if (last && tail && opt)
                    cw.Emit(Op.Callt);
                else
                    cw.Emit(Op.Call);
            }

            return ed;
        }
示例#3
0
        private ExprData CompileExpression(ElaExpression exp, LabelMap map, Hints hints, ElaExpression parent)
        {
            var exprData = ExprData.Empty;

            switch (exp.Type)
            {
            case ElaNodeType.DebugPoint:
                var dp = (ElaDebugPoint)exp;

                if (debug)
                {
                    if (dp.Action == ElaDebugAction.TracePoint)
                    {
                        var str = dp.Data ?? String.Empty;
                        cw.Emit(Op.Trace, AddString(str));
                    }

                    AddLinePragma(exp);
                }

                if (dp.Expression != null)
                {
                    return(CompileExpression(dp.Expression, map, hints, parent));
                }
                else
                {
                    cw.Emit(Op.Pushunit);
                }
                break;

            case ElaNodeType.DoNotation:
                CompileDoNotation((ElaDoNotation)exp, map, hints);
                break;

            case ElaNodeType.As:
            case ElaNodeType.Equation:
                AddError(ElaCompilerError.InvalidExpression, exp, FormatNode(exp));
                break;

            case ElaNodeType.Context:
            {
                var v = (ElaContext)exp;

                if (!v.Context.Parens && v.Context.Type == ElaNodeType.NameReference)
                {
                    var nr = (ElaNameReference)v.Context;

                    if (nr.Uppercase)
                    {
                        EmitSpecName(null, "$$" + nr.Name, nr, ElaCompilerError.UndefinedType);
                    }
                    else
                    {
                        CompileExpression(v.Context, map, Hints.None, v);
                        cw.Emit(Op.Api, 5);         //TypeCode
                    }
                }
                else if (!v.Context.Parens && v.Context.Type == ElaNodeType.FieldReference)
                {
                    var fr = (ElaFieldReference)v.Context;

                    if (Char.IsUpper(fr.FieldName[0]) && fr.TargetObject.Type == ElaNodeType.NameReference)
                    {
                        EmitSpecName(fr.TargetObject.GetName(), "$$" + fr.FieldName, fr, ElaCompilerError.UndefinedType);
                    }
                    else
                    {
                        CompileExpression(v.Context, map, Hints.None, v);
                        cw.Emit(Op.Api, 5);         //TypeCode
                    }
                }
                else
                {
                    CompileExpression(v.Context, map, Hints.None, v);
                    cw.Emit(Op.Force);
                    cw.Emit(Op.Api, 5);         //TypeCode
                }

                AddLinePragma(v);

                //This is only a possibility when '::: Expr' is a top level expression. In such a case it sets
                //a default context for the current call scope.
                if (v.Expression == null)
                {
                    cw.Emit(Op.Ctx);

                    if ((hints & Hints.Left) != Hints.Left)
                    {
                        cw.Emit(Op.Pushunit);
                    }
                }
                else
                {
                    var a = AddVariable();
                    cw.Emit(Op.Dup);
                    cw.Emit(Op.Ctx);
                    PopVar(a);
                    var newMap = map.Clone(a);
                    CompileExpression(v.Expression, newMap, hints, v);
                }
            }
            break;

            case ElaNodeType.Builtin:
            {
                var v = (ElaBuiltin)exp;
                CompileBuiltin(v.Kind, v, map, map.BindingName);

                if ((hints & Hints.Left) == Hints.Left)
                {
                    AddValueNotUsed(map, exp);
                }
            }
            break;

            case ElaNodeType.Generator:
            {
                CompileGenerator((ElaGenerator)exp, map, hints);

                if ((hints & Hints.Left) == Hints.Left)
                {
                    AddValueNotUsed(map, exp);
                }
            }
            break;

            case ElaNodeType.TypeCheck:
            {
                var n = (ElaTypeCheck)exp;
                CompileTypeCheck(n, map, hints);
            }
            break;

            case ElaNodeType.Range:
            {
                var r = (ElaRange)exp;
                CompileRange(exp, r, map, hints);

                if ((hints & Hints.Left) == Hints.Left)
                {
                    AddValueNotUsed(map, r);
                }
            }
            break;

            case ElaNodeType.LazyLiteral:
            {
                var v = (ElaLazyLiteral)exp;
                CompileLazy(v, map, hints);
            }
            break;

            case ElaNodeType.LetBinding:
            {
                var v = (ElaLetBinding)exp;
                StartScope(false, v.Line, v.Column);
                CompileEquationSet(v.Equations, map);
                CompileExpression(v.Expression, map, hints, v);
                EndScope();
            }
            break;

            case ElaNodeType.Try:
            {
                var s = (ElaTry)exp;
                CompileTryExpression(s, map, hints);
                AddWarning(map, ElaCompilerWarning.TryDeprecated, exp);
            }
            break;

            case ElaNodeType.Comprehension:
            {
                var c = (ElaComprehension)exp;
                AddLinePragma(c);

                if (c.Lazy)
                {
                    CompileLazyList(c.Generator, map, hints);
                }
                else
                {
                    cw.Emit(Op.Newlist);
                    CompileGenerator(c.Generator, map, Hints.None);
                    AddLinePragma(c);
                    cw.Emit(Op.Genfin);
                }

                if ((hints & Hints.Left) == Hints.Left)
                {
                    AddValueNotUsed(map, c);
                }
            }
            break;

            case ElaNodeType.Match:
            {
                var n = (ElaMatch)exp;
                CompileMatchExpression(n, map, hints);
            }
            break;

            case ElaNodeType.Lambda:
            {
                var f  = (ElaLambda)exp;
                var pc = CompileLambda(f);
                exprData = new ExprData(DataKind.FunParams, pc);

                if ((hints & Hints.Left) == Hints.Left)
                {
                    AddValueNotUsed(map, exp);
                }
            }
            break;

            case ElaNodeType.Condition:
            {
                var s = (ElaCondition)exp;
                CompileConditionalOperator(s, map, hints);
            }
            break;

            case ElaNodeType.Primitive:
            {
                var p = (ElaPrimitive)exp;
                exprData = CompilePrimitive(p, map, hints);
            }
            break;

            case ElaNodeType.RecordLiteral:
            {
                var p = (ElaRecordLiteral)exp;
                exprData = CompileRecord(p, map, hints);
            }
            break;

            case ElaNodeType.FieldReference:
            {
                var p  = (ElaFieldReference)exp;
                var sv = default(ScopeVar);

                //Here we check if a field reference is actually an external name
                //prefixed by a module alias. This call is not neccessary (modules
                //are first class) but is used as optimization.
                if (!TryOptimizeFieldReference(p, out sv))
                {
                    CompileExpression(p.TargetObject, map, Hints.None, p);
                    cw.Emit(Op.Pushstr, AddString(p.FieldName));
                    AddLinePragma(p);
                    cw.Emit(Op.Pushfld);
                }
                else if ((sv.Flags & ElaVariableFlags.Polyadric) == ElaVariableFlags.Polyadric)
                {
                    if (map.HasContext)
                    {
                        PushVar(map.Context.Value);
                    }
                    else
                    {
                        cw.Emit(Op.Pushunit);
                    }

                    cw.Emit(Op.Disp);
                }

                if ((hints & Hints.Left) == Hints.Left)
                {
                    AddValueNotUsed(map, exp);
                }
            }
            break;

            case ElaNodeType.ListLiteral:
            {
                var p = (ElaListLiteral)exp;
                exprData = CompileList(p, map, hints);
            }
            break;

            case ElaNodeType.NameReference:
            {
                var v = (ElaNameReference)exp;
                AddLinePragma(v);
                var scopeVar = GetVariable(v.Name, v.Line, v.Column);

                //Bang patterns are only allowed in functions and constructors
                if (v.Bang)
                {
                    AddError(ElaCompilerError.BangPatternNotValid, exp, FormatNode(exp));
                    AddHint(ElaCompilerHint.BangsOnlyFunctions, exp);
                }

                //This a polymorphic constant
                if ((scopeVar.Flags & ElaVariableFlags.Polyadric) == ElaVariableFlags.Polyadric)
                {
                    PushVar(scopeVar);

                    if (map.HasContext)
                    {
                        PushVar(map.Context.Value);
                    }
                    else
                    {
                        cw.Emit(Op.Pushunit);
                    }

                    cw.Emit(Op.Disp);
                }
                else if ((scopeVar.Flags & ElaVariableFlags.Context) == ElaVariableFlags.Context)
                {
                    //This is context value, not a real variable
                    cw.Emit(Op.Pushunit);
                    cw.Emit(Op.Api, (Int32)Api.CurrentContext);
                }
                else
                {
                    PushVar(scopeVar);
                }

                if ((hints & Hints.Left) == Hints.Left)
                {
                    AddValueNotUsed(map, v);
                }

                //Add some hints if we know how this name is initialized
                if ((scopeVar.VariableFlags & ElaVariableFlags.Function) == ElaVariableFlags.Function)
                {
                    exprData = new ExprData(DataKind.FunParams, scopeVar.Data);
                }
                else if ((scopeVar.VariableFlags & ElaVariableFlags.ObjectLiteral) == ElaVariableFlags.ObjectLiteral)
                {
                    exprData = new ExprData(DataKind.VarType, (Int32)ElaVariableFlags.ObjectLiteral);
                }
                else if ((scopeVar.VariableFlags & ElaVariableFlags.Builtin) == ElaVariableFlags.Builtin)
                {
                    exprData = new ExprData(DataKind.Builtin, scopeVar.Data);
                }
            }
            break;

            case ElaNodeType.Placeholder:
            {
                if ((hints & Hints.Left) != Hints.Left)
                {
                    AddError(ElaCompilerError.PlaceholderNotValid, exp);
                }
                else
                {
                    AddLinePragma(exp);
                    cw.Emit(Op.Pop);
                }
            }
            break;

            case ElaNodeType.Juxtaposition:
            {
                var v = (ElaJuxtaposition)exp;
                exprData = CompileFunctionCall(v, map, hints);

                if ((hints & Hints.Left) == Hints.Left)
                {
                    AddValueNotUsed(map, v);
                }
            }
            break;

            case ElaNodeType.UnitLiteral:
                if ((hints & Hints.Left) != Hints.Left)
                {
                    cw.Emit(Op.Pushunit);
                }

                exprData = new ExprData(DataKind.VarType, (Int32)ElaTypeCode.Unit);
                break;

            case ElaNodeType.TupleLiteral:
            {
                var v = (ElaTupleLiteral)exp;
                exprData = CompileTuple(v, map, hints);
            }
            break;
            }

            return(exprData);
        }
示例#4
0
        private ExprData CompileExpression(ElaExpression exp, LabelMap map, Hints hints, ElaExpression parent)
        {
            var exprData = ExprData.Empty;

            switch (exp.Type)
            {
                case ElaNodeType.As:
                case ElaNodeType.Equation:
                    AddError(ElaCompilerError.InvalidExpression, exp, FormatNode(exp));
                    break;
                case ElaNodeType.Context:
                    {
                        var v = (ElaContext)exp;

                        if (!v.Context.Parens && v.Context.Type == ElaNodeType.NameReference)
                        {
                            var nr = (ElaNameReference)v.Context;

                            if (nr.Uppercase)
                                EmitSpecName(null, "$$" + nr.Name, nr, ElaCompilerError.UndefinedType);
                            else
                            {
                                CompileExpression(v.Context, map, Hints.None, v);
                                cw.Emit(Op.Api, 5); //TypeCode
                            }
                        }
                        else if (!v.Context.Parens && v.Context.Type == ElaNodeType.FieldReference)
                        {
                            var fr = (ElaFieldReference)v.Context;

                            if (Char.IsUpper(fr.FieldName[0]) && fr.TargetObject.Type == ElaNodeType.NameReference)
                                EmitSpecName(fr.TargetObject.GetName(), "$$" + fr.FieldName, fr, ElaCompilerError.UndefinedType);
                            else
                            {
                                CompileExpression(v.Context, map, Hints.None, v);
                                cw.Emit(Op.Api, 5); //TypeCode
                            }
                        }
                        else
                        {
                            CompileExpression(v.Context, map, Hints.None, v);
                            cw.Emit(Op.Force);
                            cw.Emit(Op.Api, 5); //TypeCode
                        }

                        AddLinePragma(v);

                        var a = AddVariable();
                        cw.Emit(Op.Dup);
                        cw.Emit(Op.Ctx);
                        PopVar(a);
                        var newMap = map.Clone(a);

                        CompileExpression(v.Expression, newMap, hints, v);
                    }
                    break;
                case ElaNodeType.Builtin:
                    {
                        var v = (ElaBuiltin)exp;
                        CompileBuiltin(v.Kind, v, map, map.BindingName);

                        if ((hints & Hints.Left) == Hints.Left)
                            AddValueNotUsed(exp);
                    }
                    break;
                case ElaNodeType.Generator:
                    {
                        CompileGenerator((ElaGenerator)exp, map, hints);

                        if ((hints & Hints.Left) == Hints.Left)
                            AddValueNotUsed(exp);
                    }
                    break;
                case ElaNodeType.TypeCheck:
                    {
                        var n = (ElaTypeCheck)exp;
                        CompileTypeCheck(n, map, hints);
                    }
                    break;
                case ElaNodeType.Range:
                    {
                        var r = (ElaRange)exp;
                        CompileRange(exp, r, map, hints);

                        if ((hints & Hints.Left) == Hints.Left)
                            AddValueNotUsed(r);
                    }
                    break;
                case ElaNodeType.LazyLiteral:
                    {
                        var v = (ElaLazyLiteral)exp;
                        CompileLazy(v, map, hints);
                    }
                    break;
                case ElaNodeType.LetBinding:
                    {
                        var v = (ElaLetBinding)exp;
                        StartScope(false, v.Line, v.Column);
                        CompileEquationSet(v.Equations, map);
                        CompileExpression(v.Expression, map, hints, v);
                        EndScope();
                    }
                    break;
                case ElaNodeType.Try:
                    {
                        var s = (ElaTry)exp;
                        CompileTryExpression(s, map, hints);
                    }
                    break;
                case ElaNodeType.Comprehension:
                    {
                        var c = (ElaComprehension)exp;
                        AddLinePragma(c);

                        if (c.Lazy)
                            CompileLazyList(c.Generator, map, hints);
                        else
                        {
                            cw.Emit(Op.Newlist);
                            CompileGenerator(c.Generator, map, Hints.None);
                            AddLinePragma(c);
                            cw.Emit(Op.Genfin);
                        }

                        if ((hints & Hints.Left) == Hints.Left)
                            AddValueNotUsed(c);
                    }
                    break;
                case ElaNodeType.Match:
                    {
                        var n = (ElaMatch)exp;
                        CompileMatchExpression(n, map, hints);
                    }
                    break;
                case ElaNodeType.Lambda:
                    {
                        var f = (ElaLambda)exp;
                        var pc = CompileLambda(f);
                        exprData = new ExprData(DataKind.FunParams, pc);

                        if ((hints & Hints.Left) == Hints.Left)
                            AddValueNotUsed(exp);
                    }
                    break;
                case ElaNodeType.Condition:
                    {
                        var s = (ElaCondition)exp;
                        CompileConditionalOperator(s, map, hints);
                    }
                    break;
                case ElaNodeType.Raise:
                    {
                        var s = (ElaRaise)exp;
                        CompileExpression(s.Expression, map, Hints.None, s);
                        AddLinePragma(s);
                        cw.Emit(Op.Throw);
                    }
                    break;
                case ElaNodeType.Primitive:
                    {
                        var p = (ElaPrimitive)exp;
                        exprData = CompilePrimitive(p, map, hints);
                    }
                    break;
                case ElaNodeType.RecordLiteral:
                    {
                        var p = (ElaRecordLiteral)exp;
                        exprData = CompileRecord(p, map, hints);
                    }
                    break;
                case ElaNodeType.FieldReference:
                    {
                        var p = (ElaFieldReference)exp;

                        //Here we check if a field reference is actually an external name
                        //prefixed by a module alias. This call is not neccessary (modules
                        //are first class) but is used as optimization.
                        if (!TryOptimizeFieldReference(p))
                        {
                            CompileExpression(p.TargetObject, map, Hints.None, p);
                            cw.Emit(Op.Pushstr, AddString(p.FieldName));
                            AddLinePragma(p);
                            cw.Emit(Op.Pushfld);
                        }

                        if ((hints & Hints.Left) == Hints.Left)
                            AddValueNotUsed(exp);
                    }
                    break;
                case ElaNodeType.ListLiteral:
                    {
                        var p = (ElaListLiteral)exp;
                        exprData = CompileList(p, map, hints);
                    }
                    break;
                case ElaNodeType.NameReference:
                    {
                        var v = (ElaNameReference)exp;
                        AddLinePragma(v);
                        var scopeVar = GetVariable(v.Name, v.Line, v.Column);

                        //Bang patterns are only allowed in functions and constructors
                        if (v.Bang)
                        {
                            AddError(ElaCompilerError.BangPatternNotValid, exp, FormatNode(exp));
                            AddHint(ElaCompilerHint.BangsOnlyFunctions, exp);
                        }

                        //This a polymorphic constant
                        if ((scopeVar.Flags & ElaVariableFlags.Polyadric) == ElaVariableFlags.Polyadric)
                        {
                            PushVar(scopeVar);

                            if (map.HasContext)
                                PushVar(map.Context.Value);
                            else
                                cw.Emit(Op.Pushunit);

                            cw.Emit(Op.Disp);
                        }
                        else if ((scopeVar.Flags & ElaVariableFlags.Context) == ElaVariableFlags.Context)
                        {
                            //This is context value, not a real variable
                            cw.Emit(Op.Pushunit);
                            cw.Emit(Op.Api, (Int32)Api.CurrentContext);
                        }
                        else
                            PushVar(scopeVar);

                        if ((hints & Hints.Left) == Hints.Left)
                            AddValueNotUsed(v);

                        //Add some hints if we know how this name is initialized
                        if ((scopeVar.VariableFlags & ElaVariableFlags.Function) == ElaVariableFlags.Function)
                            exprData = new ExprData(DataKind.FunParams, scopeVar.Data);
                        else if ((scopeVar.VariableFlags & ElaVariableFlags.ObjectLiteral) == ElaVariableFlags.ObjectLiteral)
                            exprData = new ExprData(DataKind.VarType, (Int32)ElaVariableFlags.ObjectLiteral);
                        else if ((scopeVar.VariableFlags & ElaVariableFlags.Builtin) == ElaVariableFlags.Builtin)
                            exprData = new ExprData(DataKind.Builtin, scopeVar.Data);
                    }
                    break;
                case ElaNodeType.Placeholder:
                    {
                        if ((hints & Hints.Left) != Hints.Left)
                            AddError(ElaCompilerError.PlaceholderNotValid, exp);
                        else
                        {
                            AddLinePragma(exp);
                            cw.Emit(Op.Pop);
                        }
                    }
                    break;
                case ElaNodeType.Juxtaposition:
                    {
                        var v = (ElaJuxtaposition)exp;

                        CompileFunctionCall(v, map, hints);

                        if ((hints & Hints.Left) == Hints.Left)
                            AddValueNotUsed(v);
                    }
                    break;
                case ElaNodeType.UnitLiteral:
                    if ((hints & Hints.Left) != Hints.Left)
                        cw.Emit(Op.Pushunit);

                    exprData = new ExprData(DataKind.VarType, (Int32)ElaTypeCode.Unit);
                    break;
                case ElaNodeType.TupleLiteral:
                    {
                        var v = (ElaTupleLiteral)exp;
                        exprData = CompileTuple(v, map, hints);
                    }
                    break;
            }

            return exprData;
        }