github-code-scanning[bot] commented on code in PR #1833: URL: https://github.com/apache/avro/pull/1833#discussion_r950941158
########## lang/csharp/src/apache/main/IO/Parsing/ValidatingGrammarGenerator.cs: ########## @@ -0,0 +1,159 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using System.Collections.Generic; + +namespace Avro.IO.Parsing +{ + /// <summary> + /// The class that generates validating grammar. + /// </summary> + public class ValidatingGrammarGenerator + { + /// <summary> + /// Returns the non-terminal that is the start symbol for the grammar for the + /// given schema <tt>sc</tt>. + /// </summary> + public virtual Symbol Generate(Schema schema) + { + return Symbol.NewRoot(Generate(schema, new Dictionary<LitS, Symbol>())); + } + + /// <summary> + /// Returns the non-terminal that is the start symbol for the grammar for the + /// given schema <tt>sc</tt>. If there is already an entry for the given schema + /// in the given map <tt>seen</tt> then that entry is returned. Otherwise a new + /// symbol is generated and an entry is inserted into the map. + /// </summary> + /// <param name="sc"> The schema for which the start symbol is required </param> + /// <param name="seen"> A map of schema to symbol mapping done so far. </param> + /// <returns> The start symbol for the schema </returns> + protected virtual Symbol Generate(Schema sc, IDictionary<LitS, Symbol> seen) + { + switch (sc.Tag) + { + case Schema.Type.Null: + return Symbol.Null; + case Schema.Type.Boolean: + return Symbol.Boolean; + case Schema.Type.Int: + return Symbol.Int; + case Schema.Type.Long: + return Symbol.Long; + case Schema.Type.Float: + return Symbol.Float; + case Schema.Type.Double: + return Symbol.Double; + case Schema.Type.String: + return Symbol.String; + case Schema.Type.Bytes: + return Symbol.Bytes; + case Schema.Type.Fixed: + return Symbol.NewSeq(new Symbol.IntCheckAction(((FixedSchema)sc).Size), Symbol.Fixed); + case Schema.Type.Enumeration: + return Symbol.NewSeq(new Symbol.IntCheckAction(((EnumSchema)sc).Symbols.Count), Symbol.Enum); + case Schema.Type.Array: + return Symbol.NewSeq( + Symbol.NewRepeat(Symbol.ArrayEnd, Generate(((ArraySchema)sc).ItemSchema, seen)), + Symbol.ArrayStart); + case Schema.Type.Map: + return Symbol.NewSeq( + Symbol.NewRepeat(Symbol.MapEnd, Generate(((MapSchema)sc).ValueSchema, seen), Symbol.String), + Symbol.MapStart); + case Schema.Type.Record: + { + LitS wsc = new LitS(sc); + Symbol rresult = seen.ContainsKey(wsc) ? seen[wsc] : null; + if (rresult == null) + { + Symbol[] production = new Symbol[((RecordSchema)sc).Fields.Count]; + + // We construct a symbol without filling the array. Please see + // <seealso cref="Symbol.production"/> for the reason. + rresult = Symbol.NewSeq(production); + seen[wsc] = rresult; + + int j = production.Length; + foreach (Field f in ((RecordSchema)sc).Fields) + { + production[--j] = Generate(f.Schema, seen); + } + } + + return rresult; + } + case Schema.Type.Union: + IList<Schema> subs = ((UnionSchema)sc).Schemas; + Symbol[] symbols = new Symbol[subs.Count]; + string[] labels = new string[subs.Count]; + + int i = 0; + foreach (Schema b in ((UnionSchema)sc).Schemas) + { + symbols[i] = Generate(b, seen); + labels[i] = b.Fullname; + i++; + } + + return Symbol.NewSeq(Symbol.NewAlt(symbols, labels), Symbol.Union); + + default: + throw new Exception("Unexpected schema type"); + } + } + + /// <summary> + /// A wrapper around Schema that does "==" equality. + /// </summary> + protected class LitS + { + private readonly Schema actual; + + /// <summary> + /// Initializes a new instance of the <see cref="LitS"/> class. + /// </summary> + public LitS(Schema actual) + { + this.actual = actual; + } + + /// <summary> + /// Two LitS are equal if and only if their underlying schema is the same (not + /// merely equal). + /// </summary> + public override bool Equals(object o) + { + if (!(o is LitS)) Review Comment: ## Equals should not apply "is" LitS.Equals(object) should not use "is" on its parameter, as it will not work properly for subclasses of LitS. [Show more details](https://github.com/apache/avro/security/code-scanning/2904) ########## lang/csharp/src/apache/main/IO/Parsing/Symbol.cs: ########## @@ -0,0 +1,1044 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; + +namespace Avro.IO.Parsing +{ + /// <summary> + /// Symbol is the base of all symbols (terminals and non-terminals) of the + /// grammar. + /// </summary> + public abstract class Symbol + { + /// <summary> + /// The type of symbol. + /// </summary> + public enum Kind + { + /// <summary> + /// terminal symbols which have no productions </summary> + Terminal, + + /// <summary> + /// Start symbol for some grammar </summary> + Root, + + /// <summary> + /// non-terminal symbol which is a sequence of one or more other symbols </summary> + Sequence, + + /// <summary> + /// non-terminal to represent the contents of an array or map </summary> + Repeater, + + /// <summary> + /// non-terminal to represent the union </summary> + Alternative, + + /// <summary> + /// non-terminal action symbol which are automatically consumed </summary> + ImplicitAction, + + /// <summary> + /// non-terminal action symbol which is explicitly consumed </summary> + ExplicitAction + } + + /// The kind of this symbol. + public readonly Kind SymKind; + + /// <summary> + /// The production for this symbol. If this symbol is a terminal this is + /// <tt>null</tt>. Otherwise this holds the the sequence of the symbols that + /// forms the production for this symbol. The sequence is in the reverse order of + /// production. This is useful for easy copying onto parsing stack. + /// + /// Please note that this is a final. So the production for a symbol should be + /// known before that symbol is constructed. This requirement cannot be met for + /// those symbols which are recursive (e.g. a record that holds union a branch of + /// which is the record itself). To resolve this problem, we initialize the + /// symbol with an array of nulls. Later we fill the symbols. Not clean, but + /// works. The other option is to not have this field a final. But keeping it + /// final and thus keeping symbol immutable gives some comfort. See various + /// generators how we generate records. + /// </summary> + public readonly Symbol[] Production; + + /// <summary> + /// Constructs a new symbol of the given kind. + /// </summary> + protected Symbol(Kind kind) : this(kind, null) + { + } + + /// <summary> + /// Constructs a new symbol of the given kind and production. + /// </summary> + protected Symbol(Kind kind, Symbol[] production) + { + this.Production = production; + this.SymKind = kind; + } + + /// <summary> + /// A convenience method to construct a root symbol. + /// </summary> + public static Symbol NewRoot(params Symbol[] symbols) + { + return new Root(symbols); + } + + /// <summary> + /// A convenience method to construct a sequence. + /// </summary> + /// <param name="production"> The constituent symbols of the sequence. </param> + public static Symbol NewSeq(params Symbol[] production) + { + return new Sequence(production); + } + + /// <summary> + /// A convenience method to construct a repeater. + /// </summary> + /// <param name="endSymbol"> The end symbol. </param> + /// <param name="symsToRepeat"> The symbols to repeat in the repeater. </param> + public static Symbol NewRepeat(Symbol endSymbol, params Symbol[] symsToRepeat) + { + return new Repeater(endSymbol, symsToRepeat); + } + + /// <summary> + /// A convenience method to construct a union. + /// </summary> + public static Symbol NewAlt(Symbol[] symbols, string[] labels) + { + return new Alternative(symbols, labels); + } + + /// <summary> + /// A convenience method to construct an ErrorAction. + /// </summary> + /// <param name="e"> </param> + protected static Symbol Error(string e) + { + return new ErrorAction(e); + } + + /// <summary> + /// A convenience method to construct a ResolvingAction. + /// </summary> + /// <param name="w"> The writer symbol </param> + /// <param name="r"> The reader symbol </param> + protected static Symbol Resolve(Symbol w, Symbol r) + { + return new ResolvingAction(w, r); + } + + /// <summary> + /// Fixup symbol. + /// </summary> + protected class Fixup + { + /// <summary> + /// The symbols. + /// </summary> + public readonly Symbol[] Symbols; + /// <summary> + /// The position. + /// </summary> + public readonly int Pos; + + /// <summary> + /// Initializes a new instance of the <see cref="Fixup"/> class. + /// </summary> + public Fixup(Symbol[] symbols, int pos) Review Comment: ## Exposing internal representation 'Fixup' exposes the internal representation stored in field 'Symbols'. The value may be modified [through the variable out](1). 'Fixup' exposes the internal representation stored in field 'Symbols'. The value may be modified [through the variable out](2). 'Fixup' exposes the internal representation stored in field 'Symbols'. The value may be modified [through the variable out](3). 'Fixup' exposes the internal representation stored in field 'Symbols'. The value may be modified [through the variable out](4). [Show more details](https://github.com/apache/avro/security/code-scanning/2903) -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
