internal static Prototype TranslatePrototype(ScriptProcessor processor, Type t) { var name = t.Name; var customNameAttribute = t.GetCustomAttribute <ScriptPrototypeAttribute>(); if (!string.IsNullOrWhiteSpace(customNameAttribute?.VariableName)) { name = customNameAttribute.VariableName; } var prototype = new Prototype(name); object typeInstance = null; if (!t.IsAbstract) { typeInstance = Activator.CreateInstance(t); } var fields = t .GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static) .Where(f => f.GetCustomAttribute <CompilerGeneratedAttribute>() == null) .ToArray(); foreach (var field in fields) { var attributes = field.GetCustomAttributes(false); foreach (var attr in attributes) { if (attr.GetType() == typeof(ScriptVariableAttribute)) { var memberAttr = (ScriptMemberAttribute)attr; var identifier = field.Name; if (!string.IsNullOrEmpty(memberAttr.VariableName)) { identifier = memberAttr.VariableName; } var fieldContent = field.GetValue(typeInstance); if (fieldContent == null) { prototype.AddMember(processor, new PrototypeMember(identifier, processor.Undefined, field.IsStatic, field.IsInitOnly, false, false)); } else { prototype.AddMember(processor, new PrototypeMember(identifier, Translate(processor, fieldContent), field.IsStatic, field.IsInitOnly, false, false)); } } else if (attr.GetType() == typeof(ScriptFunctionAttribute)) { var memberAttr = (ScriptFunctionAttribute)attr; var identifier = field.Name; if (!string.IsNullOrEmpty(memberAttr.VariableName)) { identifier = memberAttr.VariableName; } var fieldContent = field.GetValue(typeInstance); if (fieldContent == null) { if (memberAttr.FunctionType != ScriptFunctionType.Standard) { throw new InvalidOperationException("A member function marked with Indexer Set, Indexer Get or Constructor has to be defined."); } prototype.AddMember(processor, new PrototypeMember(identifier, processor.Undefined, field.IsStatic, field.IsInitOnly, false, false)); } else { switch (memberAttr.FunctionType) { case ScriptFunctionType.Standard: prototype.AddMember(processor, new PrototypeMember(identifier, new SFunction(processor, fieldContent.ToString()), field.IsStatic, field.IsInitOnly, false, false)); break; case ScriptFunctionType.IndexerGet: prototype.IndexerGetFunction = new SFunction(processor, fieldContent.ToString()); break; case ScriptFunctionType.IndexerSet: prototype.IndexerSetFunction = new SFunction(processor, fieldContent.ToString()); break; case ScriptFunctionType.Constructor: prototype.Constructor = new PrototypeMember(Prototype.CLASS_METHOD_CTOR, new SFunction(processor, fieldContent.ToString()), false, true, false, false); break; } } } } } var methods = t .GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static) .Where(f => f.GetCustomAttribute <CompilerGeneratedAttribute>() == null) .ToArray(); foreach (var method in methods) { var attr = method.GetCustomAttribute <ScriptFunctionAttribute>(false); if (attr != null) { var identifier = method.Name; if (!string.IsNullOrEmpty(attr.VariableName)) { identifier = attr.VariableName; } if (attr.FunctionType == ScriptFunctionType.Getter) { identifier = SProtoObject.PROPERTY_GET_PREFIX + identifier; } if (attr.FunctionType == ScriptFunctionType.Setter) { identifier = SProtoObject.PROPERTY_SET_PREFIX + identifier; } Delegate methodDelegate = null; if (method.GetParameters().Length == 3) { // two parameter means the method is a DotNetBuiltInMethod. methodDelegate = (DotNetBuiltInMethod)Delegate.CreateDelegate(typeof(DotNetBuiltInMethod), method); } else if (method.GetParameters().Length == 4) { // four parameters means that the method is a valid BuiltInMethod. methodDelegate = (BuiltInMethod)Delegate.CreateDelegate(typeof(BuiltInMethod), method); } switch (attr.FunctionType) { case ScriptFunctionType.Standard: case ScriptFunctionType.Getter: case ScriptFunctionType.Setter: prototype.AddMember(processor, new PrototypeMember(identifier, new SFunction(methodDelegate), attr.IsStatic, true, false, false)); break; case ScriptFunctionType.IndexerGet: prototype.IndexerGetFunction = new SFunction(methodDelegate); break; case ScriptFunctionType.IndexerSet: prototype.IndexerSetFunction = new SFunction(methodDelegate); break; case ScriptFunctionType.Constructor: prototype.Constructor = new PrototypeMember(Prototype.CLASS_METHOD_CTOR, new SFunction(methodDelegate), false, true, false, false); break; } } } prototype.MappedType = t; return(prototype); }
/// <summary> /// Parses an anonymous object. /// </summary> internal static SProtoObject Parse(ScriptProcessor processor, string source) { var prototype = new Prototype(LITERAL_OBJECT); source = source.Trim(); // Format: { member1 : content1, member2 : content2 } // Remove "{" and "}": source = source.Remove(source.Length - 1, 1).Remove(0, 1).Trim(); if (source.Length == 0) { return(prototype.CreateInstance(processor, null, false)); } var index = 0; var identifier = ""; var content = ""; SObject contentObj = null; while (index < source.Length) { var nextSeperatorIndex = source.IndexOf(",", index); if (nextSeperatorIndex == -1) { nextSeperatorIndex = source.Length; } else { //Let's find the correct ",": nextSeperatorIndex = index; var depth = 0; StringEscapeHelper escaper = new LeftToRightStringEscapeHelper(source, nextSeperatorIndex, true); var foundSeperator = false; while (!foundSeperator && nextSeperatorIndex < source.Length) { var t = source[nextSeperatorIndex]; escaper.CheckStartAt(nextSeperatorIndex); if (!escaper.IsString) { if (t == '{' || t == '[' || t == '(') { depth++; } else if (t == '}' || t == ']' || t == ')') { depth--; } else if (t == ',' && depth == 0) { foundSeperator = true; nextSeperatorIndex--; // it adds one to the index at the end of the while loop, but we need the index where we stopped searching, so we subtract 1 here to accommodate for that. } } nextSeperatorIndex++; } } var member = source.Substring(index, nextSeperatorIndex - index); if (member.Contains(":")) { identifier = member.Remove(member.IndexOf(":")).Trim(); content = member.Remove(0, member.IndexOf(":") + 1); contentObj = processor.ExecuteStatement(new ScriptStatement(content)); } else { identifier = member.Trim(); contentObj = processor.Undefined; } if (!ScriptProcessor.IsValidIdentifier(identifier)) { processor.ErrorHandler.ThrowError(ErrorType.SyntaxError, ErrorHandler.MESSAGE_SYNTAX_MISSING_VAR_NAME); } prototype.AddMember(processor, new PrototypeMember(identifier, contentObj)); index = nextSeperatorIndex + 1; } return(prototype.CreateInstance(processor, null, false)); }