Пример #1
0
        public IOperand CompileAsOperand([NotNull] IRoutineBuilder rb, [NotNull] ZilObject expr, [NotNull] ISourceLine src,
                                         [CanBeNull] IVariable suggestion = null)
        {
            expr = expr.Unwrap(Context);

            var constant = CompileConstant(expr, AmbiguousConstantMode.Pessimistic);

            if (constant != null)
            {
                return(constant);
            }

            switch (expr.StdTypeAtom)
            {
            case StdAtom.FORM:
                return(CompileForm(rb, (ZilForm)expr, true, suggestion ?? rb.Stack));

            case StdAtom.ATOM:
                var atom = (ZilAtom)expr;
                if (Globals.ContainsKey(atom))
                {
                    Context.HandleError(new CompilerError(src,
                                                          CompilerMessages.Bare_Atom_0_Interpreted_As_Global_Variable_Index, atom));
                    return(Globals[atom].Indirect);
                }
                if (SoftGlobals.ContainsKey(atom))
                {
                    Context.HandleError(new CompilerError(
                                            expr.SourceLine ?? src,
                                            CompilerMessages.Soft_Variable_0_May_Not_Be_Used_Here,
                                            atom));
                }
                else
                {
                    Context.HandleError(new CompilerError(
                                            expr.SourceLine ?? src,
                                            CompilerMessages.Bare_Atom_0_Used_As_Operand_Is_Not_A_Global_Variable,
                                            atom));
                }
                return(Game.Zero);

            default:
                Context.HandleError(new CompilerError(
                                        expr.SourceLine ?? src,
                                        CompilerMessages.Expressions_Of_This_Type_Cannot_Be_Compiled));
                return(Game.Zero);
            }
        }
Пример #2
0
        // TODO: replace CompileStmt with CompileForm and (in loops) CompileClauseBody
        void CompileStmt([NotNull] IRoutineBuilder rb, [NotNull] ZilObject stmt, bool wantResult)
        {
            stmt = stmt.Unwrap(Context);

            switch (stmt)
            {
            case ZilForm form:
                MarkSequencePoint(rb, form);

                var result = CompileForm(rb, form, wantResult, null);

                if (wantResult)
                {
                    rb.Return(result);
                }
                break;

            case ZilList _:
                throw new CompilerError(stmt, CompilerMessages.Expressions_Of_This_Type_Cannot_Be_Compiled)
                      .Combine(new CompilerError(CompilerMessages.Misplaced_Bracket_In_COND_Or_Loop));

            default:
                if (wantResult)
                {
                    var value = CompileConstant(stmt);

                    if (value == null)
                    {
                        // TODO: show "expressions of this type cannot be compiled" warning even if wantResult is false?
                        throw new CompilerError(stmt, CompilerMessages.Expressions_Of_This_Type_Cannot_Be_Compiled);
                    }

                    rb.Return(value);
                }
                break;
            }
        }
Пример #3
0
        public IOperand CompileConstant([NotNull] ZilObject expr, AmbiguousConstantMode mode)
        {
            switch (expr.Unwrap(Context))
            {
            case ZilFix fix:
                return(Game.MakeOperand(fix.Value));

            case ZilHash hash when hash.StdTypeAtom == StdAtom.BYTE && hash.GetPrimitive(Context) is ZilFix fix:
                return(Game.MakeOperand(fix.Value));

            case ZilWord word:
                return(CompileConstant(word.Value));

            case ZilString str:
                return(Game.MakeOperand(TranslateString(str, Context)));

            case ZilChar ch:
                return(Game.MakeOperand((byte)ch.Char));

            case ZilAtom atom:
                if (atom.StdAtom == StdAtom.T)
                {
                    return(Game.One);
                }
                if (Routines.TryGetValue(atom, out var routine))
                {
                    return(routine);
                }
                if (Objects.TryGetValue(atom, out var obj))
                {
                    return(obj);
                }
                if (Constants.TryGetValue(atom, out var operand))
                {
                    return(operand);
                }

                if (mode == AmbiguousConstantMode.Optimistic && Globals.TryGetValue(atom, out var global))
                {
                    Context.HandleError(new CompilerError((ISourceLine)null,
                                                          CompilerMessages.Bare_Atom_0_Interpreted_As_Global_Variable_Index, atom));
                    return(global);
                }
                return(null);

            case ZilFalse _:
                return(Game.Zero);

            case ZilTable table:
                if (Tables.TryGetValue(table, out var tb))
                {
                    return(tb);
                }

                tb = Game.DefineTable(table.Name, true);
                Tables.Add(table, tb);
                return(tb);

            case ZilConstant constant:
                return(CompileConstant(constant.Value));

            case ZilForm form:
                return(form.IsGVAL(out var globalAtom) ? CompileConstant(globalAtom, AmbiguousConstantMode.Pessimistic) : null);

            case ZilHash hash when hash.StdTypeAtom == StdAtom.VOC && hash.GetPrimitive(Context) is ZilAtom primAtom:
                var wordAtom = ZilAtom.Parse("W?" + primAtom.Text, Context);
                if (Constants.TryGetValue(wordAtom, out operand))
                {
                    return(operand);
                }
                return(null);

            default:
                var primitive = expr.GetPrimitive(Context);
                if (primitive != expr && primitive.GetTypeAtom(Context) != expr.GetTypeAtom(Context))
                {
                    return(CompileConstant(primitive));
                }
                return(null);
            }
        }
Пример #4
0
        internal void CompileCondition([NotNull] IRoutineBuilder rb, [NotNull] ZilObject expr, [NotNull] ISourceLine src,
                                       [NotNull] ILabel label, bool polarity)
        {
            expr = expr.Unwrap(Context);
            var type = expr.StdTypeAtom;

            // ReSharper disable once SwitchStatementMissingSomeCases
            switch (type)
            {
            case StdAtom.FALSE:
                if (polarity == false)
                {
                    rb.Branch(label);
                }
                return;

            case StdAtom.ATOM:
                var atom = (ZilAtom)expr;
                if (atom.StdAtom != StdAtom.T && atom.StdAtom != StdAtom.ELSE)
                {
                    // could be a missing , or . before variable name
                    var warning = new CompilerError(src, CompilerMessages.Bare_Atom_0_Treated_As_True_Here, expr);

                    if (Locals.ContainsKey(atom) || Globals.ContainsKey(atom))
                    {
                        warning = warning.Combine(new CompilerError(src, CompilerMessages.Did_You_Mean_The_Variable));
                    }

                    Context.HandleError(warning);
                }

                if (polarity)
                {
                    rb.Branch(label);
                }
                return;

            case StdAtom.FIX:
                bool nonzero = ((ZilFix)expr).Value != 0;
                if (polarity == nonzero)
                {
                    rb.Branch(label);
                }
                return;

            case StdAtom.FORM:
                // handled below
                break;

            default:
                Context.HandleError(new CompilerError(expr.SourceLine ?? src, CompilerMessages.Expressions_Of_This_Type_Cannot_Be_Compiled));
                return;
            }

            // it's a FORM
            var form = (ZilForm)expr;

            if (!(form.First is ZilAtom head))
            {
                Context.HandleError(new CompilerError(form, CompilerMessages.FORM_Must_Start_With_An_Atom));
                return;
            }

            // check for standard built-ins
            // prefer the predicate version, then value, value+predicate, void
            // (value+predicate is hard to clean up)
            var zversion = Context.ZEnvironment.ZVersion;
            var argCount = form.Count() - 1;

            if (ZBuiltins.IsBuiltinPredCall(head.Text, zversion, argCount))
            {
                ZBuiltins.CompilePredCall(head.Text, this, rb, form, label, polarity);
                return;
            }
            if (ZBuiltins.IsBuiltinValueCall(head.Text, zversion, argCount))
            {
                var result = ZBuiltins.CompileValueCall(head.Text, this, rb, form, rb.Stack);
                BranchIfNonZero(result);
                return;
            }
            if (ZBuiltins.IsBuiltinValuePredCall(head.Text, zversion, argCount))
            {
                if (rb.CleanStack)
                {
                    /* wasting the branch and checking the result with ZERO? is more efficient
                     * than using the branch and having to clean the result off the stack */
                    var noBranch = rb.DefineLabel();
                    ZBuiltins.CompileValuePredCall(head.Text, this, rb, form, rb.Stack, noBranch, true);
                    rb.MarkLabel(noBranch);
                    rb.BranchIfZero(rb.Stack, label, !polarity);
                }
                else
                {
                    ZBuiltins.CompileValuePredCall(head.Text, this, rb, form, rb.Stack, label, polarity);
                }
                return;
            }
            if (ZBuiltins.IsBuiltinVoidCall(head.Text, zversion, argCount))
            {
                ZBuiltins.CompileVoidCall(head.Text, this, rb, form);

                // void calls return true
                if (polarity)
                {
                    rb.Branch(label);
                }
                return;
            }

            // special cases
            var op1 = CompileAsOperand(rb, form, form.SourceLine);

            BranchIfNonZero(op1);

            void BranchIfNonZero(IOperand operand)
            {
                if (operand is INumericOperand numericResult)
                {
                    if (numericResult.Value != 0 == polarity)
                    {
                        rb.Branch(label);
                    }
                }
                else
                {
                    rb.BranchIfZero(operand, label, !polarity);
                }
            }
        }
Пример #5
0
        internal IOperand CompileAsOperandWithBranch([NotNull] IRoutineBuilder rb, [NotNull] ZilObject expr,
                                                     [CanBeNull] IVariable resultStorage,
                                                     [NotNull] ILabel label, bool polarity, [CanBeNull][InstantHandle] Func <IVariable> tempVarProvider = null)
        {
            expr = expr.Unwrap(Context);
            IOperand result = resultStorage;

            switch (expr)
            {
            case ZilFalse _:
                if (resultStorage == null)
                {
                    result = Game.Zero;
                }
                else
                {
                    rb.EmitStore(resultStorage, Game.Zero);
                }

                if (polarity == false)
                {
                    rb.Branch(label);
                }

                return(result);

            case ZilFix fix:
                if (resultStorage == null)
                {
                    result = Game.MakeOperand(fix.Value);
                }
                else
                {
                    rb.EmitStore(resultStorage, Game.MakeOperand(fix.Value));
                }

                bool nonzero = fix.Value != 0;
                if (polarity == nonzero)
                {
                    rb.Branch(label);
                }

                return(result);

            case ZilForm form:
                if (!(form.First is ZilAtom head))
                {
                    Context.HandleError(new CompilerError(form, CompilerMessages.FORM_Must_Start_With_An_Atom));
                    return(Game.Zero);
                }

                // check for standard built-ins
                // prefer the value+predicate version, then value, predicate, void
                var zversion = Context.ZEnvironment.ZVersion;
                var argCount = form.Count() - 1;
                if (ZBuiltins.IsBuiltinValuePredCall(head.Text, zversion, argCount))
                {
                    if (resultStorage == null)
                    {
                        Debug.Assert(tempVarProvider != null);
                        resultStorage = tempVarProvider();
                    }

                    ZBuiltins.CompileValuePredCall(head.Text, this, rb, form, resultStorage, label, polarity);
                    return(resultStorage);
                }
                if (ZBuiltins.IsBuiltinValueCall(head.Text, zversion, argCount))
                {
                    result = ZBuiltins.CompileValueCall(head.Text, this, rb, form, resultStorage);
                    if (resultStorage != null && resultStorage != result)
                    {
                        rb.EmitStore(resultStorage, result);
                        result = resultStorage;
                    }
                    else if (resultStorage == null && result == rb.Stack)
                    {
                        Debug.Assert(tempVarProvider != null);
                        resultStorage = tempVarProvider();
                        rb.EmitStore(resultStorage, result);
                        result = resultStorage;
                    }
                    rb.BranchIfZero(result, label, !polarity);
                    return(result);
                }
                if (ZBuiltins.IsBuiltinPredCall(head.Text, zversion, argCount))
                {
                    if (resultStorage == null)
                    {
                        Debug.Assert(tempVarProvider != null);
                        resultStorage = tempVarProvider();
                    }

                    var label1 = rb.DefineLabel();
                    var label2 = rb.DefineLabel();
                    ZBuiltins.CompilePredCall(head.Text, this, rb, form, label1, true);
                    rb.EmitStore(resultStorage, Game.Zero);
                    rb.Branch(polarity ? label2 : label);
                    rb.MarkLabel(label1);
                    rb.EmitStore(resultStorage, Game.One);
                    if (polarity)
                    {
                        rb.Branch(label);
                    }
                    rb.MarkLabel(label2);
                    return(resultStorage);
                }
                if (ZBuiltins.IsBuiltinVoidCall(head.Text, zversion, argCount))
                {
                    ZBuiltins.CompileVoidCall(head.Text, this, rb, form);

                    // void calls return true
                    if (resultStorage == null)
                    {
                        result = Game.One;
                    }
                    else
                    {
                        rb.EmitStore(resultStorage, Game.One);
                    }

                    if (polarity)
                    {
                        rb.Branch(label);
                    }

                    return(result);
                }

                // for anything more complicated, treat it as a value
                result = CompileAsOperand(rb, form, form.SourceLine, resultStorage);
                if (resultStorage != null && resultStorage != result)
                {
                    rb.EmitStore(resultStorage, result);
                    result = resultStorage;
                }
                else if (resultStorage == null && result == rb.Stack)
                {
                    Debug.Assert(tempVarProvider != null);
                    resultStorage = tempVarProvider();
                    rb.EmitStore(resultStorage, result);
                    result = resultStorage;
                }

                rb.BranchIfZero(result, label, !polarity);
                return(result);

            default:
                var constValue = CompileConstant(expr);
                if (constValue == null)
                {
                    Context.HandleError(new CompilerError(expr, CompilerMessages.Expressions_Of_This_Type_Cannot_Be_Compiled));
                    return(Game.Zero);
                }
                else
                {
                    if (resultStorage == null)
                    {
                        result = constValue;
                    }
                    else
                    {
                        rb.EmitStore(resultStorage, constValue);
                    }

                    if (polarity)
                    {
                        rb.Branch(label);
                    }
                }
                return(result);
            }
        }