/// <exception cref="CompilerError">Malformed WORD-FLAGS-LIST.</exception> public void BuildLateSyntaxTables(BuildLateSyntaxTablesHelpers helpers) { var actionsTable = (ITableBuilder)helpers.CompileConstant(ctx.GetStdAtom(StdAtom.ATBL)); var preactionsTable = (ITableBuilder)helpers.CompileConstant(ctx.GetStdAtom(StdAtom.PATBL)); helpers.GetGlobal(ctx.GetStdAtom(StdAtom.ACTIONS)).DefaultValue = actionsTable; helpers.GetGlobal(ctx.GetStdAtom(StdAtom.PREACTIONS)).DefaultValue = preactionsTable; // word flag table if (ctx.GetCompilationFlagOption(StdAtom.WORD_FLAGS_IN_TABLE)) { var wordFlagsListObj = ctx.GetGlobalVal(ctx.GetStdAtom(StdAtom.WORD_FLAGS_LIST)) ?? new ZilList(null, null); if (!(wordFlagsListObj is ZilListoidBase wordFlagsList && wordFlagsList is ZilList)) { throw new CompilerError(CompilerMessages.GVAL_Of_0_Must_Be_1, "WORD-FLAGS-LIST", "a list"); } var wordFlagTable = (ITableBuilder)helpers.CompileConstant(ctx.GetStdAtom(StdAtom.WORD_FLAG_TABLE)); Debug.Assert(wordFlagTable != null); // WORD-FLAGS-LIST may contain duplicates: (W?FOO 96 W?BAR 1 W?FOO 32) // only the first appearance of each word will be kept var seen = new HashSet <ZilObject>(); var filtered = new List <IOperand>(); while (!wordFlagsList.IsEmpty) { if (!wordFlagsList.StartsWith(out ZilObject vword, out ZilObject flags)) { throw new CompilerError(CompilerMessages.WORDFLAGSLIST_Must_Have_An_Even_Number_Of_Elements); } if (!seen.Add(vword)) { continue; } var nw = NewParserWord.FromVword(ctx, (ZilHash)vword); var atom = nw.Atom; var word = ctx.ZEnvironment.Vocabulary[atom]; var zword = helpers.Vocabulary[word]; filtered.Add(zword); filtered.Add(helpers.CompileConstant(flags)); wordFlagsList = wordFlagsList.GetRest(2); Debug.Assert(wordFlagsList != null); } wordFlagTable.AddShort((short)filtered.Count); foreach (var operand in filtered) { wordFlagTable.AddShort(operand); } } }
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); }
public void WriteToBuilder(IWord word, IWordBuilder wb, WriteToBuilderHelpers helpers) { var zversion = ctx.ZEnvironment.ZVersion; var nw = (NewParserWord)word; bool needSemanticStuff = false; if (zversion >= 4) { if (nw.HasClass(dirClass)) { ConditionalAddByte(wb, word.Atom.Text, helpers.CompileConstant, nw.DirId); wb.AddByte(0); } else if (!nw.HasClass(verbClass)) { ConditionalAddShort(wb, word.Atom.Text, helpers.CompileConstant, nw.SemanticStuff); } else { needSemanticStuff = true; } } else { bool adj = nw.HasClass(adjClass), dir = nw.HasClass(dirClass); if (adj || dir) { if (adj) { ConditionalAddByte(wb, word.Atom.Text, helpers.CompileConstant, nw.AdjId); } else { wb.AddByte(0); } if (dir) { ConditionalAddByte(wb, word.Atom.Text, helpers.CompileConstant, nw.DirId); } else { wb.AddByte(0); } } else { ConditionalAddShort(wb, word.Atom.Text, helpers.CompileConstant, nw.SemanticStuff); } } bool verbed = false; if (nw.HasClass(verbClass)) { var verbStuff = nw.VerbStuff; ZilObject verbStuffId; if ((IsVerbPointer(verbStuff) && (verbStuffId = verbStuff.GetPrimitive(ctx)) != null) || TryGetVerbStuffId(verbStuff, out verbStuffId)) { if (verbStuffId.StdTypeAtom == StdAtom.VWORD) { verbStuffId = NewParserWord.FromVword(ctx, (ZilHash)verbStuffId).Atom; } var actTableAtom = ZilAtom.Parse("ACT?" + ((ZilAtom)verbStuffId).Text, ctx); var actConstant = helpers.CompileConstant(actTableAtom); Debug.Assert(actConstant != null); wb.AddShort(actConstant); verbed = true; } } if (!verbed) { if (zversion == 3) { wb.AddShort(0); } else if (needSemanticStuff) { ConditionalAddShort(wb, word.Atom.Text, helpers.CompileConstant, nw.SemanticStuff); } } if (!ctx.GetCompilationFlagOption(StdAtom.WORD_FLAGS_IN_TABLE)) { wb.AddShort((short)nw.Flags); } if (ctx.GetCompilationFlagOption(StdAtom.ONE_BYTE_PARTS_OF_SPEECH)) { var lowByte = (byte)(nw.Classification & 0x7f); var highByte = (byte)((nw.Classification >> 7) & 0x7f); if (lowByte != 0 && highByte != 0) { ctx.HandleError(new CompilerError(CompilerMessages.ONEBYTEPARTSOFSPEECH_Loses_Data_For_0, word.Atom.Text)); } if (highByte != 0) { wb.AddByte((byte)(highByte | 0x80)); } else { wb.AddByte(lowByte); } } else { wb.AddShort((short)nw.Classification); } }