public virtual bool CanStoreValue(ExecContext context, ITypeDef valueType) { //if (valueType is TypeDef) { // return null == (valueType as TypeDef).IsNull(); //} if (valueType.IsNull()) { return(true); } TypeDef_Function funcValueType = valueType as TypeDef_Function; if (null == funcValueType) { return(false); } if (!retType.Equals(IntrinsicTypeDefs.VOID) && !retType.CanStoreValue(context, funcValueType.retType)) { return(false); } if (null != classType) { if (null == funcValueType.classType || !classType.CanStoreValue(context, funcValueType.classType)) { return(false); } // This is the point of isStatic in this class. This is saying, "I can save a reference to a class member function only if it is static." } else if (null != funcValueType.classType && !funcValueType.isStaticMember) { return(false); } // Mismatch if other's max args exceeds our max args. if (argTypes.Count > funcValueType.argTypes.Count) { return(false); } // Mismatch if we have fewer min args than they do. // (Meaning we could be called with fewer arguments than they have default values for.) if (minArgs < funcValueType.minArgs) { return(false); } // Make sure that for every argument WE have, THEIR argument's type matches. for (int ii = 0; ii < argTypes.Count; ++ii) { if (!funcValueType.argTypes[ii].CanStoreValue(context, argTypes[ii])) { return(false); } } return(true); }
public override object GetDefaultValue(ExecContext context) { string name = GetName(); ClassDef classDef = context.GetClass(name); ClassDef_Enum enumDef = classDef as ClassDef_Enum; return(enumDef.enumDef.GetDefaultValue()); }
public override bool CanStoreValue(ExecContext context, ITypeDef valueType) { if (valueType is TypeDef_Enum) { return(((TypeDef_Enum)valueType).className == className); } return(false); }
public static string StandardPrintFunction(ExecContext context, List <object> args) { string result = ""; foreach (object val in args) { result += CoreLib.ValueToString(context, val, false); } return(result); }
// ******************************************************************** // Checks stack, class, and global. public bool IsSymbolAvailable(ExecContext context, string symbol, bool ignoreGlobals = false) { if (context.DoesTypeExist(symbol)) { return(false); } VarStackRef index = GetVarIndexByName(null, symbol, true); return(!index.isValid || (ignoreGlobals && index.isGlobal)); }
public static PebbleList AllocateListString(ExecContext context, string debugName = "(List<string> inst)") { if (null == _listClassDef) { _listClassDef = context.GetClass("List<string>"); } PebbleList listinst = (PebbleList)_listClassDef.childAllocator(); listinst.classDef = _listClassDef; listinst.debugName = debugName; return(listinst); }
// List<Child> could be written to a binary file, but then List<Parent> read. // If there is no variable with type List<Parent> in the reading script, it // wouldn't be in the type registry. // This function insures it's in the registry by parsing a little script which // creates a temp variable of the desired type. // It's pretty inefficient to do this, but parsing type names can be very, very // tricky. It wouldn't necessarily be a *better* solution to try to replicate // the parser's code. protected bool EnsureGenericIsRegistered(ExecContext context, string name) { if (null != context.GetClass(name)) { return(true); } List <ParseErrorInst> errors = new List <ParseErrorInst>(); // I don't think there is a way to use a variable name that is *guaranteed* not to already exist, sadly. IExpr expr = context.engine.Parse("{ " + name + " otehunstoeunthnsjthntxheui; }", ref errors, false); return(null != expr && 0 == errors.Count); }
//public override bool Equals(object obj) { // throw new InvalidProgramException("INTERNAL ERROR: Attempt to use type before it has been evaluated. (Equals)"); //} public override ITypeDef Resolve(ExecContext context, ref bool error) { if (name == "void") { return(IntrinsicTypeDefs.VOID); } ITypeDef def = context.GetTypeByName(name); if (null == def) { context.engine.LogCompileError(ParseErrorType.TypeNotFound, "Type '" + name + "' not found."); error = true; return(null); } if (null == _templateTypes) { if (_isConst && !def.IsConst()) { return(def.Clone(true)); } return(def); } // If we have template types, then we must be a TypeDef_Class. List <ITypeDef> genericTypes = new List <ITypeDef>(); for (int ii = 0; ii < _templateTypes.Count; ++ii) { genericTypes.Add(_templateTypes[ii].Resolve(context, ref error)); } if (error) { return(null); } //TypeDef_Class result = new TypeDef_Class(name, genericTypes, _isConst); TypeDef_Class result = TypeFactory.GetTypeDef_Class(name, genericTypes, _isConst); if (null == context.RegisterIfUnregisteredTemplate(result)) { error = true; } return(result); }
// Call this after creating the class and adding members to it. public bool FinalizeClass(ExecContext context) { Pb.Assert(0 == context.control.flags); // Only initializing the members that this class has added is a cool idea, but // leaves us f****d when it comes to overrridden functions. // So, I'm being lazy here and initializing them all. for (int ii = 0; ii < _memberFuncs.Count; ++ii) { ClassMember member = _memberFuncs.Get(ii); if (null != member.initializer && (member.initializer is Expr_Literal || member.initializer is Expr_Value)) { // Make sure vftableVars has a slot for this function. while (vftableVars.Count < ii + 1) { vftableVars.Add(null); } object initValue = member.initializer.Evaluate(context); if (context.IsRuntimeErrorSet()) { return(false); } // Create the variable for the function. vftableVars[ii] = new Variable(member.name, member.typeDef, initValue); } } // Initialize the static members. Populates the staticVars list. for (int ii = 0; ii < _statics.Count; ++ii) { ClassMember member = _statics.Get(ii); object initValue = null; if (null != member.initializer) { initValue = member.initializer.Evaluate(context); if (context.IsRuntimeErrorSet()) { context.engine.LogCompileError(ParseErrorType.StaticMemberEvaluationError, name + "::" + member.name + " - " + context.GetRuntimeErrorString()); return(false); } } staticVars[ii] = new Variable(member.name, member.typeDef, initValue); } return(true); }
public object EvaluateValues(ExecContext context) { bool isNum = valueType.CanStoreValue(context, IntrinsicTypeDefs.NUMBER); double nextInteger = 0; bool isString = valueType.CanStoreValue(context, IntrinsicTypeDefs.STRING); for (int ii = 0; ii < _values.Count; ++ii) { ClassValue_Enum val = (ClassValue_Enum)_classDef.Allocate(context); val.Get(mrName).value = _values[ii].name; _classDef.staticVars[ii].value = val; if (null == _values[ii].initializer) { if (isNum) { // If number, use next consecutive integer. val.Get(mrValue).value = nextInteger; nextInteger = Math.Floor(nextInteger + 1); } else if (isString) { // If string, just use name. val.Get(mrValue).value = _values[ii].name; } else { // Use the default value. val.Get(mrValue).value = valueType.GetDefaultValue(context); } } else { object init = _values[ii].initializer.Evaluate(context); if (context.IsRuntimeErrorSet()) { return(null); } val.Get(mrValue).value = init; if (isNum) { nextInteger = Math.Floor((double)init + 1); } } } return(false); }
public bool PushClassScope(ClassValue instance, ExecContext context, string msg = "") { if (CALLSTACKMAXDEPTH == _callCount) { return(false); } _callStack[_callCount].Set(_varCount, instance, true); ++_callCount; #if PEBBLE_TRACESTACK TraceScope("PushClassScope"); #endif return(true); }
public virtual object GetDefaultValue(ExecContext context) { string name = GetName(); ClassDef parent = context.GetClass(name); ClassValue result = parent.Allocate(context); if (null == result) { return(null); } result.debugName = parent.name + " Inst"; //result.typeDef = this; return(result); }
public bool Comparable(ExecContext context, ITypeDef other) { if (!(other is TypeDef_Class)) { return(false); } if (Equals(other)) { return(true); } TypeDef_Class otherClassType = other as TypeDef_Class; return(null != context.DetermineAncestor(this, otherClassType)); }
// This pushes a non-terminal scope ("block") onto the stack. // Use for "if", "for", and exrpession lists. public bool PushBlock(string name, ExecContext context) { if (CALLSTACKMAXDEPTH == _callCount) { return(false); } _callStack[_callCount].Set(_varCount, name); ++_callCount; #if PEBBLE_TRACESTACK TraceScope("PushBlock " + name); #endif return(true); }
public bool AddValue_Default(ExecContext context, string valueName) { if (_names.ContainsKey(valueName)) { return(false); } _names.Add(valueName, true); _classDef.AddMember(valueName, enumType, null, true); EnumValue ev = new EnumValue(); ev.name = valueName; _values.Add(ev); return(true); }
public virtual string ToString(ExecContext context) { Variable var = GetByName("ThisToString"); if (null != var && var.type is TypeDef_Function) { TypeDef_Function tdf = (TypeDef_Function)var.type; if (null != var.value && tdf.retType.Equals(IntrinsicTypeDefs.STRING) && tdf.argTypes.Count == 0) { FunctionValue funcVal = (FunctionValue)var.value; return((string)funcVal.Evaluate(context, new List <object>(), this)); } } return("[" + classDef.name + " instance]"); }
public bool PushDefstructorScope(ClassValue instance, ExecContext context) { Pb.Assert(_callCount < CALLSTACKMAXDEPTH); if (CALLSTACKMAXDEPTH == _callCount) { return(false); } #if PEBBLE_TRACESTACK TraceLog("PushDefstructorScope " + instance.classDef.name + " '" + instance.debugName + "'"); #endif _callStack[_callCount].Set(_varCount, instance, false); ++_callCount; return(true); }
public virtual bool CanStoreValue(ExecContext context, ITypeDef valueType) { if (valueType is TypeDef && null == ((TypeDef)valueType).GetHostType()) { return(true); } TypeDef_Class classValueType = valueType as TypeDef_Class; if (null == classValueType) { return(false); } if (!context.IsChildClass(context.GetClass(className), context.GetClass(classValueType.className))) { return(false); } // If neither has generic types, we match. if (null == classValueType._genericTypes && null == _genericTypes) { return(true); } // If only one has generic types, we do not. if (null == classValueType._genericTypes || null == _genericTypes) { return(false); } // If they don't have the same number, we do not. if (classValueType._genericTypes.Count != _genericTypes.Count) { return(false); } for (int ii = 0; ii < _genericTypes.Count; ++ii) { if (_genericTypes[ii] != classValueType._genericTypes[ii]) { return(false); } } return(true); }
public bool OpenFileRead(ExecContext context, string path) { if (IsOpen()) { lastError = "Stream already open."; return(false); } try { reader = new BinaryReader(File.Open(path, FileMode.Open)); } catch (Exception e) { lastError = "Runtime error attempting to create BinaryReader: " + e.ToString(); return(false); } return(true); }
public EnumValue AddValue_Literal(ExecContext context, string valueName, object litValue) { if (_names.ContainsKey(valueName)) { return(null); } _names.Add(valueName, true); _classDef.AddMember(valueName, enumType, null, true); EnumValue ev = new EnumValue(); ev.name = valueName; ev.literalValue = litValue; _values.Add(ev); return(ev); }
// *************************************************************************** // Variable functions. // Note - These are nearly-trivial wrappers for stack functions. // These could be removed at some point. // *************************************************************************** public VarStackRef GetVarRefByName(ExecContext context, string symbol, bool globalOnly = false) { VarStackRef index; if (globalOnly) { index = stack.GetGlobalVarIndexByName(symbol); } else { index = stack.GetVarIndexByName(context, symbol); } #if PEBBLE_TRACESTACK Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine(symbol + " -> " + index.ToString()); Console.ForegroundColor = ConsoleColor.Gray; #endif return(index); }
public PebbleEnum(ExecContext context, string _enumName, ITypeDef valueTypeIn) { enumName = _enumName; valueType = valueTypeIn; // Apparently need to register non-const first. ITypeDef nonConstEnumType = TypeFactory.GetTypeDef_Enum(_enumName, false); enumType = (TypeDef_Enum)TypeFactory.GetConstVersion(nonConstEnumType); _classDef = new ClassDef_Enum(this, _enumName, enumType); context.RegisterClass(_classDef); _classDef.childAllocator = () => { return(new ClassValue_Enum()); }; _classDef.Initialize(); //don't think this is needed _classDef.AddMemberLiteral("enumName", IntrinsicTypeDefs.CONST_STRING, _enumName, false); _classDef.AddMember("name", IntrinsicTypeDefs.CONST_STRING); _classDef.AddMember("value", valueType.Clone(true), null, false, true); { FunctionValue_Host.EvaluateDelegate eval = (_context, args, thisScope) => { ClassValue cv = thisScope as ClassValue; return(enumName + "::" + cv.Get(mrName).value); }; FunctionValue newValue = new FunctionValue_Host(IntrinsicTypeDefs.STRING, new ArgList { }, eval, false, _classDef.typeDef); _classDef.AddMemberLiteral("ThisToString", newValue.valType, newValue, false); } _classDef.FinalizeClass(context); if (mrName.isInvalid) { mrName = _classDef.GetMemberRef(null, "name", ClassDef.SEARCH.NORMAL); mrValue = _classDef.GetMemberRef(null, "value", ClassDef.SEARCH.NORMAL); } }
public bool PushTerminalScope(string name, ExecContext context, bool hard = false) { if (CALLSTACKMAXDEPTH == _callCount) { return(false); } if (hard) { _callStack[_callCount].SetHardTerminal(_varCount, name); } else { _callStack[_callCount].SetTerminal(_varCount, name); } ++_callCount; #if PEBBLE_TRACESTACK TraceScope("PushTerminalScope" + (hard ? "(hard)" : "")); #endif return(true); }
public static string ValueToString(ExecContext context, object val, bool quoteStrings) { string result = ""; if (null == val) { result += "null"; } else if (val is bool) { result += (bool)val ? "true" : "false"; } else if (val is string) { result += quoteStrings ? "\"" + (string)val + "\"" : (string)val; } else if (val is double) { result += val.ToString(); } else if (val is ClassValue) { if (null != context) { result += ((ClassValue)val).ToString(context); // this searches the class for a ToString member } else { result += ((ClassValue)val).debugName; } } else { result += val.ToString(); } return(result); }
public bool OpenFileWrite(ExecContext context, string path, bool textMode) { if (IsOpen()) { lastError = "Stream already open."; return(false); } try { if (textMode) { textWriter = new StreamWriter(path); } else { writer = new BinaryWriter(File.Open(path, FileMode.Create)); } } catch (Exception e) { lastError = "Runtime error attempting to create BinaryWriter: " + e.ToString(); return(false); } return(true); }
public static string ValueToScript(ExecContext context, object value, string prefix = "", bool topLevel = true) { string result = ""; string postfix = topLevel ? ";" : ""; if (value is double) { return(Convert.ToString((double)value) + postfix); } else if (value is bool) { return(((bool)value ? "true" : "false") + postfix); } else if (value is string) { return("\"" + (string)value + "\"" + postfix); } else if (value is ClassValue_Enum) // is enum { return(((ClassValue_Enum)value).ToString() + postfix); } else if (value is ClassValue) { ClassValue table = value as ClassValue; result = "new " + table.classDef.typeDef.ToString() + " {\n"; // ThisToScript must not be static. It's going to be printing info about a class instance, right? MemberRef toStrMem = table.classDef.GetMemberRef(null, "ThisToScript", ClassDef.SEARCH.NORMAL); Variable funcVar = null; if (!toStrMem.isInvalid) { funcVar = table.Get(toStrMem) as Variable; } if (null != funcVar) { FunctionValue funcVal = funcVar.value as FunctionValue; result += funcVal.Evaluate(context, new List <object> { prefix }, table) as string; } else { foreach (Variable kvp in table.fieldVars) { if (!(kvp.type is TypeDef_Function) && !kvp.type.IsConst()) { result += prefix + "\t" + kvp.name + " = " + ValueToScript(context, kvp.value, prefix + "\t", false); if (!result.EndsWith(";")) { result += ";"; } result += "\n"; } } } result += prefix + "}" + postfix; } else if (null == value) { result = "null" + postfix; } return(result); }
/* * delegate bool LibraryTestFunc(Engine engine, bool verbose); * * public static void RegisterLibraryTests(LibraryTestFunc testFunc) { * testFunc(); * } */ // ************************************************************************** public Engine() { defaultContext = new ExecContext(this); CoreLib.Register(this); }
// BIG IMPORTANT FUNCTION. // Searches the current call stack for a variable with the given name and returns a VarStackRef, // which can be used by GetVarAtIndex to find the variable, usually later at execution time. // This saves us from having to do string searches for variables at execution time, but also // adds a lot of complexity to the system. Since the idea is to create these Refs during // TypeCheck, any discrepancy between the order scopes are pushed/popped and variables created // between TypeCheck and Evaluate WILL result in a grave error. public VarStackRef GetVarIndexByName(ExecContext context, string name, bool stopAtTerminals = false) { bool onlyUnique = false; int callIx = _callCount; int varIx = _varCount - 1; while (--callIx >= 0) { StackScope scope = _callStack[callIx]; if (!onlyUnique && null != scope.classInstance) { // If this scope is a class function call, search that class for // a member with that name. ITypeDef typeDef = null; MemberRef memRef = _callStack[callIx].classInstance.classDef.GetMemberRef(context, name, scope.isStatic ? ClassDef.SEARCH.STATIC : ClassDef.SEARCH.EITHER, ref typeDef); if (!memRef.isInvalid) { return(new VarStackRef(typeDef, callIx - _callCount, memRef)); } } if (!onlyUnique && null != scope.classDef) { ITypeDef typeDef = null; MemberRef memRef = _callStack[callIx].classDef.GetMemberRef(context, name, scope.isStatic ? ClassDef.SEARCH.STATIC : ClassDef.SEARCH.EITHER, ref typeDef); if (!memRef.isInvalid) { return(new VarStackRef(typeDef, callIx - _callCount, memRef)); } } // Otherwise, search the variable stack for it. while (varIx >= scope.varStackStart) { if (null != _varStack[varIx] && _varStack[varIx].name == name) { Variable var = _varStack[varIx]; if (var.unique) { return(new VarStackRef(var, false)); } else if (!onlyUnique) { return(new VarStackRef(_varStack[varIx].type, callIx - _callCount, varIx - scope.varStackStart)); } else { return(new VarStackRef(VarStackRef.ErrorType.NonUnique)); } } --varIx; } if (scope.hardTerminal) { break; } if (scope.terminal) { if (stopAtTerminals) { break; } else { onlyUnique = true; } } } // Search globals last. Globals are always in scope. int globIx = _globals.GetIndex(name); if (globIx >= 0) { Variable var = _globals.Get(globIx); return(new VarStackRef(var, true)); } return(new VarStackRef(VarStackRef.ErrorType.NotFound)); }
public bool PushClassCall_StaticOrTypeCheck(TypeDef_Function funcType, ClassDef classDef, bool isStatic, ExecContext context) { if (CALLSTACKMAXDEPTH == _callCount) { return(false); } _callStack[_callCount].Set(_varCount, funcType, classDef, isStatic); ++_callCount; #if PEBBLE_TRACESTACK TraceScope("PushClassCall_StaticOrTypeCheck(" + classDef.name + ", " + (isStatic ? "static)" : "type check)")); #endif return(true); }
public bool PushCall(TypeDef_Function funcType, string funcName, ClassValue instance, bool isStatic, ExecContext context) { if (CALLSTACKMAXDEPTH == _callCount) { return(false); } _callStack[_callCount].Set(_varCount, funcName, funcType, instance, isStatic); ++_callCount; #if PEBBLE_TRACESTACK TraceScope("PushCall"); #endif return(true); }