diff --git a/SMILEBASIC/SMILEBASIC.visualdproj b/SMILEBASIC/SMILEBASIC.visualdproj
index b0a0ef1..8481e6a 100644
--- a/SMILEBASIC/SMILEBASIC.visualdproj
+++ b/SMILEBASIC/SMILEBASIC.visualdproj
@@ -214,6 +214,7 @@
+
diff --git a/SMILEBASIC/builtinfunctions.d b/SMILEBASIC/builtinfunctions.d
index c28729c..91700ec 100644
--- a/SMILEBASIC/builtinfunctions.d
+++ b/SMILEBASIC/builtinfunctions.d
@@ -43,6 +43,10 @@ struct StartOptional
{
const char[] name;
}
+struct BasicName
+{
+ wstring naame;
+}
alias ValueType = otya.smilebasic.type.ValueType;
struct BuiltinFunctionArgument
{
@@ -69,7 +73,8 @@ class BuiltinFunctions
//とりあえず引数の数で解決させる,というよりコンパイル時に型を取得する方法がない
foreach(f; func)
{
- if(f.startskip <= argc && f.argments.length >= argc && f.outoptional <= outargc && f.results.length >= outargc)
+ if(f.startskip <= argc && f.argments.length >= argc)
+ if((f.outoptional != 0 && f.outoptional <= outargc && f.results.length >= outargc) || f.results.length == outargc)
return f;
if(f.variadic)
va = f;
@@ -1302,8 +1307,94 @@ class BuiltinFunction
}
throw new IllegalFunctionCall("COPY (Not implemented error)");
}
+ @BasicName("LOAD")
+ static Value LOAD1(PetitComputer p, wstring name, DefaultValue!(int, false) flag)
+ {
+ import otya.smilebasic.project;
+ import std.string;
+ flag.setDefaultValue(0);
+ auto type = Projects.splitResourceName(name);
+ wstring txt;
+ wstring resname = type[0];
+ wstring projectname = type[1];
+ wstring filename = type[2];
+ if(projectname != "" && projectname != "SYS")
+ {
+ throw new IllegalFunctionCall("LOAD");
+ }
+ if(projectname == "")
+ {
+ projectname = p.currentProject;
+ }
+ if(resname == "TXT")
+ {
+ if(p.project.loadFile(projectname, resname, filename, txt))
+ {
+ return Value(txt);
+ }
+ throw new IllegalFunctionCall("LOAD");
+ }
+ throw new IllegalFunctionCall("LOAD");
+ }
+ @BasicName("LOAD")
+ static void LOAD2(PetitComputer p, wstring name, DefaultValue!(int, false) flag)
+ {
+ import otya.smilebasic.project;
+ import std.string;
+ flag.setDefaultValue(0);
+ auto type = Projects.splitResourceName(name);
+ wstring txt;
+ wstring resname = type[0];
+ wstring projectname = type[1];
+ wstring filename = type[2];
+ if(projectname != "" && projectname != "SYS")
+ {
+ throw new IllegalFunctionCall("LOAD");
+ }
+ if(projectname == "")
+ {
+ projectname = p.currentProject;
+ }
+ if(resname == "" || resname.indexOf("PRG") == 0)
+ {
+ int lot;
+ if(resname != "" && resname != "PRG")
+ {
+ auto num = resname[3..$];
+ lot = num.to!int;
+ }
+ if(!p.project.loadFile(projectname, "TXT", filename, txt))
+ {
+ throw new IllegalFunctionCall("LOAD");
+ }
+ p.slot[lot].load(txt);
+ return;
+ }
+ if(resname.indexOf("GRP") == 0)
+ {
+ throw new IllegalFunctionCall("NOTIMPL:LOAD GRP");
+ }
+ throw new IllegalFunctionCall("LOAD");
+ }
+ static Value LOAD(wstring name, Value arr, DefaultValue!(int, false) flag)
+ {
+ flag.setDefaultValue(0);
+ throw new IllegalFunctionCall("NOTIMPL:LOAD");
+ }
//alias void function(PetitComputer, Value[], Value[]) BuiltinFunc;
static BuiltinFunctions[wstring] builtinFunctions;
+ static wstring getBasicName(BFD)(const wstring def)
+ {
+ enum attr = __traits(getAttributes, __traits(getOverloads, BFD.C_, BFD.N)[BFD.I_]);
+ foreach(i; attr)
+ {
+ static if(__traits(compiles, i.naame))
+ {
+ return i.naame;
+ }
+ }
+ return def;
+ }
static this()
{
foreach(name; __traits(derivedMembers, BuiltinFunction))
@@ -1319,9 +1410,9 @@ class BuiltinFunction
{
suffix = "$";
}
- wstring name2 = name ~ suffix;
- auto func = builtinFunctions.get(name2, null);
alias BFD = BuiltinFunctionData!(BuiltinFunction, name, i);
+ wstring name2 = getBasicName!BFD(name ~ suffix);
+ auto func = builtinFunctions.get(name2, null);
pragma(msg, AddFunc!BFD);
auto f = new BuiltinFunction(
GetFunctionParamType!(BFD),
@@ -1435,10 +1526,6 @@ template GetBuiltinFunctionArgment(P...)
{
const string arg = "ValueType.Integer, true";
}
- else static if(is(P[0] == OptionalOutValue!int))
- {
- const string arg = "ValueType.Integer, true";
- }
else static if(is(P[0] == DefaultValue!double))
{
const string arg = "ValueType.Double, true";
@@ -1576,6 +1663,12 @@ template AddFunc(BFD)
AddFuncArg!(/*ParameterTypeTuple!(__traits(getMember, T, N)).length*/GetArgumentCount!(BFD) - 1, 0, 0, 0, BFD,
BFD.ParameterType) ~ "));}";
}
+ else static if(is(BFD.ReturnType == Value))
+ {
+ const string AddFunc = "function void(PetitComputer p, Value[] arg, Value[] ret){if(ret.length != 1){throw new IllegalFunctionCall(\"" ~ BFD.N ~ "\");}ret[0] = " ~ BFD.N ~ "(" ~
+ AddFuncArg!(/*ParameterTypeTuple!(__traits(getMember, T, N)).length*/GetArgumentCount!(BFD) - 1, 0, 0, 0, BFD,
+ BFD.ParameterType) ~ ");}";
+ }
else
{
const string AddFunc = "";
diff --git a/SMILEBASIC/petitcomputer.d b/SMILEBASIC/petitcomputer.d
index a456b16..a81311b 100644
--- a/SMILEBASIC/petitcomputer.d
+++ b/SMILEBASIC/petitcomputer.d
@@ -14,6 +14,7 @@ import otya.smilebasic.sprite;
import otya.smilebasic.error;
import otya.smilebasic.bg;
import otya.smilebasic.parser;
+import otya.smilebasic.project;
const static rot_test_deg = 45f;
const static rot_test_x = 0f;
const static rot_test_y = 1f;
@@ -141,6 +142,7 @@ struct Slot
void load(wstring data)
{
import std.algorithm;
+ program.clear();
foreach(l; splitter(data, "\n"))
{
program.insertBack(l);
@@ -358,8 +360,12 @@ class PetitComputer
fontTable[record[0]].h = 8;
}
}
+ Projects project;
+ wstring currentProject;
void init()
{
+ currentProject = "";
+ project = new Projects(".");
// DerelictGL.load();
for(int i = 0; i < consoleColor.length; i++)
consoleColorGL[i] = toGLColor(consoleColor[i]);
diff --git a/SMILEBASIC/project.d b/SMILEBASIC/project.d
new file mode 100644
index 0000000..3f51bce
--- /dev/null
+++ b/SMILEBASIC/project.d
@@ -0,0 +1,118 @@
+module otya.smilebasic.project;
+import std.path;
+import std.file;
+import std.string;
+import std.traits;
+import std.conv;
+import std.uni;
+import std.typecons;
+class Projects
+{
+ wstring rootPath;
+ wstring projectPath;
+ string projectPathU8;
+ this(wstring root)
+ {
+ rootPath = root;
+ projectPath = buildPath(root, "PROJECTS"w);
+ projectPathU8 = projectPath.to!string;
+ if(exists(projectPathU8))
+ {
+ if(isFile(projectPathU8))
+ {
+ throw new Exception("PROJECTS is file");
+ }
+ }
+ else
+ {
+ mkdir(projectPathU8);
+ }
+ createProjectInternal("[DEFAULT]");
+ createProjectInternal("SYS");
+ }
+ bool isValidProjectName(C)(C[] filename) if(isSomeChar!(C))
+ {
+ if(filename.length > 14)
+ {
+ return false;
+ }
+ foreach(c; filename)
+ {
+ if(!((c >= 'A' && c<= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_' || c == '-'))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+ bool isValidFileName(C)(C[] filename) if(isSomeChar!(C))
+ {
+ if(filename.length > 12)
+ {
+ return false;
+ }
+ foreach(c; filename)
+ {
+ if(!((c >= 'A' && c<= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '.' || c == '_' || c == '-' || c == '@'))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+ private void createProjectInternal(wstring name)
+ {
+ auto path = buildPath(projectPath, name.toUpper).to!string;
+ if(!exists(path))
+ {
+ mkdir(path);
+ }
+ auto txt = buildPath(path, "TXT").to!string;
+ if(!exists(txt))
+ {
+ mkdir(txt);
+ }
+ auto dat = buildPath(path, "DAT").to!string;
+ if(!exists(dat))
+ {
+ mkdir(dat);
+ }
+ }
+ static Tuple!(wstring, wstring, wstring) splitResourceName(wstring name)
+ {
+ auto ind = name.indexOf(":");
+ wstring type, project;
+ if(ind != -1)
+ {
+ type = name[0..ind];
+ name = name[ind + 1..$];
+ }
+ ptrdiff_t sep = name.indexOf("/");
+ if(sep != -1)
+ {
+ project = name[0..sep];
+ name = name[sep + 1..$];
+ }
+ return tuple(type, project, name);
+ }
+ bool loadFile(wstring project, wstring type, wstring name, out wstring contents)
+ {
+ contents = "";
+ if(!isValidProjectName(project))
+ {
+ return false;
+ }
+ if(project == "") project = "[DEFAULT]";
+ if(type != "TXT" && type != "DAT")
+ {
+ return false;
+ }
+ if(!isValidFileName(name))
+ {
+ return false;
+ }
+ auto path = buildPath(projectPath, project, type, name).to!string;
+ contents = readText(path).to!wstring;
+ return true;
+ }
+}
\ No newline at end of file