Merge branch 'main' of https://github.com/FNF-CNE-Devs/CodenameEngine-Dev
This commit is contained in:
@@ -13,6 +13,7 @@ import flixel.FlxG;
|
||||
* Help from Ne_Eo
|
||||
* @see https://twitter.com/Ne_Eo_Twitch
|
||||
*/
|
||||
@:access(away3d.core.managers.Stage3DManager)
|
||||
class Flx3DUtil
|
||||
{
|
||||
#if THREE_D_SUPPORT
|
||||
@@ -25,18 +26,25 @@ class Flx3DUtil
|
||||
return FlxG.stage.stage3Ds.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total amount of 3D stages that are in use
|
||||
* @return Int
|
||||
*/
|
||||
public static inline function getUsed3D():Int
|
||||
{
|
||||
return Stage3DManager._numStageProxies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if a Stage3D is available
|
||||
* @return Bool
|
||||
*/
|
||||
public static inline function is3DAvailable():Bool
|
||||
{
|
||||
@:privateAccess {
|
||||
if (Stage3DManager._stageProxies == null)
|
||||
return true;
|
||||
if (Stage3DManager._stageProxies == null)
|
||||
return true;
|
||||
|
||||
return Stage3DManager._numStageProxies < Stage3DManager._stageProxies.length;
|
||||
}
|
||||
return Stage3DManager._numStageProxies < Stage3DManager._stageProxies.length;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -36,7 +36,7 @@ class Flx3DView extends FlxView3D {
|
||||
var meshes:Array<Mesh> = [];
|
||||
public function new(x:Float = 0, y:Float = 0, width:Int = -1, height:Int = -1) {
|
||||
if (!Flx3DUtil.is3DAvailable())
|
||||
throw "[Flx3DView] 3D is not available on this platform. Stages in use: " + Flx3DUtil.getTotal3D() + ", Max stages allowed: " + FlxG.stage.stage3Ds.length + ".";
|
||||
throw "[Flx3DView] 3D is not available on this platform. Stages in use: " + Flx3DUtil.getUsed3D() + ", Max stages allowed: " + Flx3DUtil.getTotal3D() + ".";
|
||||
super(x, y, width, height);
|
||||
__cur3DStageID = __3DIDS++;
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ class MusicBeatState extends FlxState implements IBeatReceiver
|
||||
var path = Paths.script('data/states/${scriptName}/LIB_$i');
|
||||
var script = Script.create(path);
|
||||
if (script is DummyScript) continue;
|
||||
script.fileName = '$i:$scriptName';
|
||||
script.remappedNames.set(script.fileName, '$i:${script.fileName}');
|
||||
stateScripts.add(script);
|
||||
script.load();
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ class MusicBeatSubstate extends FlxSubState implements IBeatReceiver
|
||||
var path = Paths.script('data/states/${scriptName}/LIB_$i');
|
||||
var script = Script.create(path);
|
||||
if (script is DummyScript) continue;
|
||||
script.fileName = '$i:$scriptName';
|
||||
script.remappedNames.set(script.fileName, '$i:${script.fileName}');
|
||||
stateScripts.add(script);
|
||||
script.load();
|
||||
}
|
||||
|
||||
@@ -6,9 +6,6 @@ import lime.utils.AssetLibrary;
|
||||
class AssetsLibraryList extends AssetLibrary {
|
||||
public var libraries:Array<AssetLibrary> = [];
|
||||
|
||||
public var rootLibs:Array<AssetLibrary> = [];
|
||||
public var assetsLibs:Array<AssetLibrary> = [];
|
||||
|
||||
@:allow(funkin.backend.system.Main)
|
||||
@:allow(funkin.backend.system.MainState)
|
||||
private var __defaultLibraries:Array<AssetLibrary> = [];
|
||||
@@ -19,7 +16,6 @@ class AssetsLibraryList extends AssetLibrary {
|
||||
libraries.remove(lib);
|
||||
return lib;
|
||||
}
|
||||
|
||||
public function existsSpecific(id:String, type:String, source:AssetSource = BOTH) {
|
||||
if (!id.startsWith("assets/") && exists('assets/$id', type))
|
||||
return true;
|
||||
@@ -98,29 +94,23 @@ class AssetsLibraryList extends AssetLibrary {
|
||||
return content;
|
||||
}
|
||||
|
||||
public function getSpecificAsset(id:String, type:String, source:AssetSource = BOTH, ?avoidRoot:Bool = false):Dynamic {
|
||||
public function getSpecificAsset(id:String, type:String, source:AssetSource = BOTH):Dynamic {
|
||||
try {
|
||||
if (!id.startsWith("assets/")) {
|
||||
var ass = getSpecificAsset('assets/$id', type, source);
|
||||
if (ass != null)
|
||||
if (ass != null) {
|
||||
return ass;
|
||||
} else {
|
||||
for (lib in assetsLibs) {
|
||||
if (shouldSkipLib(libraries.indexOf(lib), source)) continue;
|
||||
|
||||
var asset = lib.getAsset(id, type);
|
||||
if (asset != null)
|
||||
return asset;
|
||||
}
|
||||
}
|
||||
for(k=>e in libraries) {
|
||||
if (shouldSkipLib(k, source)) continue;
|
||||
|
||||
if (!avoidRoot) {
|
||||
for (lib in rootLibs) {
|
||||
if (shouldSkipLib(libraries.indexOf(lib), source)) continue;
|
||||
|
||||
var asset = lib.getAsset(id, type);
|
||||
if (asset != null)
|
||||
@:privateAccess
|
||||
if (e.exists(id, e.types.get(id))) {
|
||||
var asset = e.getAsset(id, type);
|
||||
if (asset != null) {
|
||||
return asset;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -140,9 +130,6 @@ class AssetsLibraryList extends AssetLibrary {
|
||||
public override inline function getAsset(id:String, type:String):Dynamic
|
||||
return getSpecificAsset(id, type, BOTH);
|
||||
|
||||
public inline function getAssetSafe(id:String, type:String):Dynamic
|
||||
return getSpecificAsset(id, type, BOTH, true);
|
||||
|
||||
public override function isLocal(id:String, type:String) {
|
||||
return true;
|
||||
}
|
||||
@@ -171,17 +158,8 @@ class AssetsLibraryList extends AssetLibrary {
|
||||
addLibrary(d);
|
||||
}
|
||||
|
||||
public function addLibrary(lib:AssetLibrary) @:privateAccess {
|
||||
public function addLibrary(lib:AssetLibrary) {
|
||||
libraries.insert(0, lib);
|
||||
|
||||
var finalLib:AssetLibrary = lib;
|
||||
if (finalLib is openfl.utils.AssetLibrary)
|
||||
finalLib = cast(finalLib, openfl.utils.AssetLibrary).__proxy;
|
||||
|
||||
if (finalLib is IModsAssetLibrary)
|
||||
assetsLibs.insert(0, finalLib);
|
||||
else
|
||||
rootLibs.insert(0, finalLib);
|
||||
return lib;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -302,6 +302,23 @@ class Paths
|
||||
return content;
|
||||
*/
|
||||
}
|
||||
|
||||
// Used in Script.hx
|
||||
@:noCompletion public static function getFilenameFromLibFile(path:String) {
|
||||
var file = new haxe.io.Path(path);
|
||||
if(file.file.startsWith("LIB_")) {
|
||||
return file.dir + "." + file.ext;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
@:noCompletion public static function getLibFromLibFile(path:String) {
|
||||
var file = new haxe.io.Path(path);
|
||||
if(file.file.startsWith("LIB_")) {
|
||||
return file.file.substr(4);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
class ScriptPathInfo {
|
||||
|
||||
@@ -94,7 +94,7 @@ class GlobalScript {
|
||||
var path = Paths.script('data/global/LIB_$i');
|
||||
var script = Script.create(path);
|
||||
if (script is DummyScript) continue;
|
||||
script.fileName = '$i:global.hx';
|
||||
script.remappedNames.set(script.fileName, '$i:${script.fileName}');
|
||||
scripts.add(script);
|
||||
script.load();
|
||||
}
|
||||
|
||||
@@ -1,21 +1,17 @@
|
||||
package funkin.backend.scripting;
|
||||
|
||||
import haxe.io.Path;
|
||||
import hscript.Expr.ClassDecl;
|
||||
import hscript.Expr.ModuleDecl;
|
||||
import hscript.Expr.Error;
|
||||
import hscript.Parser;
|
||||
import openfl.Assets;
|
||||
import lime.utils.AssetType;
|
||||
import hscript.*;
|
||||
|
||||
class HScript extends Script {
|
||||
public var interp:Interp;
|
||||
public var parser:Parser;
|
||||
public var expr:Expr;
|
||||
public var decls:Array<ModuleDecl> = null;
|
||||
public var code:String;
|
||||
public var folderlessPath:String;
|
||||
public var code:String = null;
|
||||
//public var folderlessPath:String;
|
||||
var __importedPaths:Array<String>;
|
||||
|
||||
public static function initParser() {
|
||||
@@ -30,10 +26,12 @@ class HScript extends Script {
|
||||
|
||||
interp = new Interp();
|
||||
|
||||
// We use getAssetSafe to prevent crash from empty file (null which would check root (big crash)) -lunar
|
||||
code = Assets.exists(path) ? Paths.assetsTree.getAssetSafe(path, TEXT) : null;
|
||||
try {
|
||||
if(Assets.exists(rawPath)) code = Assets.getText(rawPath);
|
||||
} catch(e) Logs.trace('Error while reading $path: ${Std.string(e)}', ERROR);
|
||||
|
||||
parser = initParser();
|
||||
folderlessPath = Path.directory(path);
|
||||
//folderlessPath = Path.directory(path);
|
||||
__importedPaths = [path];
|
||||
|
||||
interp.errorHandler = _errorHandler;
|
||||
@@ -48,14 +46,13 @@ class HScript extends Script {
|
||||
}));
|
||||
|
||||
funkin.backend.scripting.GlobalScript.call("onScriptCreated", [this, "hscript"]);
|
||||
|
||||
if (code != null && code.trim() != "")
|
||||
loadFromString(code);
|
||||
loadFromString(code);
|
||||
}
|
||||
|
||||
public override function loadFromString(code:String) {
|
||||
try {
|
||||
expr = parser.parseString(code, fileName);
|
||||
if (code != null && code.trim() != "")
|
||||
expr = parser.parseString(code, fileName);
|
||||
} catch(e:Error) {
|
||||
_errorHandler(e);
|
||||
} catch(e) {
|
||||
@@ -94,7 +91,9 @@ class HScript extends Script {
|
||||
}
|
||||
|
||||
private function _errorHandler(error:Error) {
|
||||
|
||||
var fileName = error.origin;
|
||||
if(remappedNames.exists(fileName))
|
||||
fileName = remappedNames.get(fileName);
|
||||
var fn = '$fileName:${error.line}: ';
|
||||
var err = error.toString();
|
||||
if (err.startsWith(fn)) err = err.substr(fn.length);
|
||||
|
||||
@@ -124,13 +124,22 @@ class Script extends FlxBasic implements IFlxDestroyable {
|
||||
*/
|
||||
public var fileName:String;
|
||||
|
||||
/**
|
||||
* Script Extension
|
||||
*/
|
||||
public var extension:String;
|
||||
|
||||
/**
|
||||
* Path to the script.
|
||||
*/
|
||||
public var path:String = null;
|
||||
|
||||
private var rawPath:String = null;
|
||||
|
||||
private var didLoad:Bool = false;
|
||||
|
||||
public var remappedNames:Map<String, String> = [];
|
||||
|
||||
/**
|
||||
* Creates a script from the specified asset path. The language is automatically determined.
|
||||
* @param path Path in assets
|
||||
@@ -177,7 +186,11 @@ class Script extends FlxBasic implements IFlxDestroyable {
|
||||
public function new(path:String) {
|
||||
super();
|
||||
|
||||
rawPath = path;
|
||||
path = Paths.getFilenameFromLibFile(path);
|
||||
|
||||
fileName = Path.withoutDirectory(path);
|
||||
extension = Path.extension(path);
|
||||
this.path = path;
|
||||
onCreate(path);
|
||||
for(k=>e in getDefaultVariables(this)) {
|
||||
@@ -223,6 +236,9 @@ class Script extends FlxBasic implements IFlxDestroyable {
|
||||
* Traces something as this script.
|
||||
*/
|
||||
public function trace(v:Dynamic) {
|
||||
var fileName = this.fileName;
|
||||
if(remappedNames.exists(fileName))
|
||||
fileName = remappedNames.get(fileName);
|
||||
Logs.traceColored([
|
||||
Logs.logText('${fileName}: ', GREEN),
|
||||
Logs.logText(Std.string(v))
|
||||
@@ -280,6 +296,9 @@ class Script extends FlxBasic implements IFlxDestroyable {
|
||||
* @param additionalInfo Additional information you could provide.
|
||||
*/
|
||||
public function error(text:String, ?additionalInfo:Dynamic):Void {
|
||||
var fileName = this.fileName;
|
||||
if(remappedNames.exists(fileName))
|
||||
fileName = remappedNames.get(fileName);
|
||||
Logs.traceColored([
|
||||
Logs.logText(fileName, RED),
|
||||
Logs.logText(text)
|
||||
|
||||
@@ -16,7 +16,7 @@ final class GameOverCreationEvent extends CancellableEvent
|
||||
|
||||
public var gameOverSong:String;
|
||||
|
||||
public var bpm:Int;
|
||||
public var bpm:Float;
|
||||
|
||||
public var lossSFX:String;
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ class BitmapUtil {
|
||||
for(x in 0...bmap.width) {
|
||||
color = bmap.getPixel32(x, y);
|
||||
fixedColor = 0xFF000000 + (color % 0x1000000);
|
||||
if (colorMap[fixedColor] == null)
|
||||
if (!colorMap.exists(fixedColor))
|
||||
colorMap[fixedColor] = 0;
|
||||
colorMap[fixedColor] += color.alphaFloat;
|
||||
}
|
||||
@@ -50,7 +50,7 @@ class BitmapUtil {
|
||||
for(x in 0...bmap.width) {
|
||||
color = bmap.getPixel32(x, y);
|
||||
fixedColor = 0xFF000000 + (color % 0x1000000);
|
||||
if (colorMap[fixedColor] == null)
|
||||
if (!colorMap.exists(fixedColor))
|
||||
colorMap[fixedColor] = 0;
|
||||
colorMap[fixedColor] += color.alphaFloat * 0.33 + (0.67 * (color.saturation * (2 * (color.lightness > 0.5 ? 0.5 - (color.lightness) : color.lightness))));
|
||||
}
|
||||
|
||||
@@ -618,7 +618,7 @@ class CoolUtil
|
||||
frontEnd.music = music;
|
||||
}
|
||||
|
||||
public static inline function flxeaseFromString(mainEase:String, suffix:String)
|
||||
@:noUsing public static inline function flxeaseFromString(mainEase:String, suffix:String)
|
||||
return Reflect.field(FlxEase, mainEase + (mainEase == "linear" ? "" : suffix));
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ class GameOverSubstate extends MusicBeatSubstate
|
||||
|
||||
public var characterName:String;
|
||||
public var gameOverSong:String;
|
||||
public var gameOverSongBPM:Int;
|
||||
public var gameOverSongBPM:Float;
|
||||
public var lossSFXName:String;
|
||||
public var retrySFX:String;
|
||||
public var player:Bool;
|
||||
|
||||
@@ -0,0 +1,394 @@
|
||||
/*
|
||||
* Copyright (C)2005-2019 Haxe Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package haxe.format;
|
||||
|
||||
/**
|
||||
An implementation of JSON parser in Haxe.
|
||||
|
||||
This class is used by `haxe.Json` when native JSON implementation
|
||||
is not available.
|
||||
|
||||
@see https://haxe.org/manual/std-Json-parsing.html
|
||||
**/
|
||||
class JsonParser {
|
||||
/**
|
||||
Parses given JSON-encoded `str` and returns the resulting object.
|
||||
|
||||
JSON objects are parsed into anonymous structures and JSON arrays
|
||||
are parsed into `Array<Dynamic>`.
|
||||
|
||||
If given `str` is not valid JSON, an exception will be thrown.
|
||||
|
||||
If `str` is null, the result is unspecified.
|
||||
**/
|
||||
static public inline function parse(str:String):Dynamic {
|
||||
return new JsonParser(str).doParse();
|
||||
}
|
||||
|
||||
var str:String;
|
||||
var pos:Int;
|
||||
|
||||
function new(str:String) {
|
||||
this.str = str;
|
||||
this.pos = 0;
|
||||
}
|
||||
|
||||
function doParse():Dynamic {
|
||||
var result = parseRec();
|
||||
var c;
|
||||
while (!StringTools.isEof(c = nextChar())) {
|
||||
if (checkComments(c)) {
|
||||
continue;
|
||||
}
|
||||
switch (c) {
|
||||
case ' '.code, '\r'.code, '\n'.code, '\t'.code:
|
||||
// allow trailing whitespace
|
||||
default:
|
||||
invalidChar();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
var inComment = false;
|
||||
var blockComment = false;
|
||||
|
||||
inline function checkComments(c:Int) {
|
||||
var ret = false;
|
||||
if (!inComment) { // Starting Comment
|
||||
if (c == '/'.code) {
|
||||
var d = nextChar();
|
||||
if (d == '/'.code || (blockComment = (d == '*'.code))) {
|
||||
inComment = true;
|
||||
} else {
|
||||
pos--;
|
||||
}
|
||||
}
|
||||
} else { // In Comment
|
||||
if (blockComment) { // Block Comment
|
||||
if (c == '*'.code) {
|
||||
var d = nextChar();
|
||||
if (d == '/'.code) {
|
||||
inComment = blockComment = false;
|
||||
ret = true;
|
||||
} else {
|
||||
pos--;
|
||||
}
|
||||
}
|
||||
} else { // Line Comment
|
||||
if (c == '\n'.code) {
|
||||
inComment = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret || inComment;
|
||||
}
|
||||
|
||||
function parseRec():Dynamic {
|
||||
while (true) {
|
||||
var c = nextChar();
|
||||
if (checkComments(c)) {
|
||||
continue;
|
||||
}
|
||||
switch (c) {
|
||||
case ' '.code, '\r'.code, '\n'.code, '\t'.code:
|
||||
// loop
|
||||
case '{'.code:
|
||||
var obj = {}, field = null, comma:Null<Bool> = null;
|
||||
while (true) {
|
||||
var c = nextChar();
|
||||
if (checkComments(c)) {
|
||||
continue;
|
||||
}
|
||||
switch (c) {
|
||||
case ' '.code, '\r'.code, '\n'.code, '\t'.code:
|
||||
// loop
|
||||
case '}'.code:
|
||||
if (field != null || comma == false)
|
||||
invalidChar();
|
||||
return obj;
|
||||
case ':'.code:
|
||||
if (field == null)
|
||||
invalidChar();
|
||||
Reflect.setField(obj, field, parseRec());
|
||||
field = null;
|
||||
comma = true;
|
||||
case ','.code:
|
||||
if (comma) comma = false else invalidChar();
|
||||
case '"'.code:
|
||||
if (field != null || comma) invalidChar();
|
||||
field = parseString();
|
||||
default:
|
||||
invalidChar();
|
||||
}
|
||||
}
|
||||
case '['.code:
|
||||
var arr = [], comma:Null<Bool> = null;
|
||||
while (true) {
|
||||
var c = nextChar();
|
||||
if (checkComments(c)) {
|
||||
continue;
|
||||
}
|
||||
switch (c) {
|
||||
case ' '.code, '\r'.code, '\n'.code, '\t'.code:
|
||||
// loop
|
||||
case ']'.code:
|
||||
if (comma == false) invalidChar();
|
||||
return arr;
|
||||
case ','.code:
|
||||
if (comma) comma = false else invalidChar();
|
||||
default:
|
||||
if (comma) invalidChar();
|
||||
pos--;
|
||||
arr.push(parseRec());
|
||||
comma = true;
|
||||
}
|
||||
}
|
||||
case 't'.code:
|
||||
var save = pos;
|
||||
if (nextChar() != 'r'.code || nextChar() != 'u'.code || nextChar() != 'e'.code) {
|
||||
pos = save;
|
||||
invalidChar();
|
||||
}
|
||||
return true;
|
||||
case 'f'.code:
|
||||
var save = pos;
|
||||
if (nextChar() != 'a'.code || nextChar() != 'l'.code || nextChar() != 's'.code || nextChar() != 'e'.code) {
|
||||
pos = save;
|
||||
invalidChar();
|
||||
}
|
||||
return false;
|
||||
case 'n'.code:
|
||||
var save = pos;
|
||||
if (nextChar() != 'u'.code || nextChar() != 'l'.code || nextChar() != 'l'.code) {
|
||||
pos = save;
|
||||
invalidChar();
|
||||
}
|
||||
return null;
|
||||
case '"'.code:
|
||||
return parseString();
|
||||
case '0'.code, '1'.code, '2'.code, '3'.code, '4'.code, '5'.code, '6'.code, '7'.code, '8'.code, '9'.code, '-'.code:
|
||||
return parseNumber(c);
|
||||
default:
|
||||
invalidChar();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function parseString() {
|
||||
var start = pos;
|
||||
var buf:StringBuf = null;
|
||||
#if target.unicode
|
||||
var prev = -1;
|
||||
inline function cancelSurrogate() {
|
||||
// invalid high surrogate (not followed by low surrogate)
|
||||
buf.addChar(0xFFFD);
|
||||
prev = -1;
|
||||
}
|
||||
#end
|
||||
while (true) {
|
||||
var c = nextChar();
|
||||
if (c == '"'.code)
|
||||
break;
|
||||
if (c == '\\'.code) {
|
||||
if (buf == null) {
|
||||
buf = new StringBuf();
|
||||
}
|
||||
buf.addSub(str, start, pos - start - 1);
|
||||
c = nextChar();
|
||||
#if target.unicode
|
||||
if (c != "u".code && prev != -1)
|
||||
cancelSurrogate();
|
||||
#end
|
||||
switch (c) {
|
||||
case "r".code:
|
||||
buf.addChar("\r".code);
|
||||
case "n".code:
|
||||
buf.addChar("\n".code);
|
||||
case "t".code:
|
||||
buf.addChar("\t".code);
|
||||
case "b".code:
|
||||
buf.addChar(8);
|
||||
case "f".code:
|
||||
buf.addChar(12);
|
||||
case "/".code, '\\'.code, '"'.code:
|
||||
buf.addChar(c);
|
||||
case 'u'.code:
|
||||
var uc:Int = Std.parseInt("0x" + str.substr(pos, 4));
|
||||
pos += 4;
|
||||
#if !target.unicode
|
||||
if (uc <= 0x7F)
|
||||
buf.addChar(uc);
|
||||
else if (uc <= 0x7FF) {
|
||||
buf.addChar(0xC0 | (uc >> 6));
|
||||
buf.addChar(0x80 | (uc & 63));
|
||||
} else if (uc <= 0xFFFF) {
|
||||
buf.addChar(0xE0 | (uc >> 12));
|
||||
buf.addChar(0x80 | ((uc >> 6) & 63));
|
||||
buf.addChar(0x80 | (uc & 63));
|
||||
} else {
|
||||
buf.addChar(0xF0 | (uc >> 18));
|
||||
buf.addChar(0x80 | ((uc >> 12) & 63));
|
||||
buf.addChar(0x80 | ((uc >> 6) & 63));
|
||||
buf.addChar(0x80 | (uc & 63));
|
||||
}
|
||||
#else
|
||||
if (prev != -1) {
|
||||
if (uc < 0xDC00 || uc > 0xDFFF)
|
||||
cancelSurrogate();
|
||||
else {
|
||||
buf.addChar(((prev - 0xD800) << 10) + (uc - 0xDC00) + 0x10000);
|
||||
prev = -1;
|
||||
}
|
||||
} else if (uc >= 0xD800 && uc <= 0xDBFF)
|
||||
prev = uc;
|
||||
else
|
||||
buf.addChar(uc);
|
||||
#end
|
||||
default:
|
||||
throw "Invalid escape sequence \\" + String.fromCharCode(c) + " at position " + (pos - 1);
|
||||
}
|
||||
start = pos;
|
||||
}
|
||||
#if !(target.unicode)
|
||||
// ensure utf8 chars are not cut
|
||||
else if (c >= 0x80) {
|
||||
pos++;
|
||||
if (c >= 0xFC)
|
||||
pos += 4;
|
||||
else if (c >= 0xF8)
|
||||
pos += 3;
|
||||
else if (c >= 0xF0)
|
||||
pos += 2;
|
||||
else if (c >= 0xE0)
|
||||
pos++;
|
||||
}
|
||||
#end
|
||||
else if (StringTools.isEof(c))
|
||||
throw "Unclosed string";
|
||||
}
|
||||
#if target.unicode
|
||||
if (prev != -1)
|
||||
cancelSurrogate();
|
||||
#end
|
||||
if (buf == null) {
|
||||
return str.substr(start, pos - start - 1);
|
||||
} else {
|
||||
buf.addSub(str, start, pos - start - 1);
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
||||
|
||||
inline function parseNumber(c:Int):Dynamic {
|
||||
var start = pos - 1;
|
||||
var minus = c == '-'.code, digit = !minus, zero = c == '0'.code;
|
||||
var point = false, e = false, pm = false, end = false;
|
||||
while (true) {
|
||||
c = nextChar();
|
||||
switch (c) {
|
||||
case '0'.code:
|
||||
if (zero && !point)
|
||||
invalidNumber(start);
|
||||
if (minus) {
|
||||
minus = false;
|
||||
zero = true;
|
||||
}
|
||||
digit = true;
|
||||
case '1'.code, '2'.code, '3'.code, '4'.code, '5'.code, '6'.code, '7'.code, '8'.code, '9'.code:
|
||||
if (zero && !point)
|
||||
invalidNumber(start);
|
||||
if (minus)
|
||||
minus = false;
|
||||
digit = true;
|
||||
zero = false;
|
||||
case '.'.code:
|
||||
if (minus || point || e)
|
||||
invalidNumber(start);
|
||||
digit = false;
|
||||
point = true;
|
||||
case 'e'.code, 'E'.code:
|
||||
if (minus || zero || e)
|
||||
invalidNumber(start);
|
||||
digit = false;
|
||||
e = true;
|
||||
case '+'.code, '-'.code:
|
||||
if (!e || pm)
|
||||
invalidNumber(start);
|
||||
digit = false;
|
||||
pm = true;
|
||||
default:
|
||||
if (!digit)
|
||||
invalidNumber(start);
|
||||
pos--;
|
||||
end = true;
|
||||
}
|
||||
if (end)
|
||||
break;
|
||||
}
|
||||
|
||||
var f = Std.parseFloat(str.substr(start, pos - start));
|
||||
if (point) {
|
||||
return f;
|
||||
} else {
|
||||
var i = Std.int(f);
|
||||
return if (i == f) i else f;
|
||||
}
|
||||
}
|
||||
|
||||
inline function nextChar() {
|
||||
return StringTools.fastCodeAt(str, pos++);
|
||||
}
|
||||
|
||||
function invalidChar() {
|
||||
pos--; // rewind
|
||||
var col = 1;
|
||||
var line = 1;
|
||||
for (i in 0...pos) {
|
||||
var c = StringTools.fastCodeAt(str, i);
|
||||
if (c == '\n'.code) {
|
||||
col = 1;
|
||||
line++;
|
||||
}
|
||||
else {
|
||||
col++;
|
||||
}
|
||||
}
|
||||
throw "Invalid char " + StringTools.fastCodeAt(str, pos) + " ('" + str.charAt(pos) + "')" + " at line " + line + " col " + col;
|
||||
}
|
||||
|
||||
function invalidNumber(start:Int) {
|
||||
var col = 1;
|
||||
var line = 1;
|
||||
for (i in 0...start) {
|
||||
var c = StringTools.fastCodeAt(str, i);
|
||||
if (c == '\n'.code) {
|
||||
col = 1;
|
||||
line++;
|
||||
}
|
||||
else {
|
||||
col++;
|
||||
}
|
||||
}
|
||||
throw "Invalid number at line " + line + " col " + col + ": " + str.substr(start, pos - start);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user