//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); }
//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; }
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); }
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; }