pascalabcnet/SyntaxVisitors/UniversalVisitors/ABCStatisticsVisitors.cs

319 lines
11 KiB
C#
Raw Permalink Normal View History

// Copyright (c) Ivan Bondarev, Stanislav Mikhalkovich (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using PascalABCCompiler;
using PascalABCCompiler.SyntaxTree;
namespace SyntaxVisitors
{
public class ABCStatisticsVisitor : WalkingVisitorNew
{
2020-08-18 09:36:16 +03:00
public int InBlockVarDefs { get; set; }
public int OutBlockVarDefs { get; set; }
public int ForsWithoutVar { get; set; }
public int ForsWithVar { get; set; }
2020-08-18 09:36:16 +03:00
public bool ProgramKeyword { get; set; }
public int OldStrings { get; set; }
public int StaticArrays { get; set; }
public int DynamicArrays { get; set; }
public int ReadProc { get; set; }
public int WriteProcWithSpace { get; set; }
public int TuplesCount { get; set; }
public int InitVarInDef { get; set; }
public int UnpackingAssign { get; set; }
public int LoopsCount { get; set; }
public int ForeachCount { get; set; }
public int LambdasCount { get; set; }
public int ExtAssignCount { get; set; }
public int BigIntegerTypeCount { get; set; }
public int ReadFuncCount { get; set; }
public int PrintCount { get; set; }
public ABCStatisticsVisitor()
{
}
public override void visit(ident id)
{
var name = id.name.ToLower();
if (name.StartsWith("readinteger") || name.StartsWith("readreal") || name.StartsWith("readstring") ||
name.StartsWith("readlninteger") || name.StartsWith("readlnreal") || name.StartsWith("readlnstring"))
ReadFuncCount++;
if (name.StartsWith("print"))
PrintCount++;
}
public override void visit(named_type_reference ntr)
{
var name = ntr.names[0].name.ToLower();
if (name == "biginteger")
BigIntegerTypeCount++;
base.visit(ntr);
}
public override void visit(assign an)
{
if (an.operator_type == Operators.AssignmentAddition || an.operator_type == Operators.AssignmentMultiplication || an.operator_type == Operators.AssignmentDivision)
ExtAssignCount++;
base.visit(an);
}
public override void visit(function_lambda_definition fld)
{
LambdasCount++;
base.visit(fld);
}
public override void visit(loop_stmt ln)
{
LoopsCount++;
base.visit(ln);
}
public override void visit(foreach_stmt fn)
{
ForeachCount++;
base.visit(fn);
}
public override void visit(tuple_node tn)
{
TuplesCount++;
base.visit(tn);
}
public override void visit(assign_var_tuple at)
{
UnpackingAssign++;
base.visit(at);
}
public override void visit(assign_tuple at)
{
UnpackingAssign++;
base.visit(at);
}
public override void visit(for_node fn)
{
if (fn.create_loop_variable == false)
ForsWithoutVar++;
if (fn.create_loop_variable == true)
ForsWithVar++;
base.visit(fn);
}
2020-08-18 09:36:16 +03:00
public override void visit(var_def_statement vds)
{
2020-08-18 09:36:16 +03:00
if (vds.Parent is var_statement)
{
InBlockVarDefs += vds.vars.Count;
}
else if (!(vds.Parent is class_members))
{
OutBlockVarDefs += vds.vars.Count;
}
2020-08-18 09:36:16 +03:00
if (vds.vars_type != null && vds.vars_type is string_num_definition)
{
OldStrings += 1;
2020-08-18 09:36:16 +03:00
}
if (vds.vars_type != null && vds.vars_type is array_type at && at.indexers != null && at.indexers.Count > 0 && at.indexers.indexers[0] != null)
{
StaticArrays += 1;
}
if (vds.vars_type != null && vds.vars_type is array_type at1 && at1.indexers == null)
{
DynamicArrays += 1;
2020-08-18 09:36:16 +03:00
}
if (vds.inital_value != null)
InitVarInDef++;
/*if (vds.inital_value != null)
{
if (vds.inital_value is ident id &&
(id.name.ToLower().StartsWith("readinteger") || id.name.ToLower().StartsWith("readreal") || id.name.ToLower().StartsWith("readstring") ||
id.name.ToLower().StartsWith("readlninteger") || id.name.ToLower().StartsWith("readlnreal") || id.name.ToLower().StartsWith("readlnstring")))
ReadFuncCount++;
}*/
base.visit(vds);
2020-08-18 09:36:16 +03:00
}
public override void visit(program_name pn)
{
if (pn != null)
ProgramKeyword = true;
}
public override void visit(method_call mc)
{
/*if (mc.dereferencing_value is ident id && (id.name.ToLower() == "read" || id.name.ToLower() == "readln"))
2020-08-18 09:36:16 +03:00
{
syntax_tree_node n = mc;
do
{
n = n.Parent;
} while (n != null && !(n is class_members));
if (n != null)
;
//ReadProc = false;
2020-08-18 09:36:16 +03:00
else
ReadProc += 1;
}*/
/*if (mc.dereferencing_value is ident id2)
{
var name = id2.name.ToLower();
var h = new HashSet<string> { "readinteger", "readlninteger", "readreal", "readlnreal", "readstring", "readlnstring", "readchar", "readlnchar" };
if (h.Contains(name))
ReadFuncCount++;
}*/
/*if (mc.dereferencing_value is ident id1 && (id1.name.ToLower() == "write" || id1.name.ToLower() == "writeln") &&
2020-08-18 09:36:16 +03:00
mc.parameters != null && mc.parameters.expressions.Any(ex => ex is char_const cc && cc.cconst == ' '))
{
WriteProcWithSpace += 1;
}*/
base.visit(mc);
}
2020-08-18 09:36:16 +03:00
public override void visit(procedure_call pc)
{
if (pc.func_name is method_call mc && mc.dereferencing_value is ident id && (id.name.ToLower() == "read" || id.name.ToLower() == "readln"))
{
syntax_tree_node n = pc;
do
{
n = n.Parent;
} while (n != null && !(n is class_members));
if (n != null)
//ReadProc = false
;
2020-08-18 09:36:16 +03:00
else
ReadProc += 1;
2020-08-18 09:36:16 +03:00
}
if (pc.func_name is method_call mc1 && mc1.dereferencing_value is ident id1 && (id1.name.ToLower() == "write" || id1.name.ToLower() == "writeln")
&& mc1.parameters != null && mc1.parameters.expressions.Any(ex => ex is char_const cc && cc.cconst == ' '))
{
WriteProcWithSpace += 1;
2020-08-18 09:36:16 +03:00
}
base.visit(pc);
2020-08-18 09:36:16 +03:00
}
public int CalcHealth(out int NegativePercent, out int PositivePercent)
{
var stat = this;
var Percent = 100;
NegativePercent = 0;
PositivePercent = 0;
var diffBlockVarDefs = stat.OutBlockVarDefs; // - stat.InBlockVarDefs;
if (diffBlockVarDefs > 0)
{
NegativePercent += 10; // за первую
NegativePercent += (diffBlockVarDefs - 1) * 2; // за оставшиеся
if (NegativePercent > 25)
NegativePercent = 25;
}
// For i
if (stat.ForsWithoutVar > 0)
{
NegativePercent += Math.Min(15 + (stat.ForsWithoutVar - 1) * 3, 25);
}
if (stat.ReadProc > 0)
{
NegativePercent += Math.Min(15 + (stat.ReadProc - 1) * 2, 20);
}
if (stat.ProgramKeyword)
{
NegativePercent += 10;
}
if (stat.StaticArrays > 0)
{
NegativePercent += Math.Min(10 + (stat.StaticArrays - 1) * 2, 15);
}
if (stat.WriteProcWithSpace > 0)
{
NegativePercent += Math.Min(2 + (stat.WriteProcWithSpace - 1) * 1, 5);
}
if (stat.OldStrings > 0)
{
NegativePercent += stat.OldStrings;
}
if (NegativePercent < 0)
NegativePercent = 0;
Percent -= NegativePercent;
// Проценты за положительное
if (stat.InBlockVarDefs > 0)
{
PositivePercent += 10; // за первую
PositivePercent += (stat.InBlockVarDefs - 1) * 2; // за оставшиеся
// этот алгоритм уравновешивает описания внутри и вне. За одинаковое количество дается 0 баллов
}
if (stat.ForsWithVar != 0)
{
PositivePercent += Math.Min(stat.ForsWithVar, 4) * 3;
}
if (stat.InitVarInDef > 0)
{
PositivePercent += Math.Min(stat.InitVarInDef, 4) * 4;
}
if (stat.ReadFuncCount > 0)
{
PositivePercent += Math.Min(stat.ReadFuncCount, 4) * 3;
}
if (stat.ExtAssignCount > 0)
{
PositivePercent += Math.Min(stat.ExtAssignCount, 4) * 3;
}
if (stat.PrintCount > 0)
{
PositivePercent += Math.Min(stat.PrintCount, 4) * 4;
}
if (stat.TuplesCount > 0)
{
PositivePercent += Math.Min(stat.PrintCount, 4) * 5;
}
if (stat.DynamicArrays > 0)
{
PositivePercent += Math.Min(stat.PrintCount, 4) * 5;
}
if (stat.UnpackingAssign > 0)
{
PositivePercent += Math.Min(stat.UnpackingAssign, 4) * 5;
}
if (stat.LoopsCount > 0)
{
PositivePercent += Math.Min(stat.LoopsCount, 4) * 4;
}
if (stat.ForeachCount > 0)
{
PositivePercent += Math.Min(stat.ForeachCount, 4) * 4;
}
if (stat.LambdasCount > 0)
{
PositivePercent += Math.Min(stat.LambdasCount, 4) * 8;
}
Percent += PositivePercent;
if (Percent > 200)
Percent = 200;
if (Percent < 0)
Percent = 0;
return Percent;
}
2020-08-18 09:36:16 +03:00
/*public override void visit(dot_node dn)
{
ProcessNode(dn.left);
if (dn.right.GetType() != typeof(ident))
ProcessNode(dn.right);
}*/
/*public override void visit(function_lambda_definition fd)
{
}*/
}
}