예제 #1
0
 public VoidCall([NotNull] Compilation cc, [NotNull] IRoutineBuilder rb, [NotNull] ZilForm form)
     : this()
 {
     this.cc   = cc;
     this.rb   = rb;
     this.form = form;
 }
예제 #2
0
 public ValueCall([NotNull] Compilation cc, [NotNull] IRoutineBuilder rb, [NotNull] ZilForm form, [NotNull] IVariable resultStorage)
     : this()
 {
     this.cc            = cc;
     this.rb            = rb;
     this.form          = form;
     this.resultStorage = resultStorage;
 }
예제 #3
0
 public PredCall([NotNull] Compilation cc, [NotNull] IRoutineBuilder rb, [NotNull] ZilForm form, [NotNull] ILabel label, bool polarity)
     : this()
 {
     this.cc       = cc;
     this.rb       = rb;
     this.form     = form;
     this.label    = label;
     this.polarity = polarity;
 }
예제 #4
0
        static ZilFix TranslateType([NotNull] Context ctx, [NotNull] ZilAtom type)
        {
            // ReSharper disable once SwitchStatementMissingSomeCases
            switch (type.StdAtom)
            {
            case StdAtom.TADJ:
                type = ctx.GetStdAtom(StdAtom.ADJ);
                break;

            case StdAtom.TOBJECT:
                type = ctx.GetStdAtom(StdAtom.NOUN);
                break;

            case StdAtom.TPREP:
                type = ctx.GetStdAtom(StdAtom.PREP);
                break;

            case StdAtom.TDIR:
                type = ctx.GetStdAtom(StdAtom.DIR);
                break;

            case StdAtom.TVERB:
                type = ctx.GetStdAtom(StdAtom.VERB);
                break;
            }

            ZilFix classification;

            switch (type.StdAtom)
            {
            case StdAtom.BUZZ:
            case StdAtom.TBUZZ:
            case StdAtom.TZERO:
                classification = ZilFix.Zero;
                break;

            default:
                // call user-provided <GET-CLASSIFICATION type>
                var form = new ZilForm(new ZilObject[]
                {
                    ctx.GetStdAtom(StdAtom.GET_CLASSIFICATION),
                    type
                });

                classification = (ZilObject)form.Eval(ctx) as ZilFix;

                if (classification == null)
                {
                    throw new InterpreterError(InterpreterMessages._0_1_Must_Return_2, "NEW-ADD-WORD", "GET-CLASSIFICATION", "a FIX");
                }

                break;
            }

            return(classification);
        }
예제 #5
0
        internal void ExpandInPlace([NotNull] Context ctx)
        {
            IEnumerable <ZilObject> RecursiveExpandWithSplice(ZilObject zo)
            {
                ZilObject result;

                ZilObject SetSourceLine(ZilResult zr)
                {
                    var newObj = (ZilObject)zr;

                    newObj.SourceLine = zo.SourceLine;
                    return(newObj);
                }

                switch (zo)
                {
                case ZilList list:
                    result = new ZilList(list.SelectMany(RecursiveExpandWithSplice));
                    break;

                case ZilVector vector:
                    result = new ZilVector(vector.SelectMany(RecursiveExpandWithSplice).ToArray());
                    break;

                case ZilForm form:
                    ZilObject expanded;
                    try
                    {
                        using (DiagnosticContext.Push(form.SourceLine))
                        {
                            expanded = (ZilObject)form.Expand(ctx);
                        }
                    }
                    catch (InterpreterError ex)
                    {
                        ctx.HandleError(ex);
                        return(new[] { ctx.FALSE });
                    }
                    if (expanded is IMayExpandAfterEvaluation expandAfter &&
                        expandAfter.ShouldExpandAfterEvaluation)
                    {
                        return(expandAfter.ExpandAfterEvaluation().AsResultSequence()
                               .Select(SetSourceLine)
                               .Select(xo => ReferenceEquals(xo, form) ? xo : new ZilMacroResult(xo)));
                    }
                    else if (!ReferenceEquals(expanded, form))
                    {
                        expanded.SourceLine = zo.SourceLine;
                        return(RecursiveExpandWithSplice(expanded)
                               .Select(xo => new ZilMacroResult(xo)));
                    }
                    else
                    {
                        result = new ZilForm(form.SelectMany(RecursiveExpandWithSplice));
                    }
                    break;
예제 #6
0
 public ValuePredCall([NotNull] Compilation cc, [NotNull] IRoutineBuilder rb, [NotNull] ZilForm form,
                      [NotNull] IVariable resultStorage, [NotNull] ILabel label, bool polarity)
     : this()
 {
     this.cc            = cc;
     this.rb            = rb;
     this.form          = form;
     this.resultStorage = resultStorage;
     this.label         = label;
     this.polarity      = polarity;
 }
예제 #7
0
        public void TestEVAL()
        {
            // most values eval to themselves
            TestHelpers.EvalAndAssert("<EVAL 123>", new ZilFix(123));
            TestHelpers.EvalAndAssert("<EVAL \"hello\">", ZilString.FromString("hello"));

            var ctx = new Context();

            TestHelpers.EvalAndAssert(ctx, "<EVAL +>", ctx.GetStdAtom(StdAtom.Plus));
            TestHelpers.EvalAndAssert(ctx, "<EVAL <>>", ctx.FALSE);

            // lists eval to new lists formed by evaluating each element
            var list = new ZilList(new ZilObject[] {
                new ZilFix(1),
                new ZilForm(new ZilObject[] {
                    ctx.GetStdAtom(StdAtom.Plus),
                    new ZilFix(1),
                    new ZilFix(1)
                }),
                new ZilFix(3)
            });
            var expected = new ZilList(new ZilObject[] {
                new ZilFix(1),
                new ZilFix(2),
                new ZilFix(3)
            });

            ctx.SetLocalVal(ctx.GetStdAtom(StdAtom.T), list);
            var actual = TestHelpers.Evaluate(ctx, "<EVAL .T>");

            TestHelpers.AssertStructurallyEqual(expected, actual);

            // forms execute when evaluated
            var form = new ZilForm(new ZilObject[] { ctx.GetStdAtom(StdAtom.Plus), new ZilFix(1), new ZilFix(2) });

            ctx.SetLocalVal(ctx.GetStdAtom(StdAtom.T), form);
            TestHelpers.EvalAndAssert(ctx, "<EVAL .T>", new ZilFix(3));

            // must have 1-2 arguments
            TestHelpers.EvalAndCatch <ArgumentCountError>("<EVAL>");
            TestHelpers.EvalAndCatch <ArgumentCountError>("<EVAL FOO BAR BAZ>");

            // 2nd argument must be an ENVIRONMENT
            TestHelpers.EvalAndCatch <ArgumentTypeError>("<EVAL FOO BAR>");

            TestHelpers.Evaluate(ctx, "<SET A 0>");
            TestHelpers.Evaluate(ctx, "<DEFINE RIGHT (\"BIND\" E 'B \"AUX\" (A 1)) <EVAL .B .E>>");
            TestHelpers.EvalAndAssert(ctx, "<RIGHT .A>", new ZilFix(0));
        }
예제 #8
0
        static bool CheckFormOrSegment([NotNull] Context ctx, [NotNull] ZilObject value, [NotNull] ZilForm form,
                                       bool segment, bool ignoreErrors)
        {
            var(first, rest) = form;

            // special forms
            // ReSharper disable once SwitchStatementMissingSomeCases
            switch ((first as ZilAtom)?.StdAtom)
            {
            case StdAtom.OR:
                return(rest.Any(subpattern => Check(ctx, value, subpattern, ignoreErrors)));

            case StdAtom.QUOTE:
                return(rest.First?.StructurallyEquals(value) ?? false);

            case StdAtom.PRIMTYPE when rest.First is ZilAtom primType:
                // special case for GVAL and LVAL, which can substitute for <PRIMTYPE ATOM>
                return
                    (value.PrimType == ctx.GetTypePrim(primType) ||
                     primType.StdAtom == StdAtom.ATOM &&
                     (value.IsGVAL(out _) || value.IsLVAL(out _)));
            }

            // structure form: first pattern element is a DECL matched against the whole structure
            // (usually a type atom), remaining elements are matched against the structure elements
            if (first == null || !Check(ctx, value, first, ignoreErrors))
            {
                return(false);
            }

            if (value is IStructure valueAsStructure)
            {
                // yay
            }
            else if (value is IProvideStructureForDeclCheck structProvider)
            {
                valueAsStructure = structProvider.GetStructureForDeclCheck(ctx);
            }
            else
            {
                return(false);
            }

            return(CheckElements(ctx, valueAsStructure, rest, segment, ignoreErrors));
        }
예제 #9
0
        public void MakeVerb(IWord word, ISourceLine location)
        {
            var nw = (NewParserWord)word;

            if (!nw.HasClass(verbClass))
            {
                var form     = new ZilForm(new ZilObject[] { ctx.GetStdAtom(StdAtom.MAKE_VERB_DATA) });
                var verbData = (ZilObject)form.Eval(ctx);

                nw.VerbStuff = verbData;
                ctx.PutProp(verbData, ctx.GetStdAtom(StdAtom.VERB_STUFF_ID), nw.Inner);

                NewAddWord(
                    nw.Atom,
                    ctx.GetStdAtom(StdAtom.TVERB),
                    verbData,
                    ZilFix.Zero);
            }
        }
예제 #10
0
        /* GetViaInner and SetViaInner disable DECL checking because user code may expect
         * property identifiers to be passed as FIXes instead of ATOMs. */
        ZilObject GetViaInner(StdAtom accessor)
        {
            var oldCheckDecls = ctx.CheckDecls;

            try
            {
                ctx.CheckDecls = false;
                var form = new ZilForm(new ZilObject[]
                {
                    ctx.GetStdAtom(accessor),
                    Inner
                });

                return((ZilObject)form.Eval(ctx));
            }
            finally
            {
                ctx.CheckDecls = oldCheckDecls;
            }
        }
예제 #11
0
        public static NewParserWord FromVword([NotNull] Context ctx, [NotNull] ZilHash vword)
        {
            var form = new ZilForm(new ZilObject[]
            {
                ctx.GetStdAtom(StdAtom.WORD_LEXICAL_WORD),
                vword
            });

            if (!((ZilObject)form.Eval(ctx) is ZilString lexicalWord))
            {
                throw new InterpreterError(
                          InterpreterMessages._0_1_Must_Return_2,
                          InterpreterMessages.NoFunction,
                          "WORD-LEXICAL-WORD",
                          "a string");
            }

            var atom = ZilAtom.Parse(lexicalWord.Text, ctx);

            return(new NewParserWord(ctx, atom, vword));
        }
예제 #12
0
        internal static ZilForm SubstituteIfflagForm([NotNull] Context ctx, [NotNull] ZilForm form)
        {
            var body = form.Select(zo =>
            {
                ZilObject value;

                switch (zo)
                {
                case ZilAtom atom when((value = ctx.GetCompilationFlagValue(atom)) != null):
                    return(value);

                default:
                    return(zo);
                }
            });

            return(new ZilForm(body)
            {
                SourceLine = form.SourceLine
            });
        }
예제 #13
0
        /// <exception cref="InterpreterError">MAKE-VWORD did not return a VWORD.</exception>
        public IWord CreateWord(ZilAtom atom)
        {
            var form = new ZilForm(new ZilObject[]
            {
                ctx.GetStdAtom(StdAtom.MAKE_VWORD),
                ZilString.FromString(atom.Text),
                ZilFix.Zero,
                ZilFix.Zero
            });

            if (!((ZilObject)form.Eval(ctx) is ZilHash vword) || vword.StdTypeAtom != StdAtom.VWORD)
            {
                throw new InterpreterError(
                          InterpreterMessages._0_1_Must_Return_2,
                          InterpreterMessages.NoFunction,
                          "MAKE-VWORD",
                          "a VWORD");
            }

            return(new NewParserWord(ctx, atom, vword));
        }
예제 #14
0
        void SetViaInner(StdAtom accessor, ZilObject value)
        {
            var oldCheckDecls = ctx.CheckDecls;

            try
            {
                ctx.CheckDecls = false;
                var form = new ZilForm(new[]
                {
                    ctx.GetStdAtom(accessor),
                    Inner,
                    value
                });

                form.Eval(ctx);
            }
            finally
            {
                ctx.CheckDecls = oldCheckDecls;
            }
        }
예제 #15
0
        public void TestEXPAND()
        {
            // most values expand to themselves
            TestHelpers.EvalAndAssert("<EXPAND 123>", new ZilFix(123));
            TestHelpers.EvalAndAssert("<EXPAND \"hello\">", ZilString.FromString("hello"));

            var ctx = new Context();

            TestHelpers.EvalAndAssert(ctx, "<EXPAND +>", ctx.GetStdAtom(StdAtom.Plus));
            TestHelpers.EvalAndAssert(ctx, "<EXPAND <>>", ctx.FALSE);

            // lists expand to copies of themselves
            var list = new ZilList(new ZilObject[] { new ZilFix(1), new ZilFix(2), new ZilFix(3) });

            ctx.SetLocalVal(ctx.GetStdAtom(StdAtom.T), list);
            var actual = TestHelpers.Evaluate(ctx, "<EXPAND .T>");

            TestHelpers.AssertStructurallyEqual(list, actual);
            Assert.AreNotSame(list, actual);

            // forms execute when evaluated
            TestHelpers.Evaluate(ctx, "<DEFMAC FOO () <FORM BAR>>");
            var expected = new ZilForm(new ZilObject[] { ZilAtom.Parse("BAR", ctx) });

            TestHelpers.EvalAndAssert(ctx, "<EXPAND '<FOO>>", expected);
            TestHelpers.EvalAndAssert(ctx, "<EXPAND <FORM ,FOO>>", expected);

            // if the form doesn't contain a macro, it still executes
            TestHelpers.Evaluate(ctx, "<DEFINE BAR () 123>");
            TestHelpers.EvalAndAssert(ctx, "<EXPAND '<BAR>>", new ZilFix(123));
            TestHelpers.EvalAndAssert(ctx, "<EXPAND <FORM ,BAR>>", new ZilFix(123));

            // must have 1 argument
            TestHelpers.EvalAndCatch <InterpreterError>("<EXPAND>");
            TestHelpers.EvalAndCatch <InterpreterError>("<EXPAND FOO BAR>");
        }
예제 #16
0
 static ZilObject Dummy_FormArg(Context ctx, ZilForm form)
 {
     return(null);
 }
예제 #17
0
 protected Frame([NotNull] Context ctx, [NotNull] ZilForm callingForm)
 {
     Context    = ctx;
     Parent     = ctx.TopFrame;
     SourceLine = callingForm.SourceLine;
 }
예제 #18
0
 TellPattern(Token[] tokens, ZilForm outputForm)
 {
     this.tokens     = tokens;
     this.outputForm = outputForm;
 }
예제 #19
0
        internal ZilObject NewAddWord([NotNull] ZilAtom name, ZilAtom type, [CanBeNull] ZilObject value, [NotNull] ZilFix flags)
        {
            bool typeProvided;

            if (type == null)
            {
                typeProvided = false;
                type         = ctx.GetStdAtom(StdAtom.TZERO);
            }
            else
            {
                typeProvided = true;
            }

            // find new CLASS by translating TYPE
            var classification = TranslateType(ctx, type);

            // create the word or merge into the existing one
            NewParserWord word;

            if (ctx.ZEnvironment.Vocabulary.TryGetValue(name, out var iword) == false)
            {
                // create it by calling user-provided <MAKE-VWORD name class flags>
                var form = new ZilForm(new ZilObject[]
                {
                    ctx.GetStdAtom(StdAtom.MAKE_VWORD),
                    ZilString.FromString(name.Text),
                    classification,
                    flags
                });

                var vword = (ZilObject)form.Eval(ctx);

                if (vword.StdTypeAtom != StdAtom.VWORD)
                {
                    throw new InterpreterError(InterpreterMessages._0_1_Must_Return_2, "NEW-ADD-WORD", "MAKE-VWORD", "a VWORD");
                }

                word = NewParserWord.FromVword(ctx, (ZilHash)vword);
                ctx.ZEnvironment.Vocabulary.Add(name, word);
            }
            else
            {
                word = (NewParserWord)iword;

                // if old and new CLASS differ in the high bit, error (word class conflict)
                if ((word.Classification & 0x8000) != (classification.Value & 0x8000))
                {
                    throw new InterpreterError(InterpreterMessages._0_New_Classification_1_Is_Incompatible_With_Previous_2, "NEW-ADD-WORD", classification, word.Classification);
                }

                // merge new CLASS into the word
                var combinedClassification = word.Classification | classification.Value;

                if (ctx.ZEnvironment.ZVersion >= 4)
                {
                    if (typeProvided &&
                        (combinedClassification & (dirClass | verbClass)) == (dirClass | verbClass) &&
                        (word.SemanticStuff != null || word.DirId != null) &&
                        value != null)
                    {
                        throw new InterpreterError(InterpreterMessages._0_Word_Would_Be_Overloaded, "NEW-ADD-WORD");
                    }
                }

                word.Classification = combinedClassification;

                // merge new FLAGS into the word
                word.Flags |= flags.Value;
            }

            // store flags
            if (flags.Value != 0)
            {
                var compFlag = ctx.GetCompilationFlagValue("WORD-FLAGS-IN-TABLE");
                if (compFlag != null && compFlag.IsTrue)
                {
                    // prepend .WORD .FLAGS to ,WORD-FLAGS-LIST
                    var wordFlagsList = ctx.GetGlobalVal(ctx.GetStdAtom(StdAtom.WORD_FLAGS_LIST)) ?? new ZilList(null, null);

                    if (wordFlagsList is ZilList list)
                    {
                        list = new ZilList(word.Inner, new ZilList(flags, list));
                        ctx.SetGlobalVal(ctx.GetStdAtom(StdAtom.WORD_FLAGS_LIST), list);
                    }
                    else
                    {
                        throw new InterpreterError(
                                  InterpreterMessages._0_Value_Of_1_Must_Be_2,
                                  "global",
                                  "WORD-FLAGS-LIST",
                                  "a list");
                    }
                }
            }

            if (value != null)
            {
                if (classification.Value == adjClass)
                {
                    // store VALUE as word's ADJ-ID (V3) or SEMANTIC-STUFF (V4+)
                    if (ctx.ZEnvironment.ZVersion >= 4)
                    {
                        word.SemanticStuff = value;
                    }
                    else
                    {
                        word.AdjId = value;
                    }
                }
                else if (classification.Value == dirClass)
                {
                    // store VALUE as word's DIR-ID
                    word.DirId = value;
                }
                else
                {
                    // store VALUE as word's SEMANTIC-STUFF
                    word.SemanticStuff = value;
                }
            }

            return(word.Atom);
        }
예제 #20
0
        internal IOperand CompileForm([NotNull] IRoutineBuilder rb, [NotNull] ZilForm form, bool wantResult,
                                      IVariable resultStorage)
        {
            using (DiagnosticContext.Push(form.SourceLine))
            {
                var unwrapped = form.Unwrap(Context);

                if (!ReferenceEquals(unwrapped, form))
                {
                    switch (unwrapped)
                    {
                    case ZilForm newForm:
                        form = newForm;
                        break;

                    default:
                        return(wantResult ? CompileAsOperand(rb, unwrapped, form.SourceLine, resultStorage) : null);
                    }
                }

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

                // built-in statements handled by ZBuiltins
                var zversion = Context.ZEnvironment.ZVersion;
                Debug.Assert(form.Rest != null);
                var argCount = form.Rest.Count();

                if (wantResult)
                {
                    // prefer the value version, then value+predicate, predicate, void
                    if (ZBuiltins.IsBuiltinValueCall(head.Text, zversion, argCount))
                    {
                        return(ZBuiltins.CompileValueCall(head.Text, this, rb, form, resultStorage));
                    }
                    if (ZBuiltins.IsBuiltinValuePredCall(head.Text, zversion, argCount))
                    {
                        var label1 = rb.DefineLabel();
                        resultStorage = resultStorage ?? rb.Stack;
                        ZBuiltins.CompileValuePredCall(head.Text, this, rb, form, resultStorage, label1, true);
                        rb.MarkLabel(label1);
                        return(resultStorage);
                    }
                    if (ZBuiltins.IsBuiltinPredCall(head.Text, zversion, argCount))
                    {
                        var label1 = rb.DefineLabel();
                        var label2 = rb.DefineLabel();
                        resultStorage = resultStorage ?? rb.Stack;
                        ZBuiltins.CompilePredCall(head.Text, this, rb, form, label1, true);
                        rb.EmitStore(resultStorage, Game.Zero);
                        rb.Branch(label2);
                        rb.MarkLabel(label1);
                        rb.EmitStore(resultStorage, Game.One);
                        rb.MarkLabel(label2);
                        return(resultStorage);
                    }
                    if (ZBuiltins.IsBuiltinVoidCall(head.Text, zversion, argCount))
                    {
                        ZBuiltins.CompileVoidCall(head.Text, this, rb, form);
                        return(Game.One);
                    }
                }
                else
                {
                    // prefer the void version, then predicate, value, value+predicate
                    // (predicate saves a cleanup instruction)
                    if (ZBuiltins.IsBuiltinVoidCall(head.Text, zversion, argCount))
                    {
                        ZBuiltins.CompileVoidCall(head.Text, this, rb, form);
                        return(null);
                    }
                    if (ZBuiltins.IsBuiltinPredCall(head.Text, zversion, argCount))
                    {
                        var dummy = rb.DefineLabel();
                        ZBuiltins.CompilePredCall(head.Text, this, rb, form, dummy, true);
                        rb.MarkLabel(dummy);
                        return(null);
                    }
                    if (ZBuiltins.IsBuiltinValueCall(head.Text, zversion, argCount))
                    {
                        if (ZBuiltins.CompileValueCall(head.Text, this, rb, form, null) == rb.Stack)
                        {
                            rb.EmitPopStack();
                        }
                        return(null);
                    }
                    if (ZBuiltins.IsBuiltinValuePredCall(head.Text, zversion, argCount))
                    {
                        var label1 = rb.DefineLabel();
                        ZBuiltins.CompileValuePredCall(head.Text, this, rb, form, rb.Stack, label1, true);
                        rb.MarkLabel(label1);
                        rb.EmitPopStack();
                        return(null);
                    }
                }

                // routine calls
                var obj = Context.GetZVal(Context.ZEnvironment.InternGlobalName(head));

                while (obj is ZilConstant cnst)
                {
                    obj = cnst.Value;
                }

                switch (obj)
                {
                case ZilRoutine rtn:
                    // check argument count
                    var args = form.Skip(1).ToArray();
                    if (args.Length < rtn.ArgSpec.MinArgCount ||
                        rtn.ArgSpec.MaxArgCount != null && args.Length > rtn.ArgSpec.MaxArgCount)
                    {
                        Context.HandleError(CompilerError.WrongArgCount(
                                                rtn.Name?.ToString() ?? "<unnamed routine>",
                                                new ArgCountRange(rtn.ArgSpec.MinArgCount, rtn.ArgSpec.MaxArgCount)));
                        return(wantResult ? Game.Zero : null);
                    }

                    // compile routine call
                    resultStorage = wantResult ? (resultStorage ?? rb.Stack) : null;
                    using (var argOperands = CompileOperands(rb, form.SourceLine, args))
                    {
                        rb.EmitCall(Routines[head], argOperands.AsArray(), resultStorage);
                    }
                    return(resultStorage);

                case ZilFalse _:
                    // this always returns 0. we can eliminate the call if none of the arguments have side effects.
                    var argsWithSideEffects = form.Skip(1).Where(HasSideEffects).ToArray();

                    if (argsWithSideEffects.Length <= 0)
                    {
                        return(Game.Zero);
                    }

                    resultStorage = wantResult ? (resultStorage ?? rb.Stack) : null;
                    using (var argOperands = CompileOperands(rb, form.SourceLine, argsWithSideEffects))
                    {
                        var operands = argOperands.AsArray();
                        if (operands.Any(o => o == rb.Stack))
                        {
                            rb.EmitCall(Game.Zero, operands.Where(o => o == rb.Stack).ToArray(), resultStorage);
                        }
                    }
                    return(resultStorage);

                default:
                    // unrecognized
                    if (!ZBuiltins.IsNearMatchBuiltin(head.Text, zversion, argCount, out var error))
                    {
                        error = new CompilerError(CompilerMessages.Unrecognized_0_1, "routine or instruction", head);
                    }
                    Context.HandleError(error);
                    return(wantResult ? Game.Zero : null);
                }
            }
        }
예제 #21
0
            public ZilObject ToZilObject()
            {
                ZilObject result;
                StdAtom   head;

                switch (Type)
                {
                case OutputElementType.Length:
                    result = Fix ?? FALSE;
                    break;

                case OutputElementType.Many:
                    result = ZilString.FromString("MANY");
                    break;

                case OutputElementType.Adjective:
                    head = StdAtom.ADJ;
                    goto TwoElementForm;

                case OutputElementType.Byte:
                    head = StdAtom.BYTE;
                    goto TwoElementForm;

                case OutputElementType.Global:
                    head = StdAtom.GLOBAL;
                    goto TwoElementForm;

                case OutputElementType.Noun:
                    head = StdAtom.NOUN;
                    goto TwoElementForm;

                case OutputElementType.Object:
                    head = StdAtom.OBJECT;
                    goto TwoElementForm;

                case OutputElementType.Room:
                    head = StdAtom.ROOM;
                    goto TwoElementForm;

                case OutputElementType.String:
                    head = StdAtom.STRING;
                    goto TwoElementForm;

                case OutputElementType.Word:
                    head = StdAtom.WORD;

TwoElementForm:
                    result = new ZilForm(new[] {
                        GetStdAtom(head),
                        (ZilObject)Fix ?? new ZilForm(new[] {
                            GetStdAtom(StdAtom.LVAL),
                            Variable
                        })
                    });
                    break;

                case OutputElementType.Voc:
                    result = new ZilForm(new[] {
                        GetStdAtom(StdAtom.VOC),
                        (ZilObject)Fix ?? new ZilForm(new[] {
                            GetStdAtom(StdAtom.LVAL),
                            Variable
                        }),
                        PartOfSpeech
                    });
                    break;

                default:
                    throw UnhandledCaseException.FromEnum(Type);
                }

                if (Constant != null)
                {
                    result = new ZilList(new[] { Constant, result });
                }

                return(result);
            }
예제 #22
0
        /// <summary>
        /// Looks through a <see cref="ZilModelObject"/>'s property definitions, creating the
        /// property builders, flag builders, and vocab word builders that it will need.
        /// </summary>
        /// <remarks>
        /// <para>This does not create the <see cref="IObjectBuilder"/> or add any data to it.</para>
        /// <para>It does, however, call the <c>PROPSPEC</c> routines for any properties that have
        /// custom handlers installed, and replaces the corresponding property definitions with
        /// whatever the handler returned.</para>
        /// </remarks>
        /// <param name="model">The object to examine.</param>
        void PreBuildObject([NotNull] ZilModelObject model)
        {
            var globalsByName   = Context.ZEnvironment.Globals.ToDictionary(g => g.Name);
            var propertiesSoFar = new HashSet <ZilAtom>();

            var preBuilders = new ComplexPropDef.ElementPreBuilders
            {
                CreateVocabWord = (atom, partOfSpeech, src) =>
                {
                    // ReSharper disable once SwitchStatementMissingSomeCases
                    switch (partOfSpeech.StdAtom)
                    {
                    case StdAtom.ADJ:
                    case StdAtom.ADJECTIVE:
                        Context.ZEnvironment.GetVocabAdjective(atom, src);
                        break;

                    case StdAtom.NOUN:
                    case StdAtom.OBJECT:
                        Context.ZEnvironment.GetVocabNoun(atom, src);
                        break;

                    case StdAtom.BUZZ:
                        Context.ZEnvironment.GetVocabBuzzword(atom, src);
                        break;

                    case StdAtom.PREP:
                        Context.ZEnvironment.GetVocabPreposition(atom, src);
                        break;

                    case StdAtom.DIR:
                        Context.ZEnvironment.GetVocabDirection(atom, src);
                        break;

                    case StdAtom.VERB:
                        Context.ZEnvironment.GetVocabVerb(atom, src);
                        break;

                    default:
                        Context.HandleError(new CompilerError(model, CompilerMessages.Unrecognized_0_1, "part of speech", partOfSpeech));
                        break;
                    }
                },

                ReserveGlobal = atom =>
                {
                    if (globalsByName.TryGetValue(atom, out var g))
                    {
                        g.StorageType = GlobalStorageType.Hard;
                    }
                }
            };

            // for detecting implicitly defined directions
            var directionPattern = Context.GetProp(
                Context.GetStdAtom(StdAtom.DIRECTIONS), Context.GetStdAtom(StdAtom.PROPSPEC)) as ComplexPropDef;

            // create property builders for all properties on this object as needed,
            // and set up P?FOO constants for them. also create vocabulary words for
            // SYNONYM and ADJECTIVE property values, and constants for FLAGS values.
            foreach (var prop in model.Properties)
            {
                using (DiagnosticContext.Push(prop.SourceLine))
                {
                    // the first element must be an atom identifying the property
                    if (!prop.IsCons(out var first, out var propBody) || !(first is ZilAtom atom))
                    {
                        Context.HandleError(new CompilerError(model, CompilerMessages.Property_Specification_Must_Start_With_An_Atom));
                        continue;
                    }

                    ZilAtom uniquePropertyName;

                    // exclude phony built-in properties
                    bool    phony;
                    bool?   isSynonym = null;
                    Synonym synonym   = null;

                    /* We also detect direction properties here, which are tricky for a few reasons:
                     * - They can be implicitly defined by a property spec that looks sufficiently direction-like.
                     * - (IN ROOMS) is not a direction, even if IN has been explicitly defined as a direction...
                     *   but (IN "string") is!
                     * - (FOO BAR) is not enough to implicitly define FOO as a direction, even if (DIR R:ROOM)
                     *   is a pattern for directions.
                     *
                     * Thus, there are a few ways to write a property that ZILF will recognize as a direction.
                     *
                     * If the property name has already been defined as one (e.g. by <DIRECTIONS>), you can either:
                     *   - Put two or more values after the property name: (NORTH TO FOREST), (NORTH 123 456)
                     *   - Put one value after the property name that isn't an atom: (NORTH "You can't go that way.")
                     *
                     * If it hasn't been defined as a direction, you can still implicitly define it right here:
                     *   - Put two or more values after the property name, *and* match the PROPDEF for DIRECTIONS:
                     *     (STARBOARD TO BRIG), (PORT SORRY "You can't jump that far.")
                     */

                    var isKnownDirectionName = Context.ZEnvironment.Directions.Contains(atom);

                    var isDirectionProp = isKnownDirectionName
                        ? propBody.HasLengthAtLeast(2) || !(propBody.IsEmpty || propBody.First is ZilAtom)
                        : propBody.HasLengthAtLeast(2) && directionPattern?.Matches(Context, prop) == true;

                    if (isDirectionProp)
                    {
                        // it's a direction
                        phony = false;

                        // could be a new implicitly defined direction
                        if (!isKnownDirectionName)
                        {
                            synonym = Context.ZEnvironment.Synonyms.FirstOrDefault(s => s.SynonymWord.Atom == atom);

                            if (synonym == null)
                            {
                                isSynonym = false;
                                Context.ZEnvironment.Directions.Add(atom);
                                Context.ZEnvironment.GetVocabDirection(atom, prop.SourceLine);
                                Context.SetPropDef(atom, directionPattern);
                                uniquePropertyName = atom;
                            }
                            else
                            {
                                isSynonym          = true;
                                uniquePropertyName = synonym.OriginalWord.Atom;
                            }
                        }
                        else
                        {
                            uniquePropertyName = atom;
                        }
                    }
                    else
                    {
                        // ReSharper disable once SwitchStatementMissingSomeCases
                        switch (atom.StdAtom)
                        {
                        case StdAtom.DESC:
                            phony = true;
                            uniquePropertyName = PseudoPropertyAtoms.Desc;
                            break;

                        case StdAtom.IN:
                            // (IN FOO) is a location, but (IN "foo") is a property
                            if (propBody.First is ZilAtom)
                            {
                                goto case StdAtom.LOC;
                            }
                            goto default;

                        case StdAtom.LOC:
                            phony = true;
                            uniquePropertyName = PseudoPropertyAtoms.Location;
                            break;

                        case StdAtom.FLAGS:
                            phony = true;
                            // multiple FLAGS definitions are OK
                            uniquePropertyName = null;
                            break;

                        default:
                            phony = false;
                            uniquePropertyName = atom;
                            break;
                        }
                    }

                    if (uniquePropertyName != null)
                    {
                        if (propertiesSoFar.Contains(uniquePropertyName))
                        {
                            Context.HandleError(new CompilerError(
                                                    prop,
                                                    CompilerMessages.Duplicate_0_Definition_1,
                                                    phony ? "pseudo-property" : "property",
                                                    atom.ToStringContext(Context, false)));
                        }
                        else
                        {
                            propertiesSoFar.Add(uniquePropertyName);
                        }
                    }

                    if (!phony && !Properties.ContainsKey(atom))
                    {
                        if (isSynonym == null)
                        {
                            synonym   = Context.ZEnvironment.Synonyms.FirstOrDefault(s => s.SynonymWord.Atom == atom);
                            isSynonym = (synonym != null);
                        }

                        if ((bool)isSynonym)
                        {
                            var origAtom = synonym.OriginalWord.Atom;
                            if (Properties.TryGetValue(origAtom, out var origPb) == false)
                            {
                                DefineProperty(origAtom);
                                origPb = Properties[origAtom];
                            }
                            Properties.Add(atom, origPb);

                            var pAtom = ZilAtom.Parse("P?" + atom.Text, Context);
                            Constants.Add(pAtom, origPb);

                            var origSpec = Context.GetProp(origAtom, Context.GetStdAtom(StdAtom.PROPSPEC));
                            Context.PutProp(atom, Context.GetStdAtom(StdAtom.PROPSPEC), origSpec);
                        }
                        else
                        {
                            DefineProperty(atom);
                        }
                    }

                    // check for a PROPSPEC
                    var propspec = Context.GetProp(atom, Context.GetStdAtom(StdAtom.PROPSPEC));
                    if (propspec != null)
                    {
                        if (propspec is ComplexPropDef complexDef)
                        {
                            // PROPDEF pattern
                            if (complexDef.Matches(Context, prop))
                            {
                                complexDef.PreBuildProperty(Context, prop, preBuilders);
                            }
                        }
                        else
                        {
                            // name of a custom property builder function
                            var form = new ZilForm(new[] { propspec, prop })
                            {
                                SourceLine = prop.SourceLine
                            };
                            var specOutput = (ZilObject)form.Eval(Context);

                            if (specOutput is ZilListoidBase list && list.StdTypeAtom == StdAtom.LIST &&
                                list.Rest is var customBody && !customBody.IsEmpty)
                            {
                                // replace the property body with the propspec's output
                                prop.Rest = customBody;
                            }
                            else
                            {
                                Context.HandleError(new CompilerError(model,
                                                                      CompilerMessages.PROPSPEC_For_Property_0_Returned_A_Bad_Value_1, atom, specOutput));
                            }
                        }
                    }
예제 #23
0
        static OutputElement ConvertOutputForm([NotNull] ZilForm form, [CanBeNull] ZilAtom constant)
        {
            // validate and parse
            if (!form.StartsWith(out ZilAtom head))
            {
                throw new InterpreterError(
                          form,
                          InterpreterMessages.Element_0_Of_1_In_2_Must_Be_3,
                          1,
                          "FORM",
                          "PROPDEF pattern",
                          "an atom");
            }

            int length = 2;
            OutputElementType type;

            // ReSharper disable once SwitchStatementMissingSomeCases
            switch (head.StdAtom)
            {
            case StdAtom.BYTE:
                type = OutputElementType.Byte;
                break;

            case StdAtom.WORD:
                type = OutputElementType.Word;
                break;

            case StdAtom.OBJECT:
                type = OutputElementType.Object;
                break;

            case StdAtom.ROOM:
                type = OutputElementType.Room;
                break;

            case StdAtom.GLOBAL:
                type = OutputElementType.Global;
                break;

            case StdAtom.NOUN:
                type = OutputElementType.Noun;
                break;

            case StdAtom.ADJ:
            case StdAtom.ADJECTIVE:
                type = OutputElementType.Adjective;
                break;

            case StdAtom.VOC:
                type   = OutputElementType.Voc;
                length = 3;
                break;

            case StdAtom.STRING:
                type = OutputElementType.String;
                break;

            default:
                throw new InterpreterError(
                          form,
                          InterpreterMessages.FORM_In_PROPDEF_Output_Pattern_Must_Be_BYTE_WORD_STRING_OBJECT_ROOM_GLOBAL_NOUN_ADJ_Or_VOC);
            }

            if (!form.HasLength(length))
            {
                throw new InterpreterError(
                          form,
                          InterpreterMessages._0_FORM_In_PROPDEF_Output_Pattern_Must_Have_Length_1,
                          head,
                          length);
            }

            Debug.Assert(form.Rest?.Rest != null);

            ZilAtom outVariable;
            ZilFix  outFix;

            if (form.StartsWith(out ZilAtom _, out ZilObject zo) && zo.IsLVAL(out var atom))
            {
                outVariable = atom;
                outFix      = null;
            }
예제 #24
0
 public CallFrame([NotNull] Context ctx, [NotNull] ZilForm callingForm)
     : base(ctx, callingForm.SourceLine)
 {
     CallingForm = callingForm;
 }