File size: 2,349 Bytes
d605f27
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105

const WHOLE_DURATION_MAGNITUDE = 128 * 3 * 5;


const GRACE_DURATION_FACTOR = 0.2246;


const FUNCTIONAL_VARIABLE_NAME_PATTERN = /^lotus/;

const MAIN_SCORE_NAME = "lotusMainScore";


// Greatest common divisor & Least common multiple
const gcd = (a: number, b: number): number => b === 0 ? a : gcd(b, a % b);
/*const gcd = (a: number, b: number): number => {
	if (!Number.isFinite(a) || !Number.isFinite(b)) {
		console.warn("NAN:", a, b);
		debugger;
		return NaN;
	}
	return b === 0 ? a : gcd(b, a % b);
};*/
const lcm = (a: number, b: number): number => a * b / gcd(a, b);
const lcmMulti: (...numbers: number[]) => number = (a, b, ...numbers) => Number.isFinite(b) ? (numbers.length ? lcmMulti(lcm(a, b), ...numbers) : lcm(a, b)) : (Number.isFinite(a) ? a : 1);


class FractionNumber {
	denominator: number;
	numerator: number;


	static fromExpression (exp: string): FractionNumber {
		const [numerator, denominator] = exp.match(/\d+/g);

		return new FractionNumber(Number(numerator), Number(denominator));
	}


	constructor (numerator, denominator) {
		this.numerator = numerator;
		this.denominator = denominator;
	}


	toString (): string {
		return `${this.numerator}/${this.denominator}`;
	}


	get value () {
		return this.numerator / this.denominator;
	}


	get reciprocal (): FractionNumber {
		return new FractionNumber(this.denominator, this.numerator);
	}


	get reduced (): FractionNumber {
		const divider = gcd(this.denominator, this.numerator);

		return new FractionNumber(this.numerator / divider, this.denominator / divider);
	}
};


const replaceSourceToken = (source: string, token: string): string => {
	let placeholder = "";

	if (token.length < 4)
		placeholder = Array(token.length).fill(" ").join("");
	else
		placeholder = "%{" + Array(token.length - 4).fill("-").join("") + "%}";

	let result = source;
	while (result.includes(token))
		result = result.replace(token, placeholder);

	return result;
};


type DocLocation = [number, number];


const docLocationSet = (locations: DocLocation[]): Set<string> =>
	locations.reduce((set, [line, col]) => (set.add(`${line}:${col}`), set), new Set<string>());



export {
	WHOLE_DURATION_MAGNITUDE,
	GRACE_DURATION_FACTOR,
	FUNCTIONAL_VARIABLE_NAME_PATTERN,
	MAIN_SCORE_NAME,
	gcd,
	lcm,
	lcmMulti,
	FractionNumber,
	replaceSourceToken,
	DocLocation,
	docLocationSet,
};