예제 #1
0
        static StdAtom PrimTypeToType(PrimType pt)
        {
            switch (pt)
            {
            case PrimType.ATOM:
                return(StdAtom.ATOM);

            case PrimType.FIX:
                return(StdAtom.FIX);

            case PrimType.LIST:
                return(StdAtom.LIST);

            case PrimType.STRING:
                return(StdAtom.STRING);

            case PrimType.TABLE:
                return(StdAtom.TABLE);

            case PrimType.VECTOR:
                return(StdAtom.VECTOR);

            default:
                throw UnhandledCaseException.FromEnum(pt, "primtype");
            }
        }
예제 #2
0
            public ZilObject ToZilObject()
            {
                switch (Type)
                {
                case InputElementType.Atom:
                    return(Variable);

                case InputElementType.Many:
                    return(ZilString.FromString("MANY"));

                case InputElementType.Opt:
                    return(ZilString.FromString("OPT"));

                case InputElementType.Variable:
                    if (Decl != null)
                    {
                        return(new ZilAdecl(Variable, Decl));
                    }
                    else
                    {
                        return(Variable);
                    }

                default:
                    throw UnhandledCaseException.FromEnum(Type);
                }
            }
예제 #3
0
        // TODO: delete once SET-DEFSTRUCT-FILE-DEFAULTS is using ArgDecoder
        static void ParseDefStructDefaults([NotNull] Context ctx, [NotNull] ZilList fileDefaults, ref DefStructDefaults defaults)
        {
            var quoteAtom = ctx.GetStdAtom(StdAtom.QUOTE);

            foreach (var part in fileDefaults)
            {
                if (part is ZilForm partForm &&
                    partForm.First == quoteAtom &&
                    partForm.Rest.First is ZilAtom tag)
                {
                    switch (tag.StdAtom)
                    {
                    case StdAtom.NODECL:
                        defaults.SuppressDecl = true;
                        break;

                    case StdAtom.NOTYPE:
                        defaults.SuppressType = true;
                        break;

                    case StdAtom.PRINTTYPE:
                        defaults.PrintFunc = null;
                        break;

                    case StdAtom.CONSTRUCTOR:
                        defaults.SuppressDefaultCtor = true;
                        break;

                    default:
                        throw UnhandledCaseException.FromEnum(tag.StdAtom, "tag in defaults section");
                    }
                }
예제 #4
0
        void UnsetPartOfSpeech([NotNull] Context ctx, PartOfSpeech part)
        {
            var query = from pair in speechValues
                        where pair.Key != part
                        orderby pair.Key
                        select new { part = pair.Key, value = pair.Value, location = definitions[pair.Key] };
            var remainingParts = query.ToArray();

            PartOfSpeech = 0;
            speechValues.Clear();
            definitions.Clear();

            foreach (var p in remainingParts)
            {
                switch (p.part)
                {
                case PartOfSpeech.Verb:
                    SetVerb(ctx, p.location, p.value);
                    break;

                case PartOfSpeech.Adjective:
                    SetAdjective(ctx, p.location, p.value);
                    break;

                case PartOfSpeech.Direction:
                    SetDirection(ctx, p.location, p.value);
                    break;

                case PartOfSpeech.Buzzword:
                    SetBuzzword(ctx, p.location, p.value);
                    break;

                case PartOfSpeech.Preposition:
                    SetPreposition(ctx, p.location, p.value);
                    break;

                case PartOfSpeech.Object:
                    SetObject(p.location);
                    break;

                default:
                    throw UnhandledCaseException.FromEnum(p.part);
                }
            }
        }
예제 #5
0
        static ZilObject PerformTypeHandler([NotNull] Context ctx, [NotNull] ZilAtom atom, [CanBeNull] ZilObject handler,
                                            string name,
                                            Func <Context, ZilAtom, ZilObject> getter,
                                            Func <Context, ZilAtom, ZilObject, Context.SetTypeHandlerResult> setter)
        {
            if (!ctx.IsRegisteredType(atom))
            {
                throw new InterpreterError(InterpreterMessages._0_Unrecognized_1_2, name, "type", atom.ToStringContext(ctx, false));
            }

            if (handler == null)
            {
                return(getter(ctx, atom) ?? ctx.FALSE);
            }

            var result = setter(ctx, atom, handler);

            switch (result)
            {
            case Context.SetTypeHandlerResult.OK:
                return(atom);

            case Context.SetTypeHandlerResult.BadHandlerType:
                // the caller should check the handler type, but just in case...
                throw new InterpreterError(InterpreterMessages._0_Must_Be_1, "handler", "atom or applicable value");

            case Context.SetTypeHandlerResult.OtherTypeNotRegistered:
                throw new InterpreterError(InterpreterMessages._0_Unrecognized_1_2, name, "type", handler.ToStringContext(ctx, false));

            case Context.SetTypeHandlerResult.OtherTypePrimDiffers:
                throw new InterpreterError(
                          InterpreterMessages._0_Primtypes_Of_1_And_2_Differ, name, atom.ToStringContext(ctx, false), handler.ToStringContext(ctx, false));

            default:
                throw UnhandledCaseException.FromEnum(result);
            }
        }
예제 #6
0
        void BuildRoutine([NotNull] ZilRoutine routine, [NotNull] IRoutineBuilder rb, bool entryPoint, bool traceRoutines)
        {
            // give the user a chance to rewrite the routine
            routine = MaybeRewriteRoutine(Context, routine);

            // set up arguments and locals
            ClearLocalsAndBlocks();

            if (Context.TraceRoutines)
            {
                rb.EmitPrint("[" + routine.Name, false);
            }

            DefineLocalsFromArgSpec();

            if (Context.TraceRoutines)
            {
                rb.EmitPrint("]\n", false);
            }

            // define a block for the routine
            Blocks.Clear();
            Blocks.Push(new Block
            {
                Name        = routine.ActivationAtom,
                AgainLabel  = rb.RoutineStart,
                ReturnLabel = null,
                Flags       = BlockFlags.None
            });

            // generate code for routine body
            int i = 1;

            foreach (var stmt in routine.Body)
            {
                // only want the result of the last statement
                // and we never want results in the entry routine, since it can't return
                CompileStmt(rb, stmt, !entryPoint && i == routine.BodyLength);
                i++;
            }

            // the entry point has to quit instead of returning
            if (entryPoint)
            {
                rb.EmitQuit();
            }

            // clean up
            WarnAboutUnusedLocals();
            ClearLocalsAndBlocks();

            // helpers
            void DefineLocalsFromArgSpec()
            {
                foreach (var arg in routine.ArgSpec)
                {
                    var originalArgName = arg.Atom;
                    var uniqueArgName   = MakeUniqueVariableName(originalArgName);

                    if (uniqueArgName != originalArgName)
                    {
                        /* When a parameter has to be renamed because of a conflict, use TempLocalNames
                         * to reserve the new name so we don't collide with it later. For example:
                         *
                         *   <GLOBAL FOO <>>
                         *   <ROUTINE BLAH (FOO)
                         *     <PROG ((FOO)) ...>>
                         *
                         * We rename the local variable to FOO?1 to avoid shadowing the global.
                         * Now the temporary variable bound by the PROG has to be FOO?2.
                         * ZIL code only sees the name FOO: the local is shadowed inside the PROG,
                         * and the global can always be accessed with SETG and GVAL.
                         */
                        TempLocalNames.Add(uniqueArgName);
                    }

                    var lb = MakeLocalBuilder(arg, uniqueArgName.Text);

                    if (traceRoutines && arg.Type == ArgItem.ArgType.Required)
                    {
                        // TODO: print OPT parameters when tracing routine execution too
                        rb.EmitPrint(" " + originalArgName + "=", false);
                        rb.EmitPrint(PrintOp.Number, lb);
                    }

                    var lbr = new LocalBindingRecord(arg.Type.ToLocalBindingType(), routine.SourceLine, originalArgName.Text, lb);
                    Locals.Add(originalArgName, lbr);
                    AllLocalBindingRecords.Add(lbr);

                    SetOrEmitDefaultValue(lb, arg);
                }
            }

            ILocalBuilder MakeLocalBuilder(ArgItem arg, string uniqueArgName)
            {
                ILocalBuilder lb;

                switch (arg.Type)
                {
                case ArgItem.ArgType.Required:
                    try
                    {
                        lb = rb.DefineRequiredParameter(uniqueArgName);
                    }
                    catch (InvalidOperationException)
                    {
                        throw new CompilerError(
                                  CompilerMessages.Expression_Needs_Temporary_Variables_Not_Allowed_Here);
                    }
                    break;

                case ArgItem.ArgType.Optional:
                    lb = rb.DefineOptionalParameter(uniqueArgName);
                    break;

                case ArgItem.ArgType.Auxiliary:
                    lb = rb.DefineLocal(uniqueArgName);
                    break;

                default:
                    throw UnhandledCaseException.FromEnum(arg.Type);
                }

                return(lb);
            }

            void SetOrEmitDefaultValue(ILocalBuilder lb, ArgItem arg)
            {
                if (arg.DefaultValue == null)
                {
                    return;
                }

                Debug.Assert(arg.Type == ArgItem.ArgType.Optional || arg.Type == ArgItem.ArgType.Auxiliary);

                // setting any default value counts as a write
                MarkVariableAsWritten(lb);

                lb.DefaultValue = CompileConstant(arg.DefaultValue);
                if (lb.DefaultValue != null)
                {
                    return;
                }

                ILabel nextLabel = null;

                // ReSharper disable once SwitchStatementMissingSomeCases
                switch (arg.Type)
                {
                case ArgItem.ArgType.Optional when !rb.HasArgCount:
                    // not a constant
                    throw new CompilerError(routine.SourceLine,
                                            CompilerMessages.Optional_Args_With_Nonconstant_Defaults_Not_Supported_For_This_Target);

                case ArgItem.ArgType.Optional:
                    nextLabel = rb.DefineLabel();
                    rb.Branch(Condition.ArgProvided, lb, null, nextLabel, true);
                    goto default;

                default:
                    var val = CompileAsOperand(rb, arg.DefaultValue, routine.SourceLine, lb);
                    if (val != lb)
                    {
                        rb.EmitStore(lb, val);
                    }
                    break;
                }

                if (nextLabel != null)
                {
                    rb.MarkLabel(nextLabel);
                }
            }

            void WarnAboutUnusedLocals()
            {
                foreach (var lbr in AllLocalBindingRecords)
                {
                    if (lbr.IsEverRead || lbr.IsEverWritten)
                    {
                        continue;
                    }

                    if (lbr.Type == LocalBindingType.CompilerTemporary)
                    {
                        continue;
                    }

                    //XXX not sure about this
                    if (lbr.Type == LocalBindingType.RoutineRequired)
                    {
                        continue;
                    }

                    var warning = new CompilerError(
                        lbr.Definition,
                        CompilerMessages.Local_Variable_0_Is_Never_Used,
                        lbr.BoundName);

                    Context.HandleError(warning);
                }
            }
        }
예제 #7
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");
            }
        }
예제 #8
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);
            }
예제 #9
0
        static DefStructField ParseDefStructField(DefStructDefaults defaults, ref int offset, DefStructParams.FieldSpecList fieldSpec)
        {
            var result = new DefStructField
            {
                Decl    = fieldSpec.Decl,
                Name    = fieldSpec.Name,
                NthFunc = defaults.NthFunc,
                Offset  = offset,
                PutFunc = defaults.PutFunc
            };

            bool gotDefault = false, gotOffset = false;

            foreach (var part in fieldSpec.Parts)
            {
                switch (part)
                {
                case DefStructParams.AtomFieldSequence af:
                    switch (af.ClauseType)
                    {
                    case StdAtom.NTH:
                        result.NthFunc = af.Atom;
                        break;

                    case StdAtom.PUT:
                        result.PutFunc = af.Atom;
                        break;

                    default:
                        throw UnhandledCaseException.FromEnum(af.ClauseType, "atom clause type");
                    }
                    break;

                case DefStructParams.FixFieldSequence ff:
                    switch (ff.ClauseType)
                    {
                    case StdAtom.OFFSET:
                        result.Offset = ff.Fix;
                        gotOffset     = true;
                        break;

                    default:
                        throw UnhandledCaseException.FromEnum(ff.ClauseType, "FIX clause type");
                    }
                    break;

                case DefStructParams.NullaryFieldSequence nf:
                    switch (nf.ClauseType)
                    {
                    case StdAtom.NONE:
                        if (gotDefault)
                        {
                            throw new InterpreterError(InterpreterMessages._0_NONE_Is_Not_Allowed_After_A_Default_Field_Value, "DEFSTRUCT");
                        }
                        result.NoDefault = true;
                        gotDefault       = true;
                        break;

                    default:
                        throw UnhandledCaseException.FromEnum(nf.ClauseType, "nullary clause type");
                    }
                    break;

                case ZilObject zo when !gotDefault:
                    result.Default = zo;
                    gotDefault     = true;
                    break;

                default:
                    throw new InterpreterError(InterpreterMessages._0_Unrecognized_1_2, "DEFSTRUCT", "object in field definition", part);
                }
            }

            if (!gotOffset)
            {
                offset++;
            }

            return(result);
        }
예제 #10
0
        static ZilObject MakeDefstructCustomCtorMacro([NotNull] Context ctx, ZilAtom ctorName, [NotNull] ZilAtom typeName, [NotNull] ZilAtom baseType,
                                                      [NotNull] List <DefStructField> fields, [NotNull] ZilList initArgs, int startOffset, [NotNull] ArgSpec argspec)
        {
            // {0} = constructor name
            // {1} = type name
            // {2} = argspec
            // {3} = field count
            // {4} = base constructor atom
            // {5} = list of INIT-ARGS, or empty list
            // {6} = list of PUT statements for fields
            const string SMacroTemplate = @"
<DEFMAC {0} {2}
    <BIND ((RESULT-INIT <IVECTOR {3} <>>))
        {6:SPLICE}
        <FORM CHTYPE <FORM {4} {5:SPLICE} !.RESULT-INIT> {1}>>>";

            var remainingFields = fields.ToDictionary(f => f.Name);

            var resultInitializers = new List <ZilObject>();

            foreach (var arg in argspec)
            {
                // NOTE: we don't handle NoDefault ('NONE) here because this ctor allocates a new object

                // {0} = offset
                // {1} = arg name
                // {2} = default value
                const string SRequiredArgInitializer = "<PUT .RESULT-INIT {0} .{1}>";
                const string SOptAuxArgInitializer   = "<PUT .RESULT-INIT {0} <COND (<ASSIGNED? {1}> .{1}) (T {2})>>";

                if (remainingFields.TryGetValue(arg.Atom, out var field))
                {
                    remainingFields.Remove(arg.Atom);
                }
                else
                {
                    continue;
                }

                // generate code
                switch (arg.Type)
                {
                case ArgItem.ArgType.Required:
                    resultInitializers.Add(Program.Parse(
                                               ctx,
                                               SRequiredArgInitializer,
                                               new ZilFix(field.Offset - startOffset + 1),
                                               arg.Atom,
                                               field.Default ?? DefaultForDecl(ctx, field.Decl))
                                           .Single());
                    break;

                case ArgItem.ArgType.Optional:
                case ArgItem.ArgType.Auxiliary:
                    resultInitializers.Add(Program.Parse(
                                               ctx,
                                               SOptAuxArgInitializer,
                                               new ZilFix(field.Offset - startOffset + 1),
                                               arg.Atom,
                                               field.Default ?? DefaultForDecl(ctx, field.Decl))
                                           .Single());
                    break;

                default:
                    throw UnhandledCaseException.FromEnum(arg.Type);
                }
            }

            foreach (var field in remainingFields.Values)
            {
                if (field.Default == null)
                {
                    continue;
                }

                // {0} = offset
                // {1} = default value
                const string SOmittedFieldInitializer = "<PUT .RESULT-INIT {0} {1}>";
                resultInitializers.Add(Program.Parse(
                                           ctx,
                                           SOmittedFieldInitializer,
                                           new ZilFix(field.Offset - startOffset + 1),
                                           field.Default)
                                       .Single());
            }

            return(Program.Parse(
                       ctx,
                       SMacroTemplate,
                       ctorName,
                       typeName,
                       argspec.ToZilList(),
                       new ZilFix(fields.Count),
                       baseType,
                       initArgs,
                       new ZilList(resultInitializers))
                   .Single());
        }