private ElaJuxtaposition MakeBind(ElaExpression exp) { var ret = new ElaJuxtaposition { Target = new ElaNameReference { Name = ">>=" } }; ret.Parameters.Add(exp); ret.Parameters.Add(null); ret.SetLinePragma(exp.Line, exp.Column); ret.Target.SetLinePragma(exp.Line, exp.Column); return(ret); }
//Perform an eta expansion for a given expression private void EtaExpand(string name, ElaExpression exp, LabelMap map, int args) { //Here we generate a function which has a provided number of //arguments if (name != null) { StartFun(name, args); } StartSection(); StartScope(true, exp.Line, exp.Column); cw.StartFrame(args); var funSkipLabel = cw.DefineLabel(); cw.Emit(Op.Br, funSkipLabel); var address = cw.Offset; if (exp.Type != ElaNodeType.Equation) { CompileExpression(exp, map, Hints.None, null); } else { CompileFunction((ElaEquation)exp, map); } //Functions are curried so generate a call for each argument for (var i = 0; i < args; i++) { cw.Emit(Op.Call); } cw.Emit(Op.Ret); frame.Layouts.Add(new MemoryLayout(currentCounter, cw.FinishFrame(), address)); EndSection(); EndScope(); if (name != null) { EndFun(frame.Layouts.Count - 1); } cw.MarkLabel(funSkipLabel); cw.Emit(Op.PushI4, args); cw.Emit(Op.Newfun, frame.Layouts.Count - 1); }
private void ProcessBinding(ElaEquationSet block, ElaEquation bid, ElaExpression left, ElaExpression right) { bid.Left = left; bid.Right = right; if (bindings.Peek() == unit) { block.Equations.Add(bid); return; } var fName = default(String); if (right != null && left.Type == ElaNodeType.Juxtaposition && !left.Parens) { var fc = (ElaJuxtaposition)left; if (fc.Target.Type == ElaNodeType.NameReference) { fName = fc.Target.GetName(); } } if (fName != null) { var lastB = bindings.Peek(); if (lastB != null && ((ElaJuxtaposition)lastB.Left).Target.GetName() == fName) { lastB.Next = bid; } else { block.Equations.Add(bid); } bindings.Pop(); bindings.Push(bid); } else { block.Equations.Add(bid); } }
//Compiles any given expression as lazy, can be used to automatically generate thunks //as well as to compile an explicit lazy literal. private ExprData CompileLazyExpression(ElaExpression exp, LabelMap map, Hints hints) { Label funSkipLabel; int address; LabelMap newMap; CompileFunctionProlog(null, 1, exp.Line, exp.Column, out funSkipLabel, out address, out newMap); var ed = CompileExpression(exp, newMap, Hints.Scope | Hints.FunBody, null); CompileFunctionEpilog(null, 1, address, funSkipLabel); if (ed.Type == DataKind.BuiltinError) { cw.Emit(Op.Api, 18); } cw.Emit(Op.Newlazy); return(default(ExprData)); }
//Checks if we need to force a constructor parameter. private bool IsBang(ElaExpression exp) { if (exp.Type == ElaNodeType.NameReference && ((ElaNameReference)exp).Bang) { return(true); } else if (exp.Type == ElaNodeType.Juxtaposition) { var j = (ElaJuxtaposition)exp; if (j.Parameters[0].Type == ElaNodeType.NameReference && ((ElaNameReference)j.Parameters[0]).Bang) { return(true); } return(false); } return(false); }
//Includes a module reference (used for user references, Prelude and Components module). private CodeFrame IncludeModule(string alias, string name, string dllName, string[] path, int line, int col, bool reqQual, ElaExpression exp, bool addVar, bool noPrelude) { var modIndex = frame.HandleMap.Count; var modRef = new ModuleReference(frame, name, dllName, path, line, col, reqQual, modIndex); modRef.NoPrelude = noPrelude; frame.AddReference(alias, modRef); //Handles are filled by linker for module indexing at run-time frame.HandleMap.Add(-1); if (exp != null) { AddLinePragma(exp); } cw.Emit(Op.Runmod, modIndex); var addr = -1; if (addVar) { //Create a variable and bind to it module instance cw.Emit(Op.Newmod, modIndex); addr = AddVariable(alias, exp, ElaVariableFlags.Module | ElaVariableFlags.Private, modIndex); } //An event is handled by linker and a module is compiled/deserialized var ev = new ModuleEventArgs(modRef); comp.OnModuleInclude(ev); refs.Add(ev.Frame); if (addr != -1) { PopVar(addr); } return(ev.Frame); }
//Compiles xs parameters, can be used in all cases where xs creation is needed. private void CompileTupleParameters(ElaExpression v, List <ElaExpression> pars, LabelMap map) { //Optimize xs creates for a case of pair (a single op typeId is used). if (pars.Count == 2) { CompileExpression(pars[0], map, Hints.None, v); CompileExpression(pars[1], map, Hints.None, v); AddLinePragma(v); cw.Emit(Op.Newtup_2); } else { AddLinePragma(v); cw.Emit(Op.Newtup, pars.Count); for (var i = 0; i < pars.Count; i++) { CompileExpression(pars[i], map, Hints.None, v); cw.Emit(Op.Tupcons, i); } } }
//Builds a lists of all variables that are declared in the given pattern. private void ExtractPatternNames(ElaExpression pat, List <String> names) { switch (pat.Type) { case ElaNodeType.LazyLiteral: { //This whole method is used to extract names before making a //pattern lazy, so we need to extract all names here as well, //because this lazy literal will be compiled strict anyway (because //the whole pattern is lazy already). var vp = (ElaLazyLiteral)pat; ExtractPatternNames(vp.Expression, names); } break; case ElaNodeType.UnitLiteral: //Idle break; case ElaNodeType.As: { var asPat = (ElaAs)pat; names.Add(asPat.Name); ExtractPatternNames(asPat.Expression, names); } break; case ElaNodeType.Primitive: //Idle break; case ElaNodeType.NameReference: { var vexp = (ElaNameReference)pat; if (!vexp.Uppercase) //Uppercase is constructor { names.Add(vexp.Name); } } break; case ElaNodeType.RecordLiteral: { var rexp = (ElaRecordLiteral)pat; foreach (var e in rexp.Fields) { if (e.FieldValue != null) { ExtractPatternNames(e.FieldValue, names); } } } break; case ElaNodeType.TupleLiteral: { var texp = (ElaTupleLiteral)pat; foreach (var e in texp.Parameters) { ExtractPatternNames(e, names); } } break; case ElaNodeType.Placeholder: //Idle break; case ElaNodeType.Juxtaposition: { var hexp = (ElaJuxtaposition)pat; foreach (var e in hexp.Parameters) { ExtractPatternNames(e, names); } } break; case ElaNodeType.ListLiteral: { var l = (ElaListLiteral)pat; if (l.HasValues()) { foreach (var e in l.Values) { ExtractPatternNames(e, names); } } } break; } }
//Tests if a given expression is a name reference of a placeholder (_). private bool IsSimplePattern(ElaExpression exp) { return(exp.Type == ElaNodeType.NameReference || exp.Type == ElaNodeType.Placeholder); }
//Compile a given expression as a pattern. If match fails proceed to failLab. private void CompilePattern(int sysVar, ElaExpression exp, Label failLab, bool allowBang, bool forceStrict) { AddLinePragma(exp); switch (exp.Type) { case ElaNodeType.LazyLiteral: { var n = (ElaLazyLiteral)exp; //Normally this flag is set when everything is already compiled as lazy. if (forceStrict) { CompilePattern(sysVar, n.Expression, failLab, allowBang, forceStrict); } else { CompileLazyPattern(sysVar, exp, allowBang); } } break; case ElaNodeType.FieldReference: { //We treat this expression as a constructor with a module alias var n = (ElaFieldReference)exp; var fn = n.FieldName; var alias = n.TargetObject.GetName(); PushVar(sysVar); if (n.TargetObject.Type != ElaNodeType.NameReference) { AddError(ElaCompilerError.InvalidPattern, n, FormatNode(n)); } else { EmitSpecName(alias, "$$$$" + fn, n, ElaCompilerError.UndefinedName); } cw.Emit(Op.Skiptag); cw.Emit(Op.Br, failLab); } break; case ElaNodeType.NameReference: { //Irrefutable pattern, always binds expression to a name, unless it is //a constructor pattern var n = (ElaNameReference)exp; //Bang pattern are only allowed in constructors and functions if (n.Bang && !allowBang) { AddError(ElaCompilerError.BangPatternNotValid, exp, FormatNode(exp)); AddHint(ElaCompilerHint.BangsOnlyFunctions, exp); } if (n.Uppercase) //This is a constructor { if (sysVar != -1) { PushVar(sysVar); } EmitSpecName(null, "$$$$" + n.Name, n, ElaCompilerError.UndefinedName); //This op codes skips one offset if an expression //on the top of the stack has a specified tag. cw.Emit(Op.Skiptag); cw.Emit(Op.Br, failLab); } else { var newV = false; var addr = AddMatchVariable(n.Name, n, out newV); //This is a valid situation, it means that the value is //already on the top of the stack. if (sysVar > -1 && newV) { PushVar(sysVar); } if (n.Bang) { cw.Emit(Op.Force); } //The binding is already done, so just idle. if (newV) { PopVar(addr); } } } break; case ElaNodeType.UnitLiteral: { //Unit pattern is redundant, it is essentially the same as checking //the type of an expression which is what we do here. PushVar(sysVar); cw.Emit(Op.Force); cw.Emit(Op.PushI4, (Int32)ElaTypeCode.Unit); cw.Emit(Op.Ctype); //Types are not equal, proceed to fail. cw.Emit(Op.Brfalse, failLab); } break; case ElaNodeType.Primitive: { var n = (ElaPrimitive)exp; //Compare a given value with a primitive PushVar(sysVar); PushPrimitive(n, n.Value); cw.Emit(Op.Cneq); //Values not equal, proceed to fail. cw.Emit(Op.Brtrue, failLab); } break; case ElaNodeType.As: { var n = (ElaAs)exp; CompilePattern(sysVar, n.Expression, failLab, allowBang, false /*forceStrict*/); var newV = false; var addr = AddMatchVariable(n.Name, n, out newV); PushVar(sysVar); PopVar(addr); } break; case ElaNodeType.Placeholder: //This is a valid situation, it means that the value is //already on the top of the stack. Otherwise - nothing have to be done. if (sysVar == -1) { cw.Emit(Op.Pop); } break; case ElaNodeType.RecordLiteral: { var n = (ElaRecordLiteral)exp; CompileRecordPattern(sysVar, n, failLab, allowBang); } break; case ElaNodeType.TupleLiteral: { var n = (ElaTupleLiteral)exp; CompileTuplePattern(sysVar, n, failLab, allowBang); } break; case ElaNodeType.Juxtaposition: { //An infix pattern, currently the only case is head/tail pattern. var n = (ElaJuxtaposition)exp; CompileComplexPattern(sysVar, n, failLab, allowBang); } break; case ElaNodeType.ListLiteral: { var n = (ElaListLiteral)exp; //We a have a nil pattern '[]' if (!n.HasValues()) { PushVar(sysVar); cw.Emit(Op.Isnil); cw.Emit(Op.Brfalse, failLab); } else { //We don't want to write the same compilation logic twice, //so here we transform a list literal into a chain of function calls, e.g. //[1,2,3] goes to 1::2::3::[] with a mandatory nil at the end. var len = n.Values.Count; ElaExpression last = ElaListLiteral.Empty; var fc = default(ElaJuxtaposition); //Loops through all elements in literal backwards for (var i = 0; i < len; i++) { var nn = n.Values[len - i - 1]; fc = new ElaJuxtaposition(); fc.SetLinePragma(nn.Line, nn.Column); fc.Parameters.Add(nn); fc.Parameters.Add(last); last = fc; } //Now we can compile it as head/tail pattern CompilePattern(sysVar, fc, failLab, allowBang, false /*forceStrict*/); } } break; default: AddError(ElaCompilerError.InvalidPattern, exp, FormatNode(exp)); break; } }
//This method contains main compilation logic for 'match' expressions and for 'try' expressions. //This method only supports a single pattern per entry. //A 'mexp' (matched expression) parameter can be null and is used for additional validation only. private void CompileSimpleMatch(IEnumerable <ElaEquation> bindings, LabelMap map, Hints hints, ElaExpression mexp) { ValidateOverlapSimple(map, bindings, mexp); var failLab = cw.DefineLabel(); var endLab = cw.DefineLabel(); //We need to remembers the first set of system addresses because we will have //to push them manually for the entries other than first. var firstSys = -1; var first = true; //Loops through all bindings //For the first iteration we assume that all values are already on stack. //For the next iteration we manually push all values. foreach (var b in bindings) { //Each match entry starts a lexical scope StartScope(false, b.Line, b.Column); //For second+ entries we put a label where we would jump if a previous //pattern fails if (!first) { cw.MarkLabel(failLab); failLab = cw.DefineLabel(); } var p = b.Left; var sysVar = -1; //We apply an optimization if a we have a name reference (only for the first iteration). if (p.Type == ElaNodeType.NameReference && first) { sysVar = AddVariable(p.GetName(), p, ElaVariableFlags.Parameter, -1); } else { sysVar = AddVariable(); //Create an unnamed system variable } //This is not the first entry, so we have to push values first if (!first) { PushVar(firstSys); } PopVar(sysVar); //We have to remember addresses calculated in a first iteration //to be able to push them once again in a second iteration. if (first) { firstSys = sysVar; } CompilePattern(sysVar, p, failLab, false /*allowBang*/, false /*forceStrict*/); first = false; //Compile entry expression if (b.Right == null) { AddError(ElaCompilerError.InvalidMatchEntry, b.Left, FormatNode(b)); } else { CompileExpression(b.Right, map, Hints.None, b); } //Close current scope EndScope(); //If everything is OK skip through 'fail' clause cw.Emit(Op.Br, endLab); } //We fall here if all patterns have failed cw.MarkLabel(failLab); //If this hints is set than we generate a match for a 'try' //(exception handling) block. Instead of MatchFailed we need //to rethrow an original exception. Block 'try' always have //just a single expression to match, therefore firstSys[0] is //pretty safe here. if ((hints & Hints.Throw) == Hints.Throw) { PushVar(firstSys); cw.Emit(Op.Rethrow); } else { cw.Emit(Op.Failwith, (Int32)ElaRuntimeError.MatchFailed); } //Happy path for match cw.MarkLabel(endLab); cw.Emit(Op.Nop); }
//The same as FormatNode(ElaExpression,bool) but always formats AST not in non-compact manner. private string FormatNode(ElaExpression exp) { return(FormatNode(exp, false)); }
public static TreeNode Plain(this TreeNode par, ElaExpression exp) { return(Element(par, exp, "", exp.ToString(), "Function", "{0}{1}")); }
private void AddError(ElaCompilerError error, ElaExpression exp, params object[] args) { AddError(error, exp.Line, exp.Column, args); }
public static TreeNode Name(this TreeNode par, ElaExpression exp, object data, string title = "name") { return(Element(par, exp, title, data, "Field", "{1} ({0})")); }
//Performs a type check and throws and error if the type is not as expected. //This method assumes that a value to be checked is on the top of the stack. private ScopeVar TypeCheckConstructor(string cons, string prefix, string name, ElaExpression par, bool force) { var sv = EmitSpecName(prefix, "$$" + name, par, ElaCompilerError.UndefinedType); TypeCheckConstructorAllStack(cons, force); return(sv); }
//Generates a line pragma and remembers a provided location //via lastLine and lastColumn class fields. private void AddLinePragma(ElaExpression exp) { lastLine = exp.Line; lastColumn = exp.Column; pdb.AddLineSym(cw.Offset, exp.Line, exp.Column); }
//Adding all variables from pattern as NoInit's. This method recursively walks //all patterns. Currently we don't associate any additional metadata or flags //(except of NoInit) with variables inferred in such a way. private void AddPatternVariables(ElaExpression pat) { switch (pat.Type) { case ElaNodeType.LazyLiteral: { //Not all forms of lazy patterns are supported, //but it is easier to process them anyways. Errors will be caught //during pattern compilation. var vp = (ElaLazyLiteral)pat; AddPatternVariables(vp.Expression); } break; case ElaNodeType.UnitLiteral: //Idle break; case ElaNodeType.As: { var asPat = (ElaAs)pat; AddVariable(asPat.Name, asPat, ElaVariableFlags.NoInit, -1); AddPatternVariables(asPat.Expression); } break; case ElaNodeType.Primitive: //Idle break; case ElaNodeType.NameReference: { var vexp = (ElaNameReference)pat; if (!vexp.Uppercase) //Uppercase is constructor { AddVariable(vexp.Name, vexp, ElaVariableFlags.NoInit, -1); } } break; case ElaNodeType.RecordLiteral: { var rexp = (ElaRecordLiteral)pat; foreach (var e in rexp.Fields) { if (e.FieldValue != null) { AddPatternVariables(e.FieldValue); } } } break; case ElaNodeType.TupleLiteral: { var texp = (ElaTupleLiteral)pat; foreach (var e in texp.Parameters) { AddPatternVariables(e); } } break; case ElaNodeType.Placeholder: //Idle break; case ElaNodeType.Juxtaposition: { var hexp = (ElaJuxtaposition)pat; foreach (var e in hexp.Parameters) { AddPatternVariables(e); } } break; case ElaNodeType.ListLiteral: //Idle { var l = (ElaListLiteral)pat; if (l.HasValues()) { foreach (var e in l.Values) { AddPatternVariables(e); } } } break; } }
public static TreeNode Literal(this TreeNode par, ElaExpression exp, ElaTypeCode typeCode, object data) { return(Element(par, exp, TCF.GetShortForm(typeCode), data, "Literal", "{1} ({0})")); }
private void PopulateNodes(TreeNode par, ElaExpression exp) { if (exp == null) { return; } switch (exp.Type) { case ElaNodeType.DebugPoint: var @deb = (ElaDebugPoint)exp; var debNode = par.Simple(exp, String.Format("trace: {0}", @deb.Data)); if (@deb.Expression != null) { PopulateNodes(debNode, @deb.Expression); } break; case ElaNodeType.DoNotation: var @do = (ElaDoNotation)exp; var doNode = par.Simple(@do, "do"); foreach (var st in @do.Statements) { var stNode = doNode.Simple(st, "statement"); PopulateNodes(stNode, st); } break; case ElaNodeType.DoAssignment: var @ass = (ElaDoAssignment)exp; par.Simple(@ass, String.Format("{0} <- {1}", @ass.Left, @ass.Right)); break; case ElaNodeType.As: var @as = (ElaAs)exp; par.Control(@as, "as", @as.Name); break; case ElaNodeType.Builtin: var @built = (ElaBuiltin)exp; par.Control(@built, "built-in", @built.Kind.ToString()); break; case ElaNodeType.ClassInstance: var @inst = (ElaClassInstance)exp; while (@inst != null) { var instNode = par.Simple(@inst, "instance " + (String.IsNullOrEmpty(@inst.TypeClassPrefix) ? @inst.TypeClassName : String.Format("{0}.{1}", @inst.TypeClassName, @inst.TypeClassPrefix)) + "( " + (String.IsNullOrEmpty(@inst.TypePrefix) ? @inst.TypeName : String.Format("{0}.{1}", @inst.TypePrefix, @inst.TypeName)) + " )"); PopulateNodes(instNode, @inst.Where); @inst = @inst.And; } break; case ElaNodeType.ClassMember: var @mem = (ElaClassMember)exp; par.Plain(@mem); break; case ElaNodeType.Comprehension: var @comp = (ElaComprehension)exp; var compNode = par.Simple(@comp, @comp.Lazy ? "lazy comprehension" : "comprehension"); PopulateNodes(compNode, @comp.Generator); break; case ElaNodeType.Condition: var @cond = (ElaCondition)exp; var condNode = par.Simple(@cond, "if"); var condExpNode = condNode.Simple(@cond.Condition, "condition"); PopulateNodes(condExpNode, @cond.Condition); var trueExpNode = condNode.Simple(@cond.True, "true"); PopulateNodes(trueExpNode, @cond.True); var falseExpNode = condNode.Simple(@cond.False, "false"); PopulateNodes(falseExpNode, @cond.False); break; case ElaNodeType.Context: var @ctx = (ElaContext)exp; var ctxNode = par.Simple(@ctx, "context"); var ctxSetNode = ctxNode.Simple(@ctx, "set context"); PopulateNodes(ctxSetNode, @ctx.Context); if (@ctx.Expression != null) { var ctxObjNode = ctxNode.Simple(@ctx, "expression"); PopulateNodes(ctxObjNode, @ctx.Expression); } break; case ElaNodeType.Equation: var @eq = (ElaEquation)exp; var eqNode = par.Simple(@eq, "equation"); var eqLeftNode = eqNode.Simple(@eq.Left, "left"); PopulateNodes(eqLeftNode, @eq.Left); if (@eq.Right != null) { var eqRightNode = eqNode.Simple(@eq.Right, "right"); PopulateNodes(eqRightNode, @eq.Right); } break; case ElaNodeType.EquationSet: var @eqs = (ElaEquationSet)exp; var eqsNode = par.Simple(@eqs, "equation set"); foreach (var e in @eqs.Equations) { PopulateNodes(eqsNode, e); } break; case ElaNodeType.FieldDeclaration: var @fldDec = (ElaFieldDeclaration)exp; var fldDecNode = par.Simple(@fldDec, "field " + @fldDec.FieldName); PopulateNodes(fldDecNode, @fldDec.FieldValue); break; case ElaNodeType.FieldReference: var @fld = (ElaFieldReference)exp; var fldNode = par.Simple(@fld, "field " + @fld.FieldName); PopulateNodes(fldNode, @fld.TargetObject); break; case ElaNodeType.Generator: var @gen = (ElaGenerator)exp; var genNode = par.Simple(@gen, "generator"); var genTargetNode = genNode.Simple(@gen.Target, "target"); PopulateNodes(genTargetNode, @gen.Target); var genPatternNode = genNode.Simple(@gen.Pattern, "pattern"); PopulateNodes(genPatternNode, @gen.Pattern); var genGuardNode = genNode.Simple(@gen.Guard, "guard"); PopulateNodes(genGuardNode, @gen.Guard); var genBodyNode = genNode.Simple(@gen.Body, "body"); PopulateNodes(genBodyNode, @gen.Body); break; case ElaNodeType.Header: var @head = (ElaHeader)exp; var attrs = String.Empty; if ((@head.Attributes & ElaVariableFlags.Private) == ElaVariableFlags.Private) { attrs += "private "; } if ((@head.Attributes & ElaVariableFlags.Qualified) == ElaVariableFlags.Qualified) { attrs += "qualified "; } par.Name(@head, attrs + @head.Name, "header"); break; case ElaNodeType.ImportedVariable: var @imp = (ElaImportedVariable)exp; par.Name(@imp, (@imp.Private ? "private " : String.Empty) + @imp.LocalName + " = " + @imp.Name, "import"); break; case ElaNodeType.Juxtaposition: var @juxta = (ElaJuxtaposition)exp; var juxtaNode = par.Simple(@juxta, "juxtaposition"); var juxtaTargetNode = juxtaNode.Simple(@juxta.Target, "target"); PopulateNodes(juxtaTargetNode, @juxta.Target); var juxtaParsNode = juxtaNode.Simple(@juxta, "positioned"); foreach (var jp in @juxta.Parameters) { PopulateNodes(juxtaParsNode, jp); } break; case ElaNodeType.Lambda: var @lam = (ElaLambda)exp; var lamNode = par.Simple(@lam, "lambda"); var lamParNode = lamNode.Simple(@lam.Left, "left"); PopulateNodes(lamParNode, @lam.Left); var lamRightNode = lamNode.Simple(@lam.Right, "right"); PopulateNodes(lamRightNode, @lam.Right); break; case ElaNodeType.LazyLiteral: var @laz = (ElaLazyLiteral)exp; var lazNode = par.Simple(@laz, "lazy"); PopulateNodes(lazNode, @laz.Expression); break; case ElaNodeType.LetBinding: var @let = (ElaLetBinding)exp; var letNode = par.Simple(@let, "let"); if (@let.Expression != null) { var letExprNode = letNode.Simple(@let.Expression, "expression"); PopulateNodes(letExprNode, @let.Expression); } var letEqNode = letNode.Simple(@let.Equations, "equations"); PopulateNodes(letEqNode, @let.Equations); break; case ElaNodeType.ListLiteral: var @list = (ElaListLiteral)exp; var listNode = par.Simple(@list, "list"); foreach (var le in @list.Values) { PopulateNodes(listNode, le); } break; case ElaNodeType.Match: var @mt = (ElaMatch)exp; var mtNode = par.Simple(@mt, "match"); var mtExprNode = mtNode.Simple(@mt.Expression, "expression"); PopulateNodes(mtExprNode, @mt.Expression); var mtEntriesNode = mtNode.Simple(@mt.Entries, "entries"); PopulateNodes(mtEntriesNode, @mt.Entries); break; case ElaNodeType.ModuleInclude: var @inc = (ElaModuleInclude)exp; var incNode = par.Simple(@inc, "include " + (String.IsNullOrEmpty(@inc.Alias) ? @inc.Name : @inc.Name + "@" + @inc.Alias) + (String.IsNullOrEmpty(@inc.DllName) ? String.Empty : "#" + @inc.DllName)); foreach (var incNm in @inc.ImportList) { PopulateNodes(incNode, incNm); } break; case ElaNodeType.NameReference: var @nam = (ElaNameReference)exp; par.Name(@nam, (@nam.Bang ? "!" : String.Empty) + @nam.Name); break; case ElaNodeType.Newtype: var @newt = (ElaNewtype)exp; while (@newt != null) { var newtNode = par.Simple(@newt, (@newt.Extends ? "data " : (@newt.Opened ? "opentype " : "type ")) + (@newt.Prefix != null ? @newt.Prefix + "." : String.Empty) + @newt.Name); foreach (var newtCons in @newt.Constructors) { PopulateNodes(newtNode, newtCons); } @newt = @newt.And; } break; case ElaNodeType.Placeholder: par.Name(exp, "_"); break; case ElaNodeType.Primitive: var @prim = (ElaPrimitive)exp; par.Literal(@prim, @prim.Value.LiteralType, @prim.Value.ToString()); break; case ElaNodeType.Range: var @rng = (ElaRange)exp; var rngNode = par.Simple(@rng, "range"); var rngFirstNode = rngNode.Simple(@rng.First, "start"); PopulateNodes(rngFirstNode, @rng.First); if (@rng.Second != null) { var rngSecondNode = rngNode.Simple(@rng.Second, "step"); PopulateNodes(rngSecondNode, @rng.Second); } if (@rng.Last != null) { var rngLastNode = rngNode.Simple(@rng.Last, "end"); PopulateNodes(rngLastNode, @rng.Last); } break; case ElaNodeType.RecordLiteral: var @rec = (ElaRecordLiteral)exp; var recNode = par.Simple(@rec, "record"); foreach (var recFld in @rec.Fields) { PopulateNodes(recNode, recFld); } break; case ElaNodeType.Try: var @try = (ElaTry)exp; var tryNode = par.Simple(@try, "try"); var tryExprNode = tryNode.Simple(@try.Expression, "expression"); PopulateNodes(tryExprNode, @try.Expression); var tryEntriesNode = tryNode.Simple(@try.Entries, "entries"); PopulateNodes(tryEntriesNode, @try.Entries); break; case ElaNodeType.TupleLiteral: var @tup = (ElaTupleLiteral)exp; var tupNode = par.Simple(@tup, "tuple"); foreach (var tupEl in @tup.Parameters) { PopulateNodes(tupNode, tupEl); } break; case ElaNodeType.TypeCheck: var @typc = (ElaTypeCheck)exp; var typcNode = par.Simple(@typc, "type check"); var traits = typcNode.Simple(@typc, "traits"); foreach (var typcTra in @typc.Traits) { typcNode.Name(@typc, (typcTra.Prefix != null ? typcTra.Prefix + "." : String.Empty) + typcTra.Name, "trait"); } var typcExprNode = typcNode.Simple(@typc, "expression"); PopulateNodes(typcExprNode, @typc.Expression); break; case ElaNodeType.TypeClass: var @class = (ElaTypeClass)exp; while (@class != null) { var classNode = par.Simple(@class, "class " + @class.Name); foreach (var classMem in @class.Members) { PopulateNodes(classNode, classMem); } @class = @class.And; } break; case ElaNodeType.UnitLiteral: par.Literal(exp, ElaTypeCode.Unit, "()"); break; } }
//Performs validation of overlapping for simple case of pattern matching //(such as 'match' expression with a single pattern per entry). private void ValidateOverlapSimple(LabelMap map, IEnumerable <ElaEquation> seq, ElaExpression mexp) { var lst = new List <ElaExpression>(); foreach (var e in seq) { foreach (var o in lst) { if (!e.Left.CanFollow(o)) { AddWarning(map, ElaCompilerWarning.MatchEntryNotReachable, e.Left, FormatNode(e.Left), FormatNode(o)); } } lst.Add(e.Left); } }
private void AddHint(ElaCompilerHint hint, ElaExpression exp, params object[] args) { AddHint(hint, exp.Line, exp.Column, args); }
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); }
public static TreeNode Simple(this TreeNode par, ElaExpression exp, string str) { return(Element(par, exp, "", str, "Arrow", "{0}{1}")); }
private void AddWarning(LabelMap map, ElaCompilerWarning warning, ElaExpression exp, params object[] args) { AddWarning(map, warning, exp.Line, exp.Column, args); }
//This method can be called directly when a built-in is inlined. private void CompileBuiltinInline(ElaBuiltinKind kind, ElaExpression exp, LabelMap map, Hints hints) { switch (kind) { case ElaBuiltinKind.Fail: cw.Emit(Op.Throw); break; case ElaBuiltinKind.Seq: cw.Emit(Op.Force); cw.Emit(Op.Pop); break; case ElaBuiltinKind.ForwardPipe: cw.Emit(Op.Swap); cw.Emit(Op.Call); break; case ElaBuiltinKind.BackwardPipe: cw.Emit(Op.Call); break; case ElaBuiltinKind.LogicalOr: { var left = AddVariable(); var right = AddVariable(); PopVar(left); PopVar(right); PushVar(left); var termLab = cw.DefineLabel(); var exitLab = cw.DefineLabel(); cw.Emit(Op.Brtrue, termLab); PushVar(right); cw.Emit(Op.Br, exitLab); cw.MarkLabel(termLab); cw.Emit(Op.PushI1_1); cw.MarkLabel(exitLab); cw.Emit(Op.Nop); } break; case ElaBuiltinKind.LogicalAnd: { var left = AddVariable(); var right = AddVariable(); PopVar(left); PopVar(right); PushVar(left); var termLab = cw.DefineLabel(); var exitLab = cw.DefineLabel(); cw.Emit(Op.Brfalse, termLab); PushVar(right); cw.Emit(Op.Br, exitLab); cw.MarkLabel(termLab); cw.Emit(Op.PushI1_0); cw.MarkLabel(exitLab); cw.Emit(Op.Nop); } break; case ElaBuiltinKind.Head: cw.Emit(Op.Head); break; case ElaBuiltinKind.Tail: cw.Emit(Op.Tail); break; case ElaBuiltinKind.IsNil: cw.Emit(Op.Isnil); break; case ElaBuiltinKind.Negate: cw.Emit(Op.Neg); break; case ElaBuiltinKind.Length: cw.Emit(Op.Len); break; case ElaBuiltinKind.Force: cw.Emit(Op.Force); break; case ElaBuiltinKind.Not: cw.Emit(Op.Not); break; case ElaBuiltinKind.Show: cw.Emit(Op.Show); break; case ElaBuiltinKind.Concat: cw.Emit(Op.Concat); break; case ElaBuiltinKind.Add: cw.Emit(Op.Add); break; case ElaBuiltinKind.Divide: cw.Emit(Op.Div); break; case ElaBuiltinKind.Quot: cw.Emit(Op.Quot); break; case ElaBuiltinKind.Multiply: cw.Emit(Op.Mul); break; case ElaBuiltinKind.Power: cw.Emit(Op.Pow); break; case ElaBuiltinKind.Remainder: cw.Emit(Op.Rem); break; case ElaBuiltinKind.Modulus: cw.Emit(Op.Mod); break; case ElaBuiltinKind.Subtract: cw.Emit(Op.Sub); break; case ElaBuiltinKind.ShiftRight: cw.Emit(Op.Shr); break; case ElaBuiltinKind.ShiftLeft: cw.Emit(Op.Shl); break; case ElaBuiltinKind.Greater: cw.Emit(Op.Cgt); break; case ElaBuiltinKind.Lesser: cw.Emit(Op.Clt); break; case ElaBuiltinKind.Equal: cw.Emit(Op.Ceq); break; case ElaBuiltinKind.NotEqual: cw.Emit(Op.Cneq); break; case ElaBuiltinKind.GreaterEqual: cw.Emit(Op.Cgteq); break; case ElaBuiltinKind.LesserEqual: cw.Emit(Op.Clteq); break; case ElaBuiltinKind.BitwiseAnd: cw.Emit(Op.AndBw); break; case ElaBuiltinKind.BitwiseOr: cw.Emit(Op.OrBw); break; case ElaBuiltinKind.BitwiseXor: cw.Emit(Op.Xor); break; case ElaBuiltinKind.Cons: cw.Emit(Op.Cons); break; case ElaBuiltinKind.BitwiseNot: cw.Emit(Op.NotBw); break; case ElaBuiltinKind.GetValue: cw.Emit(Op.Pushelem); break; case ElaBuiltinKind.GetValueR: cw.Emit(Op.Swap); cw.Emit(Op.Pushelem); break; case ElaBuiltinKind.GetField: cw.Emit(Op.Pushfld); break; case ElaBuiltinKind.HasField: cw.Emit(Op.Hasfld); break; /* Api */ case ElaBuiltinKind.Api1: cw.Emit(Op.Api, 1); break; case ElaBuiltinKind.Api2: cw.Emit(Op.Api, 2); break; case ElaBuiltinKind.Api3: cw.Emit(Op.Api, 3); break; case ElaBuiltinKind.Api4: cw.Emit(Op.Api, 4); break; case ElaBuiltinKind.Api5: cw.Emit(Op.Api, 5); break; case ElaBuiltinKind.Api6: cw.Emit(Op.Api, 6); break; case ElaBuiltinKind.Api7: cw.Emit(Op.Api, 7); break; case ElaBuiltinKind.Api8: cw.Emit(Op.Api, 8); break; case ElaBuiltinKind.Api9: cw.Emit(Op.Api, 9); break; case ElaBuiltinKind.Api10: cw.Emit(Op.Api, 10); break; case ElaBuiltinKind.Api11: cw.Emit(Op.Api, 11); break; case ElaBuiltinKind.Api12: cw.Emit(Op.Api, 12); break; case ElaBuiltinKind.Api13: cw.Emit(Op.Api, 13); break; case ElaBuiltinKind.Api14: cw.Emit(Op.Api, 14); break; case ElaBuiltinKind.Api15: cw.Emit(Op.Api, 15); break; case ElaBuiltinKind.Api16: cw.Emit(Op.Api, 16); break; case ElaBuiltinKind.Api17: cw.Emit(Op.Api, 17); break; case ElaBuiltinKind.Api18: cw.Emit(Op.Api, 18); break; case ElaBuiltinKind.Api101: cw.Emit(Op.Api2, 101); break; case ElaBuiltinKind.Api102: cw.Emit(Op.Api2, 102); break; case ElaBuiltinKind.Api103: cw.Emit(Op.Api2, 103); break; case ElaBuiltinKind.Api104: cw.Emit(Op.Api2, 104); break; case ElaBuiltinKind.Api105: cw.Emit(Op.Api2, 105); break; case ElaBuiltinKind.Api106: cw.Emit(Op.Api2, 106); break; case ElaBuiltinKind.Api107: cw.Emit(Op.Api2, 107); break; } }
//This method generate a warning and hint and when a value is not used and //pops this value from the top of the stack. private void AddValueNotUsed(LabelMap map, ElaExpression exp) { AddWarning(map, ElaCompilerWarning.ValueNotUsed, exp, FormatNode(exp)); AddHint(ElaCompilerHint.UseIgnoreToPop, exp, FormatNode(exp, true)); cw.Emit(Op.Pop); }
private void FindName(string name, CodeDocument doc, ElaExpression expr, List <SymbolLocation> syms) { if (expr == null) { return; } switch (expr.Type) { case ElaNodeType.DebugPoint: FindName(name, doc, ((ElaDebugPoint)expr).Expression, syms); break; case ElaNodeType.As: { var a = (ElaAs)expr; if (a.Name == name) { syms.Add(new SymbolLocation(doc, a.Line, a.Column)); } if (a.Expression != null) { FindName(name, doc, a.Expression, syms); } } break; case ElaNodeType.EquationSet: { var b = (ElaEquationSet)expr; foreach (var e in b.Equations) { FindName(name, doc, e, syms); } } break; case ElaNodeType.Builtin: break; case ElaNodeType.Newtype: { var b = (ElaNewtype)expr; foreach (var e in b.Constructors) { FindName(name, doc, e, syms); } } break; case ElaNodeType.TypeClass: { var b = (ElaTypeClass)expr; if (b.Members != null) { foreach (var m in b.Members) { FindName(name, doc, m, syms); } } if (b.And != null) { FindName(name, doc, b.And, syms); } } break; case ElaNodeType.ClassMember: { var b = (ElaClassMember)expr; if (b.Name == name) { syms.Add(new SymbolLocation(doc, b.Line, b.Column)); } } break; case ElaNodeType.ClassInstance: { var b = (ElaClassInstance)expr; if (b.Where != null) { FindName(name, doc, b.Where, syms); } if (b.And != null) { FindName(name, doc, b.And, syms); } } break; case ElaNodeType.Equation: { var b = (ElaEquation)expr; if (b.Left != null) { FindName(name, doc, b.Left, syms); } if (b.Right != null) { FindName(name, doc, b.Right, syms); } if (b.Next != null) { FindName(name, doc, b.Next, syms); } } break; case ElaNodeType.LetBinding: { var b = (ElaLetBinding)expr; if (b.Equations != null) { FindName(name, doc, b.Equations, syms); } if (b.Expression != null) { FindName(name, doc, b.Expression, syms); } } break; case ElaNodeType.Comprehension: { var c = (ElaComprehension)expr; if (c.Generator != null) { FindName(name, doc, c.Generator, syms); } } break; case ElaNodeType.Condition: { var c = (ElaCondition)expr; if (c.Condition != null) { FindName(name, doc, c.Condition, syms); } if (c.True != null) { FindName(name, doc, c.True, syms); } if (c.False != null) { FindName(name, doc, c.False, syms); } } break; case ElaNodeType.Placeholder: break; case ElaNodeType.FieldDeclaration: { var f = (ElaFieldDeclaration)expr; if (f.FieldValue != null) { FindName(name, doc, f.FieldValue, syms); } } break; case ElaNodeType.FieldReference: { var r = (ElaFieldReference)expr; if (r.TargetObject != null) { FindName(name, doc, r.TargetObject, syms); } } break; case ElaNodeType.Juxtaposition: { var c = (ElaJuxtaposition)expr; FindName(name, doc, c.Target, syms); foreach (var p in c.Parameters) { FindName(name, doc, p, syms); } } break; case ElaNodeType.Lambda: { var f = (ElaLambda)expr; if (f.Left != null) { FindName(name, doc, f.Left, syms); } if (f.Right != null) { FindName(name, doc, f.Right, syms); } } break; case ElaNodeType.Generator: { var g = (ElaGenerator)expr; if (g.Target != null) { FindName(name, doc, g.Target, syms); } if (g.Pattern != null) { FindName(name, doc, g.Pattern, syms); } if (g.Guard != null) { FindName(name, doc, g.Guard, syms); } if (g.Body != null) { FindName(name, doc, g.Body, syms); } } break; case ElaNodeType.ImportedVariable: { var v = (ElaImportedVariable)expr; if (v.LocalName == name || v.Name == name) { syms.Add(new SymbolLocation(doc, v.Line, v.Column)); } } break; case ElaNodeType.TypeCheck: { var i = (ElaTypeCheck)expr; if (i.Expression != null) { FindName(name, doc, i.Expression, syms); } } break; case ElaNodeType.LazyLiteral: { var l = (ElaLazyLiteral)expr; if (l.Expression != null) { FindName(name, doc, l.Expression, syms); } } break; case ElaNodeType.ListLiteral: { var l = (ElaListLiteral)expr; if (l.Values != null) { foreach (var v in l.Values) { FindName(name, doc, v, syms); } } } break; case ElaNodeType.Match: { var m = (ElaMatch)expr; if (m.Expression != null) { FindName(name, doc, m.Expression, syms); } if (m.Entries != null) { FindName(name, doc, m.Entries, syms); } } break; case ElaNodeType.ModuleInclude: { var m = (ElaModuleInclude)expr; if (m.Alias == name) { syms.Add(new SymbolLocation(doc, m.Line, m.Column)); } if (m.HasImportList) { foreach (var i in m.ImportList) { FindName(name, doc, i, syms); } } } break; case ElaNodeType.Primitive: break; case ElaNodeType.Range: { var r = (ElaRange)expr; if (r.First != null) { FindName(name, doc, r.First, syms); } if (r.Second != null) { FindName(name, doc, r.Second, syms); } if (r.Last != null) { FindName(name, doc, r.Last, syms); } } break; case ElaNodeType.RecordLiteral: { var r = (ElaRecordLiteral)expr; if (r.Fields != null) { foreach (var f in r.Fields) { FindName(name, doc, f, syms); } } } break; case ElaNodeType.Try: { var t = (ElaTry)expr; if (t.Expression != null) { FindName(name, doc, t.Expression, syms); } if (t.Entries != null) { FindName(name, doc, t.Entries, syms); } } break; case ElaNodeType.TupleLiteral: { var t = (ElaTupleLiteral)expr; if (t.Parameters != null) { foreach (var p in t.Parameters) { FindName(name, doc, p, syms); } } } break; case ElaNodeType.NameReference: { var r = (ElaNameReference)expr; if (r.Name == name) { syms.Add(new SymbolLocation(doc, r.Line, r.Column)); } } break; } }
//Pushes a primitive value. It can be a string, a char, //a 32-bit integer, a 64-bit integer, a 32-bit float, a 64-bit float, //a boolean or unit. private void PushPrimitive(ElaExpression exp, ElaLiteralValue val) { switch (val.LiteralType) { case ElaTypeCode.String: var str = val.AsString(); //String is added to the string table and indexed //An empty string is pushed using special op typeId. if (str.Length == 0) { cw.Emit(Op.Pushstr_0); } else { cw.Emit(Op.Pushstr, AddString(str)); } break; case ElaTypeCode.Char: cw.Emit(Op.PushCh, val.AsInteger()); break; case ElaTypeCode.Integer: var v = val.AsInteger(); if (v == 0) { cw.Emit(Op.PushI4_0); } else { cw.Emit(Op.PushI4, v); } break; case ElaTypeCode.Long: //64-bit long is pushed as two 32-bit integers cw.Emit(Op.PushI4, val.GetData().I4_1); cw.Emit(Op.PushI4, val.GetData().I4_2); cw.Emit(Op.NewI8); break; case ElaTypeCode.Single: cw.Emit(Op.PushR4, val.GetData().I4_1); break; case ElaTypeCode.Double: //64-bit float is pushed as two 32-bit integers cw.Emit(Op.PushI4, val.GetData().I4_1); cw.Emit(Op.PushI4, val.GetData().I4_2); cw.Emit(Op.NewR8); break; case ElaTypeCode.Boolean: cw.Emit(val.AsBoolean() ? Op.PushI1_1 : Op.PushI1_0); break; case ElaTypeCode.__Reserved: cw.Emit(Op.Pushstr, AddString(val.AsString())); var sv = GetVariable("literal'" + Char.ToLower(val.Postfix), exp.Line, exp.Column); PushVar(sv); cw.Emit(Op.Call); break; default: cw.Emit(Op.Pushunit); break; } }
public static TreeNode Control(this TreeNode par, ElaExpression exp, string title, object data) { return(Element(par, exp, title, data, "Function", "{0} {1}")); }