// 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); }
// Compile a scoped expression that returns a typed value DataTypes CompileExpr(PredefScopes predef, NodeListParser nlp) { Logger.WriteLine(2, "CompileExpr {0} <{1}>", predef, nlp); Symbols.PushPredefScope(predef); var codetype = Symbols.PredefScopeDict[predef].CodeType; _gen.EmitEntry(codetype); nlp.Expect(nlp.IsCallable, "callable function"); var sexpr = nlp.GetSexprNode(); nlp.Expect(sexpr.DataType != DataTypes.Void, "typed function"); CompileSexpr(sexpr, nlp); Symbols.PopPredefScope(); _gen.EmitExit(true); return(sexpr.DataType); }
// 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"); } } }
//-------------------------------------------------------------------------- // 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 a function with given arguments void CompileBuiltin(BuiltinSymbol funcsym, NodeListParser nlp) { Logger.WriteLine(3, "CompileBuiltin {0} <{1}>", funcsym.Name, nlp); var ci = funcsym.CallInfo; for (int i = 0; i < ci.Arguments.Count; i++) { if (ci.ArgOptional[i] && nlp.Done) { _gen.EmitLoadValue(null); } else if (ci.Arguments[i] == typeof(AttributeValue)) { _gen.EmitLoadValue(DefAttribute(nlp.GetIdent())); // special for attribute } // TODO: could possibly check for combo of boolean expected and undefined ident, and emit false else { CompileArg(ci.Arguments[i], nlp); } } nlp.Expect(nlp.Done, "no more arguments for {0}", funcsym.Name); _gen.EmitCall(funcsym); }
// 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); } }