// 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"); } } }
// these functions serve to ensure that symbols in nodes are defined as the right type protected TypedValue DefSymbolValue(IdentNode node, TypedValue value) { if (node.Sym.IsValue && node.Sym.DataType == value.DataType) { return(node.Sym.Value); } Logger.WriteLine(3, "Getsym adding {0} value:{1} type:{2}", node.Sym.Name, value, value.DataType); // will create new symbol and store in symbol table, so other nodes see the same thing if (node.Sym.IsUndef) { Symbols.DefineValue(node.Name, value); } else if (value.GetType() == typeof(IdentValue) && node.Sym.Value is IdentValue) { ; // any subclass will do for flag. TODO: reverse operation if flag defined first } else { _currentparser.Syntax("already defined {0} as type {1}", node.Name, node.Sym.DataType); } return(value); }
// 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); } }