예제 #1
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>");
        }
예제 #2
0
        public static ZilResult ISTRING(Context ctx, int count, [CanBeNull] ZilObject init = null)
        {
            if (count < 0)
            {
                throw new InterpreterError(
                          InterpreterMessages._0_Expected_1,
                          "ISTRING: arg 1",
                          "a non-negative FIX");
            }

            var contents = new List <char>(count);

            for (int i = 0; i < count; i++)
            {
                if (init != null)
                {
                    var initResult = init.Eval(ctx);
                    if (initResult.ShouldPass())
                    {
                        return(initResult);
                    }

                    if (!((ZilObject)initResult is ZilChar ch))
                    {
                        throw new InterpreterError(InterpreterMessages._0_Iterated_Values_Must_Be_CHARACTERs, "ISTRING");
                    }
                    contents.Add(ch.Char);
                }
                else
                {
                    contents.Add('\0');
                }
            }

            return(ZilString.FromString(new string(contents.ToArray())));
        }
예제 #3
0
        static string TranslateString([NotNull] ZilString zstr, [NotNull] Context ctx, char crlfChar, StringSpacesMode spacesMode)
        {
            // strip CR/LF and ensure 1 space afterward, translate crlfChar to LF,
            // and collapse two spaces after '.' or crlfChar into one
            var  sb          = new StringBuilder(zstr.Text);
            char?last        = null;
            bool sawDotSpace = false;

            var zversion = ctx.ZEnvironment.ZVersion;

            string DescribeChar(byte zscii)
            {
                switch (zscii)
                {
                case 8:
                    return("backspace");

                case 9:
                    return("tab");

                case 11:
                    return("sentence space");

                case 27:
                    return("escape");

                case var _ when zscii < 32:
                    return("^" + (char)(zscii + 64));

                case var _ when zscii < 127:
                    return("'" + (char)zscii + "'");

                default:
                    return(null);
                }
            }

            for (int i = 0; i < sb.Length; i++)
            {
                char c = sb[i];
                byte b = UnicodeTranslation.ToZscii(c);

                if (!StringEncoder.IsPrintable(b, zversion))
                {
                    var warning = new CompilerError(zstr,
                                                    CompilerMessages.ZSCII_0_1_Cannot_Be_Safely_Printed_In_Zmachine_Version_2,
                                                    b,
                                                    DescribeChar(b),
                                                    zversion);

                    ctx.HandleError(warning);
                }

                switch (spacesMode)
                {
                case StringSpacesMode.CollapseAfterPeriod:
                    if ((last == '.' || last == crlfChar) && c == ' ')
                    {
                        sawDotSpace = true;
                    }
                    else if (sawDotSpace && c == ' ')
                    {
                        sb.Remove(i--, 1);
                        sawDotSpace = false;
                        last        = c;
                        continue;
                    }
                    else
                    {
                        sawDotSpace = false;
                    }
                    break;

                case StringSpacesMode.CollapseWithSentenceSpace:
                    if ((last == '.' || last == '?' || last == '!') && c == ' ')
                    {
                        sawDotSpace = true;
                    }
                    else if (sawDotSpace && c == ' ')
                    {
                        sb.Remove(i--, 1);
                        sb[i]       = SentenceSpaceChar;
                        sawDotSpace = false;
                        last        = c;
                        continue;
                    }
                    else
                    {
                        sawDotSpace = false;
                    }
                    break;
                }

                switch (c)
                {
                case '\r':
                    sb.Remove(i--, 1);
                    continue;

                case '\n':
                    if (last == crlfChar)
                    {
                        sb.Remove(i--, 1);
                    }
                    else
                    {
                        sb[i] = ' ';
                    }
                    break;

                default:
                    if (c == crlfChar)
                    {
                        sb[i] = '\n';
                    }
                    break;
                }

                last = c;
            }

            return(sb.ToString());
        }
예제 #4
0
 public void ISTRING_Should_Evaluate_Initializer_Each_Time()
 {
     TestHelpers.EvalAndAssert("<SET X 64> <ISTRING 3 '<ASCII <SET X <+ .X 1>>>>",
                               ZilString.FromString("ABC"));
 }
예제 #5
0
 public void REST_Of_One_Character_String_Should_Be_Empty_String()
 {
     TestHelpers.EvalAndAssert("<REST \"x\">", ZilString.FromString(""));
     TestHelpers.EvalAndAssert("<REST <REST \"xx\">>", ZilString.FromString(""));
 }
예제 #6
0
        public void TestUNPARSE()
        {
            TestHelpers.EvalAndAssert("<UNPARSE 123>", ZilString.FromString("123"));

            TestHelpers.EvalAndAssert("<UNPARSE '(\"FOO\" [BAR])>", ZilString.FromString("(\"FOO\" [BAR])"));
        }
예제 #7
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);
        }
예제 #8
0
        public void TUPLE_Is_Included_In_ZilListBody()
        {
            var ctx = new Context();

            var spec = ArgSpec.Parse("test", ZilAtom.Parse("FOO", ctx), null, new ZilObject[] { ZilString.FromString("TUPLE"), ZilAtom.Parse("A", ctx) });

            TestHelpers.AssertStructurallyEqual(
                new ZilObject[]
            {
                ZilString.FromString("TUPLE"),
                ZilAtom.Parse("A", ctx)
            },
                spec.AsZilListBody().ToArray());
        }
예제 #9
0
        public static ZilObject UNPARSE([NotNull] Context ctx, [NotNull] ZilObject arg)
        {
            // in MDL, this takes an optional second argument (radix), but we don't bother

            return(ZilString.FromString(arg.ToStringContext(ctx, false)));
        }
예제 #10
0
 public static ZilObject SPNAME(Context ctx, [NotNull] ZilAtom atom)
 {
     return(ZilString.FromString(atom.Text));
 }
예제 #11
0
        public static ZilObject SUBSTRUC(Context ctx, [NotNull] IStructure from, int rest = 0, int?amount = null,
                                         [CanBeNull] IStructure dest = null)
        {
            if (amount != null)
            {
                var max = from.GetLength(rest + (int)amount);
                if (max != null && max.Value - rest < amount)
                {
                    throw new InterpreterError(
                              InterpreterMessages._0_1_Element1s_Requested_But_Only_2_Available,
                              "SUBSTRUC",
                              amount,
                              max.Value - rest);
                }
            }
            else
            {
                amount = from.GetLength() - rest;
            }

            if (amount < 0)
            {
                throw new InterpreterError(InterpreterMessages._0_Negative_Element_Count, "SUBSTRUC");
            }

            var fromObj   = (ZilObject)from;
            var destObj   = (ZilObject)dest;
            var primitive = (IStructure)fromObj.GetPrimitive(ctx);

            if (destObj != null)
            {
                // modify an existing structure
                if (destObj.PrimType != fromObj.PrimType)
                {
                    throw new InterpreterError(InterpreterMessages._0_Destination_Must_Have_Same_Primtype_As_Source, "SUBSTRUC");
                }

                int i;

                switch (dest)
                {
                case ZilListoidBase list:
                    foreach (var item in primitive.Skip(rest).Take((int)amount))
                    {
                        if (list.IsEmpty)
                        {
                            throw new InterpreterError(InterpreterMessages._0_Destination_Too_Short, "SUBSTRUC");
                        }

                        Debug.Assert(list.Rest != null);

                        list.First = item;
                        list       = list.Rest;
                    }
                    break;

                case ZilString str:
                    // this is crazy inefficient, but works with ZilString and OffsetString
                    // TODO: method on ZilString to do this more efficiently?
                    for (i = 0; i < amount; i++)
                    {
                        str[i] = primitive[i + rest];
                    }
                    break;

                case ZilVector vector:
                    i = 0;
                    foreach (var item in primitive.Skip(rest).Take((int)amount))
                    {
                        if (i >= vector.GetLength())
                        {
                            throw new InterpreterError(InterpreterMessages._0_Destination_Too_Short, "SUBSTRUC");
                        }

                        vector[i++] = item;
                    }
                    break;

                default:
                    throw new InterpreterError(InterpreterMessages._0_Destination_Type_Not_Supported_1, "SUBSTRUC", destObj.GetTypeAtom(ctx));
                }

                return(destObj);
            }

            // no destination, return a new structure
            switch (fromObj.PrimType)
            {
            case PrimType.LIST:
                return(new ZilList(primitive.Skip(rest).Take((int)amount)));

            case PrimType.STRING:
                return(ZilString.FromString(((ZilString)primitive).Text.Substring(rest, (int)amount)));

            case PrimType.TABLE:
                throw new InterpreterError(InterpreterMessages._0_Primtype_TABLE_Not_Supported, "SUBSTRUC");

            case PrimType.VECTOR:
                return(new ZilVector(((ZilVector)primitive).Skip(rest).Take((int)amount).ToArray()));

            default:
                throw UnhandledCaseException.FromEnum(fromObj.PrimType, "structured primtype");
            }
        }
예제 #12
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);
            }