From fbf8c884b0295269ac05e4a7e547df14c8a0d804 Mon Sep 17 00:00:00 2001 From: otya128 Date: Tue, 23 Feb 2016 21:24:55 +0900 Subject: [PATCH] =?UTF-8?q?=E3=83=95=E3=82=A1=E3=82=A4=E3=83=AB=E3=82=92?= =?UTF-8?q?=E6=89=B1=E3=81=88=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB=E3=81=97?= =?UTF-8?q?=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SMILEBASIC/SMILEBASIC.visualdproj | 1 + SMILEBASIC/builtinfunctions.d | 107 +++++++++++++++++++++++++-- SMILEBASIC/petitcomputer.d | 6 ++ SMILEBASIC/project.d | 118 ++++++++++++++++++++++++++++++ 4 files changed, 225 insertions(+), 7 deletions(-) create mode 100644 SMILEBASIC/project.d 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