1
0
Files
otyaSMILEBASIC/SMILEBASIC/program.d

570 lines
14 KiB
D
Raw Normal View History

2016-12-27 17:16:54 +09:00
module otya.smilebasic.program;
import otya.smilebasic.error;
2016-12-27 21:03:48 +09:00
import std.range;
2016-12-27 17:16:54 +09:00
import std.container;
2016-12-27 23:01:28 +09:00
import std.algorithm;
2016-12-27 17:16:54 +09:00
2016-12-28 15:49:44 +09:00
unittest
{
Slot slot;
slot.init();
slot.currentLine = 1;
assert(slot.get() == "\n");
slot.currentLine = 1;
slot.set("1");
assert(slot.get() == "\n");
assert(slot.get() == "");
slot.currentLine = 1;
assert(slot.get() == "1\n");
assert(slot.get() == "\n");
assert(slot.get() == "");
slot.currentLine = 2;
slot.set("2");
assert(slot.get() == "\n");
assert(slot.get() == "");
slot.currentLine = 1;
assert(slot.get() == "1\n");
assert(slot.get() == "2\n");
assert(slot.get() == "\n");
assert(slot.get() == "");
slot.currentLine = 1;
slot.set("A");
assert(slot.get() == "2\n");
assert(slot.get() == "\n");
assert(slot.get() == "");
slot.currentLine = 1;
assert(slot.get() == "A\n");
assert(slot.get() == "2\n");
assert(slot.get() == "\n");
assert(slot.get() == "");
slot.currentLine = 2;
slot.set("I\nJ");
assert(slot.get() == "\n");
assert(slot.get() == "");
slot.currentLine = 1;
assert(slot.get() == "A\n");
assert(slot.get() == "I\n");
assert(slot.get() == "J\n");
assert(slot.get() == "\n");
assert(slot.get() == "");
//PRGINS
slot.currentLine = 1;
slot.insert("3", false);
assert(slot.get() == "A\n");
assert(slot.get() == "I\n");
assert(slot.get() == "J\n");
assert(slot.get() == "\n");
assert(slot.get() == "");
slot.currentLine = 1;
assert(slot.get() == "3\n");
assert(slot.get() == "A\n");
assert(slot.get() == "I\n");
assert(slot.get() == "J\n");
assert(slot.get() == "\n");
assert(slot.get() == "");
slot.currentLine = 1;
slot.insert("4", true);
assert(slot.get() == "4\n");
assert(slot.get() == "A\n");
assert(slot.get() == "I\n");
assert(slot.get() == "J\n");
assert(slot.get() == "\n");
assert(slot.get() == "");
slot.currentLine = 1;
assert(slot.get() == "3\n");
assert(slot.get() == "4\n");
assert(slot.get() == "A\n");
assert(slot.get() == "I\n");
assert(slot.get() == "J\n");
assert(slot.get() == "\n");
assert(slot.get() == "");
slot.currentLine = 2;
slot.insert("5", false);
assert(slot.get() == "4\n");
assert(slot.get() == "A\n");
assert(slot.get() == "I\n");
assert(slot.get() == "J\n");
assert(slot.get() == "\n");
assert(slot.get() == "");
slot.currentLine = 1;
assert(slot.get() == "3\n");
assert(slot.get() == "5\n");
assert(slot.get() == "4\n");
assert(slot.get() == "A\n");
assert(slot.get() == "I\n");
assert(slot.get() == "J\n");
assert(slot.get() == "\n");
assert(slot.get() == "");
slot.currentLine = 2;
slot.insert("6", true);
assert(slot.get() == "6\n");
assert(slot.get() == "4\n");
assert(slot.get() == "A\n");
assert(slot.get() == "I\n");
assert(slot.get() == "J\n");
assert(slot.get() == "\n");
assert(slot.get() == "");
slot.currentLine = 1;
assert(slot.get() == "3\n");
assert(slot.get() == "5\n");
assert(slot.get() == "6\n");
assert(slot.get() == "4\n");
assert(slot.get() == "A\n");
assert(slot.get() == "I\n");
assert(slot.get() == "J\n");
assert(slot.get() == "\n");
assert(slot.get() == "");
2016-12-28 16:09:06 +09:00
//PRGDEL
slot.currentLine = 1;
slot.delete_(1);
assert(slot.get() == "5\n");
assert(slot.get() == "6\n");
assert(slot.get() == "4\n");
assert(slot.get() == "A\n");
assert(slot.get() == "I\n");
assert(slot.get() == "J\n");
assert(slot.get() == "\n");
assert(slot.get() == "");
slot.currentLine = 1;
assert(slot.get() == "5\n");
assert(slot.get() == "6\n");
assert(slot.get() == "4\n");
assert(slot.get() == "A\n");
assert(slot.get() == "I\n");
assert(slot.get() == "J\n");
assert(slot.get() == "\n");
assert(slot.get() == "");
slot.currentLine = 2;
slot.delete_(2);
assert(slot.get() == "A\n");
assert(slot.get() == "I\n");
assert(slot.get() == "J\n");
assert(slot.get() == "\n");
assert(slot.get() == "");
slot.currentLine = 1;
assert(slot.get() == "5\n");
assert(slot.get() == "A\n");
assert(slot.get() == "I\n");
assert(slot.get() == "J\n");
assert(slot.get() == "\n");
assert(slot.get() == "");
slot.delete_(-1);
assert(slot.get() == "");
slot.currentLine = 1;
assert(slot.get() == "\n");
assert(slot.get() == "");
2016-12-28 17:31:30 +09:00
slot.set("A");
assert(slot.get() == "");
slot.currentLine = 1;
assert(slot.get() == "A\n");
assert(slot.get() == "\n");
assert(slot.get() == "");
slot.delete_(1);
slot.delete_(1);
slot.delete_(1);
slot.delete_(1);
slot.currentLine = 1;
slot.set("A");
slot.set("B");
slot.currentLine = 1;
slot.set("A");
slot.set("B");
slot.currentLine = 1;
assert(slot.get() == "A\n");
assert(slot.get() == "B\n");
assert(slot.get() == "\n");
assert(slot.get() == "");
assert(slot.size(SizeType.Line) == 3);
slot.delete_(-1);
assert(slot.size(SizeType.Line) == 0);
slot.currentLine = 1;
slot.set("A");
slot.set("B");
slot.delete_(1);
assert(slot.get() == "B\n");
assert(slot.get() == "");
slot.currentLine = -1;
assert(slot.get() == "B\n");
assert(slot.get() == "");
slot.currentLine = 1;
assert(slot.get() == "A\n");
assert(slot.get() == "B\n");
assert(slot.get() == "");
slot.currentLine = 2;
slot.delete_(1);
assert(slot.get() == "A\n");
assert(slot.get() == "");
2016-12-28 22:46:28 +09:00
slot.delete_(-1);
slot.set("1");
slot.set("2");
slot.set("3");
slot.set("4");
slot.set("5");
slot.set("6");
slot.set("7");
slot.currentLine = 1;
slot.currentLine = 1;
slot.get();
slot.insert("A", false);
slot.get();
slot.get();
slot.insert("B", true);
assert(slot.get() == "4\n");
assert(slot.get() == "5\n");
slot.insert("C", false);
slot.get();
slot.currentLine = 1;
slot.currentLine = 1;
assert(slot.get() == "A\n");
assert(slot.get() == "1\n");
assert(slot.get() == "2\n");
assert(slot.get() == "3\n");
assert(slot.get() == "B\n");
assert(slot.get() == "4\n");
assert(slot.get() == "C\n");
assert(slot.get() == "5\n");
assert(slot.get() == "6\n");
assert(slot.get() == "7\n");
assert(slot.get() == "\n");
assert(slot.get() == "");
assert(slot.get() == "");
assert(slot.get() == "");
assert(slot.get() == "");
slot.insert("D", true);
slot.insert("E", false);
slot.insert("F", false);
slot.insert("G", false);
slot.currentLine = 1;
assert(slot.get() == "A\n");
assert(slot.get() == "1\n");
assert(slot.get() == "2\n");
assert(slot.get() == "3\n");
assert(slot.get() == "B\n");
assert(slot.get() == "4\n");
assert(slot.get() == "C\n");
assert(slot.get() == "5\n");
assert(slot.get() == "6\n");
assert(slot.get() == "7\n");
assert(slot.get() == "\n");
assert(slot.get() == "E\n");
assert(slot.get() == "F\n");
assert(slot.get() == "G\n");
assert(slot.get() == "D\n");
assert(slot.get() == "");
2016-12-28 15:49:44 +09:00
}
2016-12-28 16:20:50 +09:00
enum SizeType
{
Line = 0,
Char = 1,
FreeChar = 2,
}
2016-12-27 17:16:54 +09:00
struct Slot
{
2016-12-28 16:27:49 +09:00
private DList!wstring program;
private DList!wstring.Range range;
2016-12-28 17:31:30 +09:00
private DList!wstring.Range range2;
2016-12-28 16:27:49 +09:00
wstring name;
2016-12-28 15:49:44 +09:00
void init()
2016-12-27 23:01:28 +09:00
{
2016-12-28 15:49:44 +09:00
program = make!(DList!wstring)(["\n"w]);
2016-12-27 23:01:28 +09:00
range = program[];
}
2016-12-28 16:27:49 +09:00
void load(wstring filename, wstring data)
2016-12-27 17:16:54 +09:00
{
2016-12-28 16:27:49 +09:00
name = filename;
2016-12-27 17:16:54 +09:00
program.clear();
foreach(l; splitter(data, "\n"))
{
program.insertBack(l ~ '\n');
}
2016-12-27 21:03:48 +09:00
if (program.back == "\n")
{
program.removeBack();
}
range = program[];
2016-12-27 17:16:54 +09:00
}
wchar[] text()
{
import std.algorithm.iteration, std.outbuffer;
auto buffer = new OutBuffer();
buffer.reserve(program.opSlice.map!"(a.length + 1) * 2".sum);
foreach(line; program)
{
buffer.write(line);
}
ubyte[] progbuff = buffer.toBytes;
wchar[] progbuff2 = (cast(wchar*)progbuff.ptr)[0..progbuff.length / 2];
return progbuff2;
}
import otya.smilebasic.token;
wstring getLine(SourceLocation loc)
{
import std.string;
int i;
foreach (line; program)
{
i++;
if (i == loc.line)
return line;
}
return "";
}
2016-12-27 21:03:48 +09:00
void currentLine(int line)
{
if (line == -1)
{
//range = DList!wstring.Range(program._last);
range = program[];
while (!range.empty)
{
auto old = range.save;
range.popFront();
if (range.empty)
{
range = old;
break;
}
}
2016-12-28 22:46:28 +09:00
range2 = range.save;
2016-12-27 21:03:48 +09:00
return;
}
range = program[];
range.popFrontN(line - 1);
2016-12-28 22:46:28 +09:00
range2 = range.save;
2016-12-27 21:03:48 +09:00
}
wstring get()
{
if (range.empty)
{
return "";
}
auto a = range.front;
2016-12-28 17:31:30 +09:00
range2 = range.save;
2016-12-27 21:03:48 +09:00
range.popFront();
return a;
}
2016-12-27 23:01:28 +09:00
void set(wstring v)
{
int i;
foreach(l; splitter(v, "\n"))
{
if (!range.empty && i == 0)
{
2016-12-28 15:49:44 +09:00
auto b = range.save;
b.popFront();
if (b.empty)
{
program.insertBefore(range, l ~ "\n");
}
else
{
2016-12-28 17:31:30 +09:00
range2 = range.save;
2016-12-28 15:49:44 +09:00
range.put(l ~ "\n");
}
2016-12-27 23:01:28 +09:00
}
else
{
if (range.empty)
{
2016-12-28 17:31:30 +09:00
if (!range2.empty)
{
range = range2;
program.insertBefore(range, l ~ "\n");
range2 = range.save;
range.popFront();
continue;
}
program.insertBefore(range, l ~ "\n");
2016-12-27 23:01:28 +09:00
}
else
{
program.insertBefore(range, l ~ "\n");
}
}
i++;
}
}
2016-12-28 15:49:44 +09:00
void insert(wstring line, bool isBack)
{
typeof(range) backup;
if (isBack)
{
backup = range.save;
2016-12-28 22:46:28 +09:00
range = range2;
2016-12-28 15:49:44 +09:00
range.popFront();
}
foreach(l; splitter(line, "\n"))
{
if (isBack)
{
//backup = range.save;
2016-12-28 22:46:28 +09:00
if (range.empty)
{
program.insertBack(l ~ "\n");
continue;
}
2016-12-28 15:49:44 +09:00
program.insertBefore(range, l ~ "\n");
}
else
{
2016-12-28 22:46:28 +09:00
if (range2.empty)
{
program.insertBack(l ~ "\n");
continue;
}
program.insertBefore(range2, l ~ "\n");
2016-12-28 15:49:44 +09:00
}
}
if (isBack)
{
2016-12-28 22:46:28 +09:00
if (range.empty)
{
currentLine = -1;
return;
}
2016-12-28 15:49:44 +09:00
range = backup;
2016-12-28 22:46:28 +09:00
if (range == range2)
{
range.popFront();
}
else
{
if (!range.empty)
{
range2 = range.save;
}
}
return;
2016-12-28 15:49:44 +09:00
}
2016-12-28 22:46:28 +09:00
if (!range.empty)
range2 = range.save;
2016-12-28 15:49:44 +09:00
}
2016-12-28 16:09:06 +09:00
void delete_(int count)
{
if (count < 0)
{
init();
2016-12-28 22:46:28 +09:00
range2 = range.save;
2016-12-28 16:09:06 +09:00
range.popFront();
2016-12-28 22:46:28 +09:00
return;
2016-12-28 16:09:06 +09:00
}
else
{
2016-12-28 17:31:30 +09:00
if (range.empty)
{
for (int i = 0; i < count;i++)
{
program.removeBack();
}
}
else
{
range = program.linearRemove(range.take(count));
}
if (range.empty)
{
range = program[];
if (range.empty)
{
program.insertAfter(range, "\n"w);
range = program[];
}
else
{
currentLine = -1;
}
}
2016-12-28 16:09:06 +09:00
}
2016-12-28 17:31:30 +09:00
range2 = range.save;
2016-12-28 16:09:06 +09:00
}
2016-12-28 16:20:50 +09:00
int memorySize = 1048476;//WiiU..?
int size(SizeType type)
{
switch(type)
{
case SizeType.Line:
2016-12-28 17:31:30 +09:00
{
auto a = cast(int)program[].walkLength;
if (a == 1 && program.front.length == 1 && program.front[0] == '\n'/*?*/)
return 0;
return a;
}
2016-12-28 16:20:50 +09:00
case SizeType.Char:
2016-12-28 16:27:49 +09:00
return cast(int)program[].map!(x => x.length).sum;
2016-12-28 16:20:50 +09:00
case SizeType.FreeChar:
2016-12-28 16:27:49 +09:00
return cast(int)(memorySize - program[].map!(x => x.length).sum).max(0);
2016-12-28 16:20:50 +09:00
default:
throw new OutOfRange("PRGSIZE", 2);
}
}
2016-12-27 17:16:54 +09:00
}
class Program
{
Slot[] slot;
bool PRGEDITused;
2016-12-28 22:51:22 +09:00
int currentSlot = -1/*PRGSLOT default value*/;
2016-12-27 17:16:54 +09:00
int slotSize = 4;
this()
{
slot = new Slot[5];
2016-12-27 23:01:28 +09:00
foreach(ref s; slot)
{
2016-12-28 15:49:44 +09:00
s.init();
2016-12-27 23:01:28 +09:00
}
2016-12-27 17:16:54 +09:00
}
2016-12-27 21:03:48 +09:00
void edit(int slot, int line)
{
PRGEDITused = true;
2016-12-27 21:03:48 +09:00
this.currentSlot = slot;
this.slot[slot].currentLine = line;
}
wstring get()
{
if (!PRGEDITused)
throw new UsePRGEDITBeforeAnyPRGFunction("PRGGET$");
2016-12-27 21:03:48 +09:00
return this.slot[currentSlot].get;
}
2016-12-27 23:01:28 +09:00
void set(wstring v)
{
if (!PRGEDITused)
throw new UsePRGEDITBeforeAnyPRGFunction("PRGSET");
2016-12-27 23:01:28 +09:00
this.slot[currentSlot].set = v;
}
2016-12-28 15:49:44 +09:00
void insert(wstring line, bool isBack)
{
if (!PRGEDITused)
throw new UsePRGEDITBeforeAnyPRGFunction("PRGINS");
this.slot[currentSlot].insert(line, isBack);
}
2016-12-28 16:09:06 +09:00
void delete_(int count)
{
if (!PRGEDITused)
throw new UsePRGEDITBeforeAnyPRGFunction("PRGDEL");
this.slot[currentSlot].delete_(count);
}
2016-12-28 16:20:50 +09:00
int size(int slot, SizeType st)
{
return this.slot[slot].size(st);
}
2016-12-28 16:27:49 +09:00
wstring name(int slot)
{
return this.slot[slot].name;
}
2016-12-27 17:16:54 +09:00
}