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"); } }
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); } }
// 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"); } }
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); } } }
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); } }
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); } } }
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"); } }
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); }
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); }
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()); }