// Create piece index from array of section nodes // Note: Also does sanity check (first peek inside game/variant definition) // The passed in parser is used to generate meaningful errors Dictionary <string, Node> CreatePieceLookup(NodeListParser nlp) { Dictionary <string, Node> lookup = new Dictionary <string, Node>(); while (!nlp.Done) { var pnode = nlp.Current; // could be a piece section var nlp2 = nlp.GetParser(); // note: cannot use anything that relies on CheckedIdent nlp.Expect(nlp2.IsIdent, "section identifier"); if (nlp2.GetNode().AsIdent.Name == "piece") { while (true) { nlp2.Expect(nlp2.IsList, "piece name"); var nlp3 = nlp2.GetParser(); if (nlp3.IsIdent && nlp3.GetNode().AsIdent.Name == "name") { if (nlp3.IsIdent) { lookup[nlp3.GetNode().AsIdent.Name] = pnode; break; } } } } } return(lookup); }
//: ( BOARD-SETUP ( player placement+ )+ )? //: placement := (piece-type { off <int> | position }+ ) IList <PlacementDef> ParsePlacements(NodeListParser nlp) { Logger.WriteLine(4, "ParsePlacements <{0}>", nlp); var list = new List <PlacementDef>(); while (!nlp.Done) { list.Add(ParsePlacement(nlp.GetParser())); } return(list); }
// Compile a literal, symbol or expression that returns a typed value // Return datatype to caller for type checking DataTypes CompileValue(Type type, NodeListParser nlp) { Logger.WriteLine(4, "CompileValue {0} <{1}>", type, nlp); // bracketed expression with arguments if (nlp.IsSexpr) { var sexpr = nlp.GetSexprNode(); CompileSexpr(sexpr, nlp); return(sexpr.DataType); } if (nlp.IsFunc) { // bare function no arguments var sym = nlp.GetIdent().Sym as BuiltinSymbol; CompileBuiltin(sym, NodeListParser.Null); return(sym.DataType); } if (nlp.IsVariable) { var sym = nlp.GetIdent().Sym; _gen.EmitLoadVar(sym); return(sym.DataType); } if (nlp.IsAttribute || (nlp.IsList && nlp.CheckedHead.IsAttribute)) { var handler = Symbols.Find("--attribute") as BuiltinSymbol; if (handler != null) { CompileBuiltin(handler, nlp.GetParser()); } else { nlp.Syntax("attribute not allowed here"); } return(handler.DataType); } var func = _typeactiondict.SafeLookup(type); if (func != null) { // direct lookup to get constant value var value = func(type, nlp, this) as TypedValue; _gen.EmitLoadValue(value); return(value.DataType); } nlp.Unexpected("unknown type {0}", type); return(DataTypes.Unknown); }
// compile a prog block inside an existing scope internal void CompileProg(NodeListParser nlp) { Logger.WriteLine(2, "CompileProg <{0}>", nlp); // iterate over the action items in the prog block while (!nlp.Done) { // value -- special handler if (nlp.IsValue || nlp.IsValueCallable) { if (!CompileHandler("--value", nlp)) { nlp.Syntax("bare value not allowed"); } // callable function, call it } else if (nlp.IsCallable) { if (nlp.IsFunc && nlp.CurrentIdent.Sym.Keyword == Keywords.ELSE) { return; // sneaky! } var sexpr = nlp.GetSexprNode(); nlp.Expect(sexpr.DataType == DataTypes.Void, "void function"); CompileSexpr(sexpr, nlp); // list -- special handler } else if (nlp.IsList) { var handler = Symbols.Find("--list") as BuiltinSymbol; if (handler != null) { CompileBuiltin(handler, nlp.GetParser()); } else { nlp.Unexpected("unknown function"); } } else { nlp.Expected("function call"); } } }
OccupierDef ParseOccupier(NodeListParser nlp) { //NOTE: this change allows dropping parens, but breaks order dependence //if (nlp.IsIdent && (nlp.CurrentIdent.IsPiece || nlp.CurrentIdent.IsDirection)) { // take ident; define as piece if not direction if (nlp.IsIdent) { var ident = nlp.GetIdent(); if (ident.IsDirection) // only used by relative-config { return(OccupierDef.Create(ident.AsValue as DirectionValue)); } else { return(OccupierDef.Create(PlayerKinds.Friend, DefPiece(ident))); } } // note: relies on dummy functions defined in scope if (nlp.IsList && nlp.IsCallable) { var nlp2 = nlp.GetParser(); var ident = nlp2.GetIdent(); if (ident.Sym.Name == "not") { return(ParseOccupier(nlp2).SetNot()); } else { var piece = DefPiece(nlp2.GetIdent()); nlp2.CheckDone(); if (ident.Sym.Name == "opponent") { return(OccupierDef.Create(PlayerKinds.Enemy, piece)); } if (ident.Sym.Name == "any-owner") { return(OccupierDef.Create(PlayerKinds.Any, piece)); } } } return(null); }
//-------------------------------------------------------------------------- // Parsers for individual productions that return a data structure //: (TURN-ORDER { player | ( player move-type ) | ( player player ) | ( player player move-type ) | REPEAT }+ )? TurnDef ParseTurnDef(NodeListParser nlparg) { Logger.WriteLine(4, "ParseTurnDef <{0}>", nlparg); nlparg.Expect(nlparg.IsIdent || nlparg.IsList, "player or list"); var nlp = nlparg.GetParser(); var ident = nlp.GetIdent(); if (ident.Name == "repeat") { nlp.CheckDone(); return(TurnDef.Repeat); } var player = DefPlayer(ident); // default is to play as self var playeras = nlp.IsIdent && nlp.Current.IsPlayer ? DefPlayer(nlp.GetIdent()) : player; var movetype = nlp.IsIdent ? DefMoveType(nlp.GetIdent()) : MoveTypeValue.Any; nlp.CheckDone(); return(new TurnDef { TurnPlayer = player, MovePlayer = playeras, MoveType = movetype }); }
// Compile an argument of given type void CompileArg(Type type, NodeListParser nlp) { Logger.WriteLine(4, "CompileArg {0} <{1}>", type, nlp); var func = _typeactiondict.SafeLookup(type); // special for variable assignment and implicit definition if (type == typeof(Variable)) { var ident = nlp.GetIdent(); var datatype = DataTypes.Bool; // TODO: handle other types if (ident.Sym.IsVariable) { nlp.Expect(ident.Sym.DataType == datatype, "variable of type {0}", datatype); } else if (ident.Sym.IsUndef) { Symbols.DefineVariable(ident.Name, datatype, BoolValue.False); } else { nlp.Expected("defined variable"); } _gen.EmitRefVar(ident.Sym); // handle these separately, could be variable or function } else if (type.IsSubclassOf(typeof(TypedValue))) { // TODO: type checking CompileValue(type, nlp); //var exptype = TypedValue.DataTypeDict.SafeLookup(type); //var rettype = CompileValue(type, nlp); //nlp.Expect(rettype == exptype, "value of type {0}", exptype); // direct lookup gets special cases; else continue } else if (func != null) { var value = func(type, nlp, this); _gen.EmitLoadValue(value); // Array means parse a list of this type } else if (type.IsArray) { var nargs = 0; for (var nlp2 = nlp.GetParser(); !nlp2.Done; nargs++) { CompileArg(type.GetElementType(), nlp2); } _gen.EmitToArray(type, nargs); // List<> means parse a tail of this type } else if (type.IsGenericType && type.Name.StartsWith("List")) { var nargs = 0; for (; !nlp.Done; ++nargs) { CompileArg(type.GetGenericArguments()[0], nlp); } _gen.EmitToList(type, nargs); // Pair<> means parse a pair of arbitrary types } else if (type.IsGenericType && type.Name.StartsWith("Pair")) { var nlp2 = nlp.GetParser(); foreach (var subtype in type.GetGenericArguments()) { CompileArg(subtype, nlp2); } _gen.EmitToPair(type); // nested prog block } else if (type.IsSubclassOf(typeof(CodeBase))) { var info = Symbols.PredefScopeDict.First(kv => kv.Value.CodeType == type).Value; CompileProg(info, nlp); } else if (type == typeof(PositionOrDirection)) { CompilePositionOrDirection(nlp); // function call on built in } else if (nlp.IsSexpr) { var sexpr = nlp.GetSexprNode(); var datatype = TypedValue.DataTypeDict.SafeLookup(type); nlp.Expect(sexpr.DataType == datatype, "value of type {0}", datatype); CompileBuiltin(sexpr.Sym as BuiltinSymbol, NodeListParser.Create(sexpr.Args, Symbols)); } else { nlp.Syntax("unknown type {0}", type); } }
Maybe <PositionOrZone> ParseMaybePositionOrZone(NodeListParser nlp) { if (nlp.IsConstant) { var value = nlp.Current.AsValue; if (value is PositionValue || value is ZoneValue) { return new Maybe <PositionOrZone> { Value = ParsePositionOrZone(nlp) } } ; } return(new Maybe <PositionOrZone> { }); } // parse a term which may be a position, direction or opposite void CompilePositionOrDirection(NodeListParser nlp) { var rettype = CompileValue(typeof(TypedValue), nlp); nlp.Expect(rettype == DataTypes.Position || rettype == DataTypes.Direction, "position or direction"); var funcsym = Symbols.Find("--pos-or-dir"); _gen.EmitCall(funcsym as BuiltinSymbol); } //protected PositionOrDirection ParsePositionOrDirection(NodeListParser nlp) { // if (nlp.IsValue) { // var value = nlp.GetValue(); // if (value is PositionValue || value is DirectionValue) // return new PositionOrDirection { Value = value }; // } // nlp.Expected("position or direction"); // return null; //} GoKinds ParseGoKind(NodeListParser nlp) { var ident = nlp.GetIdent(); var gosym = Symbols.Find(ident.Name, PredefKinds.GO); nlp.Expect(gosym != null, "valid go target"); return(gosym.GoKind); } Maybe <PlayerValue[]> ParseMaybePlayers(NodeListParser nlp) { if (!(nlp.IsList && nlp.CheckedHead.IsPlayer)) { return(Maybe <PlayerValue[]> .Null); } return(Maybe <PlayerValue[]> .Create(nlp.GetParser().UntilDone(n => DefPlayer(n.GetIdent())).ToArray())); } Maybe <PieceValue> ParseMaybePiece(NodeListParser nlp) { return((nlp.IsIdent && nlp.Current.IsPiece) ? Maybe <PieceValue> .Create(DefPiece(nlp.GetIdent())) : Maybe <PieceValue> .Null); } Maybe <PlayerValue> ParseMaybePlayer(NodeListParser nlp) { return((nlp.IsIdent && nlp.Current.IsPlayer) ? Maybe <PlayerValue> .Create(DefPlayer(nlp.GetIdent())) : Maybe <PlayerValue> .Null); } }