public bool VisitNode(Class node) { // class classname extends parentclass [within outerclass] [specifiers] ; Write("class {0} extends {1} ", node.Name, node.Parent.Name); if (node.OuterClass.Name != node.Parent.Name) Append("within {0} ", node.OuterClass.Name); if (node.Specifiers.Count > 0) Append("{0}", String.Join(" ", node.Specifiers.Select(x => x.Value))); Append(";"); // print the rest of the class, according to the standard "anatomy of an unrealscript" article. if (node.TypeDeclarations.Count > 0) { Write(""); Write("// Types"); foreach (VariableType type in node.TypeDeclarations) type.AcceptVisitor(this); } if (node.VariableDeclarations.Count > 0) { Write(""); Write("// Variables"); foreach (VariableDeclaration decl in node.VariableDeclarations.ToList()) decl.AcceptVisitor(this); } if (node.Operators.Count > 0) { Write(""); Write("// Operators"); foreach (OperatorDeclaration op in node.Operators) op.AcceptVisitor(this); } if (node.Functions.Count > 0) { Write(""); Write("// Functions"); foreach (Function func in node.Functions) func.AcceptVisitor(this); } if (node.States.Count > 0) { Write(""); Write("// States"); foreach (State state in node.States) state.AcceptVisitor(this); } Write(""); if (node.DefaultProperties != null) node.DefaultProperties.AcceptVisitor(this); return true; }
// TODO: this is only for text decompiling, should extend to a full ast for modification. public Class ConvertClass() { VariableType parent; if (Object.SuperField != null) parent = new VariableType(Object.SuperField.Name, null, null); else parent = new VariableType("object", null, null); VariableType outer; if (Object.OuterClass != null) outer = new VariableType(Object.OuterClass.Name, null, null); else outer = new VariableType(parent.Name, null, null); // TODO: specifiers // TODO: operators // TODO: components // TODO: constants // TODO: interfaces var Types = new List<VariableType>(); foreach (var member in Object.Structs) Types.Add(ConvertStruct(member)); foreach (var member in Object.Enums) Types.Add(ConvertEnum(member)); var Vars = new List<VariableDeclaration>(); foreach (var member in Object.Variables) Vars.Add(ConvertVariable(member)); var Funcs = new List<Function>(); foreach (var member in Object.DefinedFunctions) Funcs.Add(ConvertFunction(member)); var States = new List<State>(); foreach (var member in Object.States) States.Add(ConvertState(member)); AST = new Class(Object.Name, new List<Specifier>(), Vars, Types, Funcs, States, parent, outer, new List<OperatorDeclaration>(), null, null); // Ugly quick fix: foreach (var member in Types) member.Outer = AST; foreach (var member in Vars) member.Outer = AST; foreach (var member in Funcs) member.Outer = AST; foreach (var member in States) member.Outer = AST; var propObject = PCC.GetExportObject(Object.DefaultPropertyIndex); if (propObject != null && propObject.DefaultProperties != null && propObject.DefaultProperties.Count != 0) AST.DefaultProperties = ConvertDefaultProperties(propObject.DefaultProperties); return AST; }
public bool VisitNode(Class node) { // TODO: allow duplicate names as long as its in different packages! if (Symbols.SymbolExists(node.Name, "")) return Error("A class named '" + node.Name + "' already exists!", node.StartPos, node.EndPos); Symbols.AddSymbol(node.Name, node); ASTNode parent; if (!Symbols.TryGetSymbol(node.Parent.Name, out parent, "")) return Error("No parent class named '" + node.Parent.Name + "' found!", node.Parent.StartPos, node.Parent.EndPos); if (parent != null) { if (parent.Type != ASTNodeType.Class) return Error("Parent named '" + node.Parent.Name + "' is not a class!", node.Parent.StartPos, node.Parent.EndPos); else if ((parent as Class).SameOrSubClass(node.Name)) // TODO: not needed due to no forward declarations? return Error("Extending from '" + node.Parent.Name + "' causes circular extension!", node.Parent.StartPos, node.Parent.EndPos); else node.Parent = parent as Class; } ASTNode outer; if (node.OuterClass != null) { if (!Symbols.TryGetSymbol(node.OuterClass.Name, out outer, "")) return Error("No outer class named '" + node.OuterClass.Name + "' found!", node.OuterClass.StartPos, node.OuterClass.EndPos); else if (outer.Type != ASTNodeType.Class) return Error("Outer named '" + node.OuterClass.Name + "' is not a class!", node.OuterClass.StartPos, node.OuterClass.EndPos); else if (node.Parent.Name == "Actor") return Error("Classes extending 'Actor' can not be inner classes!", node.OuterClass.StartPos, node.OuterClass.EndPos); else if (!(outer as Class).SameOrSubClass((node.Parent as Class).OuterClass.Name)) return Error("Outer class must be a sub-class of the parents outer class!", node.OuterClass.StartPos, node.OuterClass.EndPos); } else { outer = (node.Parent as Class).OuterClass; } node.OuterClass = outer as Class; // TODO(?) validate class specifiers more than the initial parsing? Symbols.GoDirectlyToStack((node.Parent as Class).GetInheritanceString()); Symbols.PushScope(node.Name); foreach (VariableType type in node.TypeDeclarations) { type.Outer = node; Success = Success && type.AcceptVisitor(this); } foreach (VariableDeclaration decl in node.VariableDeclarations.ToList()) { decl.Outer = node; Success = Success && decl.AcceptVisitor(this); } foreach (OperatorDeclaration op in node.Operators) { op.Outer = node; Success = Success && op.AcceptVisitor(this); } foreach (Function func in node.Functions) { func.Outer = node; Success = Success && func.AcceptVisitor(this); } foreach (State state in node.States) { state.Outer = node; Success = Success && state.AcceptVisitor(this); } Symbols.PopScope(); Symbols.RevertToObjectStack(); node.Declaration = node; return Success; }
public void BasicClassTest() { var source = "class Test Deprecated Transient; \n" + "var enum ETestnumeration {\n" + " TEST_value1,\n" + " TEST_value2,\n" + " TEST_value3,\n" + "} inlineNumeration, testnum2;\n" + "var private deprecated int X; \n" + "VAR INT Y, Z; \n" + "var ETestnumeration testnum;\n" + "struct transient testStruct\n" + "{ var float a, b, c; };\n" + "var private struct transient twoStruct extends testStruct\n" + "{\n" + " var etestnumeration num;\n" + "} structA, structB;\n" + "function float funcB( testStruct one, float two ) \n" + "{\n" + " local float c;" + " one.a = 1.3 * c;" + " while (true)" + " {" + " c = c - c - c;" + " }" + " if (false) {" + " switch(one.a) {" + " case one.a:" + " c = one.a;" + " break;" + " case 1.2:" + " case 1.3:" + " c = c + 0.5;" + " break;" + " default:" + " c = 6.6;" + " }" + " }" + " return one.a + 0.33 * (0.66 + 0.1) * 1.5;\n" + "}\n" + "private simulated function float MyFunc( out testStruct one, coerce optional float two ) \n" + "{\n" + " return one.b + funcB(one, two);\n" + "}\n" + "auto state MyState\n" + "{\n" + "ignores MyFunc;\n" + "function StateFunc()\n" + "{\n" + "}\n" + "\n" + "Begin:\n" + " moredragons\n" + "}\n" + "\n" + "final static operator(254) int >>>( coerce float left, coerce float right )\n" + "{\n" + " all the dragons\n" + "}\n" + "\n" + "\n" + "\n"; var parser = new ClassOutlineParser(new TokenStream<String>(new StringLexer(source)), log); var symbols = new SymbolTable(); Class obj = new Class("Object", null, null, null, null, null, null, null, null, null, null); obj.OuterClass = obj; symbols.PushScope(obj.Name); symbols.AddSymbol(obj.Name, obj); VariableType integer = new VariableType("int", null, null); symbols.AddSymbol(integer.Name, integer); VariableType floatingpoint = new VariableType("float", null, null); symbols.AddSymbol(floatingpoint.Name, floatingpoint); InOpDeclaration plus_float = new InOpDeclaration("+", 20, false, null, floatingpoint, new FunctionParameter(floatingpoint, null, null, null, null), new FunctionParameter(floatingpoint, null, null, null, null), null, null, null); symbols.AddOperator(plus_float); InOpDeclaration sub_float = new InOpDeclaration("-", 20, false, null, floatingpoint, new FunctionParameter(floatingpoint, null, null, null, null), new FunctionParameter(floatingpoint, null, null, null, null), null, null, null); symbols.AddOperator(sub_float); InOpDeclaration mult_float = new InOpDeclaration("*", 16, false, null, floatingpoint, new FunctionParameter(floatingpoint, null, null, null, null), new FunctionParameter(floatingpoint, null, null, null, null), null, null, null); symbols.AddOperator(mult_float); Class node = (Class)parser.ParseDocument(); var ClassValidator = new ClassValidationVisitor(log, symbols); node.AcceptVisitor(ClassValidator); symbols.GoDirectlyToStack(node.GetInheritanceString()); foreach (Function f in node.Functions) { symbols.PushScope(f.Name); var p = new CodeBodyParser(new TokenStream<String>(new StringLexer(source)), f.Body, symbols, f, log); var b = p.ParseBody(); symbols.PopScope(); } var CodeBuilder = new CodeBuilderVisitor(); node.AcceptVisitor(CodeBuilder); Console.Write(CodeBuilder.GetCodeString()); Assert.IsTrue(log.AllErrors.Count == 0); return; }