[yaml] add sources
This commit is contained in:
@@ -8,14 +8,13 @@
|
||||
"template"
|
||||
],
|
||||
"description": "View framework.",
|
||||
"version": "1.1.0",
|
||||
"version": "1.2.0",
|
||||
"releasenote": "Update.",
|
||||
"contributors": [
|
||||
"shmyga"
|
||||
],
|
||||
"classPath": "src/main",
|
||||
"dependencies": {
|
||||
"promhx": "1.1.0",
|
||||
"yaml": "1.3.0"
|
||||
"promhx": "1.1.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,11 +12,11 @@ class LoggerUtil {
|
||||
|
||||
public static function printStackItem(item:StackItem):String {
|
||||
return switch item {
|
||||
case StackItem.CFunction: 'CFunction';
|
||||
case StackItem.Module(m): m;
|
||||
case StackItem.FilePos(s, file, line): '${file}:${line}';
|
||||
case StackItem.Method(classname, method): '${classname}::${method}}';
|
||||
case StackItem.LocalFunction(v): 'LocalFunction(${v})';
|
||||
case CFunction: 'CFunction';
|
||||
case Module(m): m;
|
||||
case FilePos(s, file, line): '${file}:${line}';
|
||||
case Method(classname, method): '${classname}::${method}}';
|
||||
case LocalFunction(v): 'LocalFunction(${v})';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,9 @@ class TraceLogger extends BaseLogger {
|
||||
$print("\n");
|
||||
}
|
||||
#elseif js
|
||||
untyped js.Boot.__trace(v, infos);
|
||||
if (js.Syntax.typeof(untyped console) != "undefined" && (untyped console).log != null)
|
||||
(untyped console).log(v);
|
||||
//untyped js.Boot.__trace(v, infos);
|
||||
#elseif android
|
||||
haxework.log.AndroidLog.write(3, "", ConstCharStar.fromString(Std.string(v)));
|
||||
#elseif (php && php7)
|
||||
|
||||
2017
src/main/yaml/Parser.hx
Normal file
2017
src/main/yaml/Parser.hx
Normal file
File diff suppressed because it is too large
Load Diff
638
src/main/yaml/Renderer.hx
Normal file
638
src/main/yaml/Renderer.hx
Normal file
@@ -0,0 +1,638 @@
|
||||
package yaml;
|
||||
|
||||
import Type;
|
||||
import yaml.util.StringMap;
|
||||
import yaml.util.IntMap;
|
||||
import haxe.Utf8;
|
||||
import haxe.io.Bytes;
|
||||
import yaml.YamlType;
|
||||
import yaml.schema.DefaultSchema;
|
||||
import yaml.schema.SafeSchema;
|
||||
import yaml.util.Strings;
|
||||
import yaml.util.Ints;
|
||||
|
||||
import yaml.YamlException;
|
||||
|
||||
class RenderOptions
|
||||
{
|
||||
public var schema:Schema;
|
||||
public var indent:Int;
|
||||
public var flow:Int;
|
||||
public var styles:StringMap<String>;
|
||||
|
||||
public function new(?schema:Schema, ?styles:StringMap<String>)
|
||||
{
|
||||
this.schema = (schema != null) ? schema : new DefaultSchema();
|
||||
this.styles = (styles != null) ? styles : new StringMap();
|
||||
this.indent = 2;
|
||||
this.flow = -1;
|
||||
}
|
||||
|
||||
public function setSchema(schema:Schema):RenderOptions
|
||||
{
|
||||
this.schema = schema;
|
||||
return this;
|
||||
}
|
||||
|
||||
public function setFlowLevel(level:Int):RenderOptions
|
||||
{
|
||||
this.flow = level;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
The indentation level. Default is 2.
|
||||
*/
|
||||
public function setIndent(indent:Int):RenderOptions
|
||||
{
|
||||
this.indent = indent;
|
||||
return this;
|
||||
}
|
||||
|
||||
public function setStyle(name:String, value:String):RenderOptions
|
||||
{
|
||||
styles.set(name, value);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
class Renderer
|
||||
{
|
||||
/**
|
||||
Utility method to create RenderOptions for configuring a Renderer instance.
|
||||
*/
|
||||
public static function options():RenderOptions
|
||||
{
|
||||
return new RenderOptions();
|
||||
}
|
||||
|
||||
var schema:Schema;
|
||||
var indent:Int;
|
||||
var flowLevel:Int;
|
||||
var styleMap:StringMap<Dynamic>;
|
||||
|
||||
var implicitTypes:Array<AnyYamlType>;
|
||||
var explicitTypes:Array<AnyYamlType>;
|
||||
|
||||
var kind:String;
|
||||
var tag:String;
|
||||
var result:Dynamic;
|
||||
|
||||
public function new()
|
||||
{}
|
||||
|
||||
public function safeRender(input:Dynamic, options:RenderOptions)
|
||||
{
|
||||
options.schema = new SafeSchema();
|
||||
return render(input, options);
|
||||
}
|
||||
|
||||
public function render(input:Dynamic, options:RenderOptions)
|
||||
{
|
||||
schema = options.schema;
|
||||
indent = Std.int(Math.max(1, options.indent));
|
||||
flowLevel = options.flow;
|
||||
styleMap = compileStyleMap(schema, options.styles);
|
||||
|
||||
implicitTypes = schema.compiledImplicit;
|
||||
explicitTypes = schema.compiledExplicit;
|
||||
|
||||
writeNode(0, input, true, true);
|
||||
|
||||
return result + '\n';
|
||||
}
|
||||
|
||||
function generateNextLine(level:Int)
|
||||
{
|
||||
return '\n' + Strings.repeat(' ', indent * level);
|
||||
}
|
||||
|
||||
function testImplicitResolving(object:Dynamic)
|
||||
{
|
||||
for (type in implicitTypes)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!type.loader.skip)
|
||||
{
|
||||
type.resolve(object, false);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch(e:ResolveTypeException) {}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function writeScalar(object:String)
|
||||
{
|
||||
#if sys
|
||||
object = Utf8.encode(object);
|
||||
#end
|
||||
|
||||
var isQuoted = false;
|
||||
var checkpoint = 0;
|
||||
var position = -1;
|
||||
|
||||
result = '';
|
||||
|
||||
if (0 == object.length ||
|
||||
CHAR_SPACE == Utf8.charCodeAt(object, 0) ||
|
||||
CHAR_SPACE == Utf8.charCodeAt(object, Utf8.length(object) - 1))
|
||||
{
|
||||
isQuoted = true;
|
||||
}
|
||||
|
||||
var length = Utf8.length(object);
|
||||
while (++position < length)
|
||||
{
|
||||
var character = Utf8.charCodeAt(object, position);
|
||||
if (!isQuoted)
|
||||
{
|
||||
if (CHAR_TAB == character ||
|
||||
CHAR_LINE_FEED == character ||
|
||||
CHAR_CARRIAGE_RETURN == character ||
|
||||
CHAR_COMMA == character ||
|
||||
CHAR_LEFT_SQUARE_BRACKET == character ||
|
||||
CHAR_RIGHT_SQUARE_BRACKET == character ||
|
||||
CHAR_LEFT_CURLY_BRACKET == character ||
|
||||
CHAR_RIGHT_CURLY_BRACKET == character ||
|
||||
CHAR_SHARP == character ||
|
||||
CHAR_AMPERSAND == character ||
|
||||
CHAR_ASTERISK == character ||
|
||||
CHAR_EXCLAMATION == character ||
|
||||
CHAR_VERTICAL_LINE == character ||
|
||||
CHAR_GREATER_THAN == character ||
|
||||
CHAR_SINGLE_QUOTE == character ||
|
||||
CHAR_DOUBLE_QUOTE == character ||
|
||||
CHAR_PERCENT == character ||
|
||||
CHAR_COMMERCIAL_AT == character ||
|
||||
CHAR_GRAVE_ACCENT == character ||
|
||||
CHAR_QUESTION == character ||
|
||||
CHAR_COLON == character ||
|
||||
CHAR_MINUS == character)
|
||||
{
|
||||
isQuoted = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (ESCAPE_SEQUENCES.exists(character) ||
|
||||
!((0x00020 <= character && character <= 0x00007E) ||
|
||||
(0x00085 == character) ||
|
||||
(0x000A0 <= character && character <= 0x00D7FF) ||
|
||||
(0x0E000 <= character && character <= 0x00FFFD) ||
|
||||
(0x10000 <= character && character <= 0x10FFFF)))
|
||||
{
|
||||
result += yaml.util.Utf8.substring(object, checkpoint, position);
|
||||
|
||||
if (ESCAPE_SEQUENCES.exists(character))
|
||||
{
|
||||
result += ESCAPE_SEQUENCES.get(character);
|
||||
}
|
||||
else
|
||||
{
|
||||
result += encodeHex(character);
|
||||
}
|
||||
|
||||
checkpoint = position + 1;
|
||||
isQuoted = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (checkpoint < position)
|
||||
{
|
||||
result += yaml.util.Utf8.substring(object, checkpoint, position);
|
||||
}
|
||||
|
||||
if (!isQuoted && testImplicitResolving(result))
|
||||
{
|
||||
isQuoted = true;
|
||||
}
|
||||
|
||||
if (isQuoted)
|
||||
{
|
||||
result = '"' + result + '"';
|
||||
}
|
||||
|
||||
#if sys
|
||||
result = Utf8.decode(result);
|
||||
#end
|
||||
}
|
||||
|
||||
function writeFlowSequence(level:Int, object:Array<Dynamic>)
|
||||
{
|
||||
var _result = '';
|
||||
var _tag = tag;
|
||||
|
||||
for (index in 0...object.length)
|
||||
{
|
||||
if (0 != index)
|
||||
_result += ', ';
|
||||
|
||||
writeNode(level, object[index], false, false);
|
||||
_result += result;
|
||||
}
|
||||
|
||||
tag = _tag;
|
||||
result = '[' + _result + ']';
|
||||
}
|
||||
|
||||
function writeBlockSequence(level:Int, object:Array<Dynamic>, compact:Bool)
|
||||
{
|
||||
var _result = '';
|
||||
var _tag = tag;
|
||||
|
||||
for (index in 0...object.length)
|
||||
{
|
||||
if (!compact || 0 != index)
|
||||
_result += generateNextLine(level);
|
||||
|
||||
writeNode(level + 1, object[index], true, true);
|
||||
_result += '- ' + result;
|
||||
}
|
||||
|
||||
tag = _tag;
|
||||
result = _result;
|
||||
}
|
||||
|
||||
function writeFlowMapping(level:Int, object:Dynamic)
|
||||
{
|
||||
if (Type.typeof(object) == ValueType.TObject)
|
||||
writeObjectFlowMapping(level, object);
|
||||
else
|
||||
writeMapFlowMapping(level, object);
|
||||
}
|
||||
|
||||
function writeObjectFlowMapping(level:Int, object:Dynamic)
|
||||
{
|
||||
var _result = '';
|
||||
var _tag = tag;
|
||||
var index = 0;
|
||||
var objectKey;
|
||||
|
||||
for (objectKey in Reflect.fields(object))
|
||||
{
|
||||
if (0 != index++)
|
||||
_result += ', ';
|
||||
|
||||
var objectValue = Reflect.field(object, objectKey);
|
||||
|
||||
writeNode(level, objectKey, false, false);
|
||||
|
||||
if (result.length > 1024)
|
||||
_result += '? ';
|
||||
|
||||
_result += result + ': ';
|
||||
writeNode(level, objectValue, false, false);
|
||||
_result += result;
|
||||
}
|
||||
|
||||
tag = _tag;
|
||||
result = '{' + _result + '}';
|
||||
}
|
||||
|
||||
#if haxe3
|
||||
function writeMapFlowMapping<K,V>(level:Int, object:Map<K,V>)
|
||||
#else
|
||||
function writeMapFlowMapping(level:Int, object:Dynamic)
|
||||
#end
|
||||
{
|
||||
var _result = '';
|
||||
var _tag = tag;
|
||||
var index = 0;
|
||||
var objectKey;
|
||||
var keys:Iterator<Dynamic> = object.keys();
|
||||
|
||||
for (objectKey in keys)
|
||||
{
|
||||
if (0 != index++)
|
||||
_result += ', ';
|
||||
|
||||
var objectValue = object.get(objectKey);
|
||||
|
||||
writeNode(level, objectKey, false, false);
|
||||
|
||||
if (result.length > 1024)
|
||||
_result += '? ';
|
||||
|
||||
_result += result + ': ';
|
||||
writeNode(level, objectValue, false, false);
|
||||
_result += result;
|
||||
}
|
||||
|
||||
tag = _tag;
|
||||
result = '{' + _result + '}';
|
||||
}
|
||||
|
||||
function writeBlockMapping(level:Int, object:Dynamic, compact:Bool)
|
||||
{
|
||||
if (Type.typeof(object) == ValueType.TObject)
|
||||
writeObjectBlockMapping(level, object, compact);
|
||||
else
|
||||
writeMapBlockMapping(level, object, compact);
|
||||
}
|
||||
|
||||
function writeObjectBlockMapping(level:Int, object:Dynamic, compact:Bool)
|
||||
{
|
||||
var _result = '';
|
||||
var _tag = tag;
|
||||
var index = 0;
|
||||
|
||||
for (objectKey in Reflect.fields(object))
|
||||
{
|
||||
if (!compact || 0 != index++)
|
||||
_result += generateNextLine(level);
|
||||
|
||||
var objectValue = Reflect.field(object, objectKey);
|
||||
writeNode(level + 1, objectKey, true, true);
|
||||
var explicitPair = (null != tag && '?' != tag && result.length <= 1024);
|
||||
|
||||
if (explicitPair)
|
||||
_result += '? ';
|
||||
|
||||
_result += result;
|
||||
|
||||
if (explicitPair)
|
||||
_result += generateNextLine(level);
|
||||
|
||||
writeNode(level + 1, objectValue, true, explicitPair);
|
||||
_result += ': ' + result;
|
||||
}
|
||||
|
||||
tag = _tag;
|
||||
result = _result;
|
||||
}
|
||||
|
||||
#if haxe3
|
||||
function writeMapBlockMapping<K,V>(level:Int, object:Map<K,V>, compact:Bool)
|
||||
#else
|
||||
function writeMapBlockMapping(level:Int, object:Dynamic, compact:Bool)
|
||||
#end
|
||||
{
|
||||
var _result = '';
|
||||
var _tag = tag;
|
||||
var index = 0;
|
||||
var keys:Iterator<Dynamic> = object.keys();
|
||||
|
||||
for (objectKey in keys)
|
||||
{
|
||||
if (!compact || 0 != index++)
|
||||
_result += generateNextLine(level);
|
||||
|
||||
var objectValue = object.get(objectKey);
|
||||
writeNode(level + 1, objectKey, true, true);
|
||||
var explicitPair = (null != tag && '?' != tag && result.length <= 1024);
|
||||
|
||||
if (explicitPair)
|
||||
_result += '? ';
|
||||
|
||||
_result += result;
|
||||
|
||||
if (explicitPair)
|
||||
_result += generateNextLine(level);
|
||||
|
||||
writeNode(level + 1, objectValue, true, explicitPair);
|
||||
_result += ': ' + result;
|
||||
}
|
||||
|
||||
tag = _tag;
|
||||
result = _result;
|
||||
}
|
||||
|
||||
function detectType(object:Dynamic, explicit:Bool)
|
||||
{
|
||||
var _result:Dynamic = null;
|
||||
var typeList:Array<AnyYamlType> = explicit ? explicitTypes : implicitTypes;
|
||||
var style:String;
|
||||
|
||||
kind = kindOf(object);
|
||||
|
||||
for (type in typeList)
|
||||
{
|
||||
if ((null != type.dumper) &&
|
||||
type.dumper.skip != true &&
|
||||
(null == type.dumper.kind || kind == type.dumper.kind) &&
|
||||
(null == type.dumper.instanceOf || Std.is(object, type.dumper.instanceOf) &&
|
||||
(null == type.dumper.predicate || type.dumper.predicate(object))))
|
||||
{
|
||||
tag = explicit ? type.tag : '?';
|
||||
|
||||
if (styleMap.exists(type.tag))
|
||||
style = styleMap.get(type.tag);
|
||||
else
|
||||
style = type.dumper.defaultStyle;
|
||||
|
||||
var success = true;
|
||||
try
|
||||
{
|
||||
_result = type.represent(object, style);
|
||||
}
|
||||
catch (e:RepresentTypeException)
|
||||
{
|
||||
success = false;
|
||||
}
|
||||
|
||||
if (success)
|
||||
{
|
||||
kind = kindOf(_result);
|
||||
result = _result;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (explicit)
|
||||
throw new YamlException('cannot represent an object of !<' + type.tag + '> type');
|
||||
else
|
||||
continue;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function writeNode(level:Int, object:Dynamic, block:Bool, compact:Bool)
|
||||
{
|
||||
tag = null;
|
||||
result = object;
|
||||
|
||||
if (!detectType(object, false))
|
||||
detectType(object, true);
|
||||
|
||||
if (block)
|
||||
block = (0 > flowLevel || flowLevel > level);
|
||||
|
||||
if ((null != tag && '?' != tag) || (2 != indent && level > 0))
|
||||
compact = false;
|
||||
|
||||
if ('object' == kind)
|
||||
{
|
||||
var empty = (Type.typeof(object) == ValueType.TObject) ? (Reflect.fields(object).length == 0) : Lambda.empty(object);
|
||||
|
||||
if (block && !empty)
|
||||
{
|
||||
writeBlockMapping(level, object, compact);
|
||||
}
|
||||
else
|
||||
{
|
||||
writeFlowMapping(level, object);
|
||||
}
|
||||
}
|
||||
else if ('array' == kind)
|
||||
{
|
||||
if (block && (0 != result.length))
|
||||
{
|
||||
writeBlockSequence(level, result, compact);
|
||||
}
|
||||
else
|
||||
{
|
||||
writeFlowSequence(level, result);
|
||||
}
|
||||
}
|
||||
else if ('string' == kind)
|
||||
{
|
||||
if ('?' != tag)
|
||||
{
|
||||
writeScalar(result);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new YamlException('unacceptabe kind of an object to dump (' + kind + ')');
|
||||
}
|
||||
|
||||
if (null != tag && '?' != tag)
|
||||
{
|
||||
result = '!<' + tag + '> ' + result;
|
||||
}
|
||||
}
|
||||
|
||||
public function kindOf(object:Dynamic)
|
||||
{
|
||||
var kind = Type.typeof(object);
|
||||
|
||||
return switch (Type.typeof(object))
|
||||
{
|
||||
case TNull: "null";
|
||||
case TInt: "integer";
|
||||
case TFloat: "float";
|
||||
case TBool: "boolean";
|
||||
case TObject:
|
||||
if (Std.is(object, Array)) "array";
|
||||
else "object";
|
||||
case TFunction: "function";
|
||||
case TClass(c):
|
||||
if (c == String) "string";
|
||||
else if (c == Array) "array";
|
||||
else if (c == Bytes) "binary";
|
||||
else "object";
|
||||
case TEnum(_): "enum";
|
||||
case TUnknown: "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static function compileStyleMap(schema:Schema, map:StringMap<Dynamic>):StringMap<Dynamic>
|
||||
{
|
||||
if (null == map)
|
||||
return new StringMap();
|
||||
|
||||
var result = new StringMap<Dynamic>();
|
||||
|
||||
for (tag in map.keys())
|
||||
{
|
||||
var style = Std.string(map.get(tag));
|
||||
|
||||
if (0 == tag.indexOf('!!'))
|
||||
tag = 'tag:yaml.org,2002:' + tag.substring(2);
|
||||
|
||||
var type = schema.compiledTypeMap.get(tag);
|
||||
|
||||
if (type != null && type.dumper != null)
|
||||
{
|
||||
if (type.dumper.styleAliases.exists(style))
|
||||
{
|
||||
style = type.dumper.styleAliases.get(style);
|
||||
}
|
||||
}
|
||||
result.set(tag, style);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static function encodeHex(charCode:Int)
|
||||
{
|
||||
var handle:String;
|
||||
var length:Int;
|
||||
var str = Ints.toString(charCode, 16).toUpperCase();
|
||||
|
||||
if (charCode <= 0xFF)
|
||||
{
|
||||
handle = 'x';
|
||||
length = 2;
|
||||
}
|
||||
else if (charCode <= 0xFFFF)
|
||||
{
|
||||
handle = 'u';
|
||||
length = 4;
|
||||
}
|
||||
else if (charCode <= 0xFFFFFFFF)
|
||||
{
|
||||
handle = 'U';
|
||||
length = 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new YamlException('code point within a string may not be greater than 0xFFFFFFFF');
|
||||
}
|
||||
|
||||
return '\\' + handle + Strings.repeat('0', length - str.length) + str;
|
||||
}
|
||||
|
||||
static inline var CHAR_TAB = 0x09; /* Tab */
|
||||
static inline var CHAR_LINE_FEED = 0x0A; /* LF */
|
||||
static inline var CHAR_CARRIAGE_RETURN = 0x0D; /* CR */
|
||||
static inline var CHAR_SPACE = 0x20; /* Space */
|
||||
static inline var CHAR_EXCLAMATION = 0x21; /* ! */
|
||||
static inline var CHAR_DOUBLE_QUOTE = 0x22; /* " */
|
||||
static inline var CHAR_SHARP = 0x23; /* # */
|
||||
static inline var CHAR_PERCENT = 0x25; /* % */
|
||||
static inline var CHAR_AMPERSAND = 0x26; /* & */
|
||||
static inline var CHAR_SINGLE_QUOTE = 0x27; /* ' */
|
||||
static inline var CHAR_ASTERISK = 0x2A; /* * */
|
||||
static inline var CHAR_COMMA = 0x2C; /* , */
|
||||
static inline var CHAR_MINUS = 0x2D; /* - */
|
||||
static inline var CHAR_COLON = 0x3A; /* : */
|
||||
static inline var CHAR_GREATER_THAN = 0x3E; /* > */
|
||||
static inline var CHAR_QUESTION = 0x3F; /* ? */
|
||||
static inline var CHAR_COMMERCIAL_AT = 0x40; /* @ */
|
||||
static inline var CHAR_LEFT_SQUARE_BRACKET = 0x5B; /* [ */
|
||||
static inline var CHAR_RIGHT_SQUARE_BRACKET = 0x5D; /* ] */
|
||||
static inline var CHAR_GRAVE_ACCENT = 0x60; /* ` */
|
||||
static inline var CHAR_LEFT_CURLY_BRACKET = 0x7B; /* { */
|
||||
static inline var CHAR_VERTICAL_LINE = 0x7C; /* | */
|
||||
static inline var CHAR_RIGHT_CURLY_BRACKET = 0x7D; /* } */
|
||||
static var HEX_VALUES = "0123456789ABCDEF";
|
||||
|
||||
|
||||
static var ESCAPE_SEQUENCES:IntMap<String> =
|
||||
{
|
||||
var hash = new IntMap<String>();
|
||||
hash.set(0x00, '\\0');
|
||||
hash.set(0x07, '\\a');
|
||||
hash.set(0x08, '\\b');
|
||||
hash.set(0x09, '\\t');
|
||||
hash.set(0x0A, '\\n');
|
||||
hash.set(0x0B, '\\v');
|
||||
hash.set(0x0C, '\\f');
|
||||
hash.set(0x0D, '\\r');
|
||||
hash.set(0x1B, '\\e');
|
||||
hash.set(0x22, '\\"');
|
||||
hash.set(0x5C, '\\\\');
|
||||
hash.set(0x85, '\\N');
|
||||
hash.set(0xA0, '\\_');
|
||||
hash.set(0x2028, '\\L');
|
||||
hash.set(0x2029, '\\P');
|
||||
hash;
|
||||
};
|
||||
}
|
||||
95
src/main/yaml/Schema.hx
Normal file
95
src/main/yaml/Schema.hx
Normal file
@@ -0,0 +1,95 @@
|
||||
package yaml;
|
||||
|
||||
import yaml.util.StringMap;
|
||||
import yaml.YamlType;
|
||||
|
||||
class Schema
|
||||
{
|
||||
public static var DEFAULT:Schema;
|
||||
|
||||
public var compiledImplicit:Array<AnyYamlType>;
|
||||
public var compiledExplicit:Array<AnyYamlType>;
|
||||
public var compiledTypeMap:StringMap<AnyYamlType>;
|
||||
|
||||
public var implicit:Array<AnyYamlType>;
|
||||
public var explicit:Array<AnyYamlType>;
|
||||
public var include:Array<Schema>;
|
||||
|
||||
public function new(include:Array<Schema>, explicit:Array<AnyYamlType>, ?implicit:Array<AnyYamlType>)
|
||||
{
|
||||
this.include = (include == null) ? [] : include;
|
||||
this.implicit = (implicit == null) ? [] : implicit;
|
||||
this.explicit = (explicit == null) ? [] : explicit;
|
||||
|
||||
for (type in this.implicit)
|
||||
{
|
||||
if (null != type.loader && 'string' != type.loader.kind)
|
||||
{
|
||||
throw new YamlException('There is a non-scalar type in the implicit list of a schema. Implicit resolving of such types is not supported.');
|
||||
}
|
||||
}
|
||||
|
||||
this.compiledImplicit = compileList(this, 'implicit', []);
|
||||
this.compiledExplicit = compileList(this, 'explicit', []);
|
||||
this.compiledTypeMap = compileMap([this.compiledImplicit, this.compiledExplicit]);
|
||||
}
|
||||
|
||||
public static function create(types:Array<AnyYamlType>, ?schemas:Array<Schema>)
|
||||
{
|
||||
if (schemas == null)
|
||||
schemas = [DEFAULT];
|
||||
else if (schemas.length == 0)
|
||||
schemas.push(DEFAULT);
|
||||
|
||||
return new Schema(schemas, types);
|
||||
}
|
||||
|
||||
|
||||
public static function compileList(schema:Schema, name:String, result:Array<AnyYamlType>)
|
||||
{
|
||||
var exclude = [];
|
||||
|
||||
for (includedSchema in schema.include)
|
||||
{
|
||||
result = compileList(includedSchema, name, result);
|
||||
}
|
||||
|
||||
var types:Array<AnyYamlType> = switch (name)
|
||||
{
|
||||
case "implicit": schema.implicit;
|
||||
case "explicit": schema.explicit;
|
||||
default: throw new YamlException("unknown type list type: " + name);
|
||||
}
|
||||
|
||||
for (currenYamlType in types)
|
||||
{
|
||||
for (previousIndex in 0...result.length)
|
||||
{
|
||||
var previousType = result[previousIndex];
|
||||
if (previousType.tag == currenYamlType.tag)
|
||||
{
|
||||
exclude.push(previousIndex);
|
||||
}
|
||||
}
|
||||
result.push(currenYamlType);
|
||||
}
|
||||
|
||||
var filteredResult:Array<AnyYamlType> = [];
|
||||
for (i in 0...result.length)
|
||||
if (!Lambda.has(exclude, i))
|
||||
filteredResult.push(result[i]);
|
||||
|
||||
return filteredResult;
|
||||
}
|
||||
|
||||
public static function compileMap(list:Array<Array<AnyYamlType>>):StringMap<AnyYamlType>
|
||||
{
|
||||
var result = new StringMap<AnyYamlType>();
|
||||
|
||||
for (member in list)
|
||||
for (type in member)
|
||||
result.set(type.tag, type);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
69
src/main/yaml/Yaml.hx
Normal file
69
src/main/yaml/Yaml.hx
Normal file
@@ -0,0 +1,69 @@
|
||||
package yaml;
|
||||
|
||||
import yaml.Renderer;
|
||||
import yaml.Parser;
|
||||
|
||||
/**
|
||||
Facade for common YAML processing operations.
|
||||
*/
|
||||
class Yaml
|
||||
{
|
||||
/**
|
||||
Parse a yaml document into object form.
|
||||
|
||||
@param document The yaml document to parse.
|
||||
@param ?options Parsing options (optional).
|
||||
|
||||
@return The parsed yaml document in object form.
|
||||
*/
|
||||
public static function parse(document:String, ?options:ParserOptions):Dynamic
|
||||
{
|
||||
if (options == null) options = new ParserOptions();
|
||||
return new Parser().parse(document, options);
|
||||
}
|
||||
|
||||
#if sys
|
||||
/**
|
||||
Read a yaml document from disk and parse into object form.
|
||||
|
||||
@param filePath The path to read the yaml file.
|
||||
@param ?options Parsing options (optional).
|
||||
|
||||
@return The parsed yaml document in object form.
|
||||
*/
|
||||
public static function read(filePath:String, ?options:ParserOptions):Dynamic
|
||||
{
|
||||
return parse(sys.io.File.getContent(filePath), options);
|
||||
}
|
||||
#end
|
||||
|
||||
/**
|
||||
Render a yaml object graph as a yaml text document.
|
||||
|
||||
@param data The root object to render.
|
||||
@param ?options Rendering options (optional).
|
||||
|
||||
@return The rendered yaml document.
|
||||
*/
|
||||
public static function render(data:Dynamic, ?options:RenderOptions):String
|
||||
{
|
||||
if (options == null) options = new RenderOptions();
|
||||
return new Renderer().render(data, options);
|
||||
}
|
||||
|
||||
#if sys
|
||||
/**
|
||||
Render an object graph as a yaml text document and write it to disk.
|
||||
|
||||
@param filePath The path to write the yaml document.
|
||||
@param data The root object to render.
|
||||
@param ?options Rendering options (optional).
|
||||
*/
|
||||
public static function write(filePath:String, data:Dynamic, ?options:RenderOptions):Void
|
||||
{
|
||||
sys.io.File.saveContent(filePath, render(data, options));
|
||||
}
|
||||
#end
|
||||
|
||||
private function new() {}
|
||||
}
|
||||
31
src/main/yaml/YamlException.hx
Normal file
31
src/main/yaml/YamlException.hx
Normal file
@@ -0,0 +1,31 @@
|
||||
package yaml;
|
||||
|
||||
import haxe.PosInfos;
|
||||
|
||||
class YamlException
|
||||
{
|
||||
public var name(get, null):String;
|
||||
function get_name():String { return name; }
|
||||
|
||||
public var message(get, null):String;
|
||||
function get_message():String { return message; }
|
||||
|
||||
public var cause(default, null):Dynamic;
|
||||
public var info(default, null):PosInfos;
|
||||
|
||||
public function new(?message:String="", ?cause:Dynamic = null, ?info:PosInfos)
|
||||
{
|
||||
this.name = Type.getClassName(Type.getClass(this));
|
||||
this.message = message;
|
||||
this.cause = cause;
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
public function toString():String
|
||||
{
|
||||
var str:String = name + ": " + message;
|
||||
if (info != null)
|
||||
str += " at " + info.className + "#" + info.methodName + " (" + info.lineNumber + ")";
|
||||
return str;
|
||||
}
|
||||
}
|
||||
112
src/main/yaml/YamlType.hx
Normal file
112
src/main/yaml/YamlType.hx
Normal file
@@ -0,0 +1,112 @@
|
||||
package yaml;
|
||||
|
||||
import yaml.util.StringMap;
|
||||
import haxe.PosInfos;
|
||||
|
||||
typedef POptions =
|
||||
{
|
||||
?kind:String,
|
||||
?skip:Bool
|
||||
}
|
||||
|
||||
typedef ROptions =
|
||||
{
|
||||
?kind:String,
|
||||
?defaultStyle:String,
|
||||
?instanceOf:Class<Dynamic>,
|
||||
?predicate:Dynamic->Bool,
|
||||
?styleAliases:StringMap<String>,
|
||||
?skip:Bool
|
||||
}
|
||||
|
||||
typedef AnyYamlType = YamlType<Dynamic, Dynamic>;
|
||||
typedef StringYamlType<T> = YamlType<T, String>;
|
||||
|
||||
class YamlType<T, D>
|
||||
{
|
||||
public var tag:String;
|
||||
public var loader:POptions;
|
||||
public var dumper:ROptions;
|
||||
|
||||
public function new(tag:String, loaderOptions:POptions, dumperOptions:ROptions)
|
||||
{
|
||||
if (loaderOptions == null && dumperOptions == null)
|
||||
throw new YamlException('Incomplete YAML type definition. "loader" or "dumper" setting must be specified.');
|
||||
|
||||
this.tag = tag;
|
||||
this.loader = loaderOptions;
|
||||
this.dumper = dumperOptions;
|
||||
|
||||
if (loaderOptions != null && !loaderOptions.skip)
|
||||
validateLoaderOptions();
|
||||
if (dumperOptions != null && !dumperOptions.skip)
|
||||
validateDumperOptions();
|
||||
}
|
||||
|
||||
public function resolve(object:D, ?usingMaps:Bool = true, ?explicit:Bool = false):T
|
||||
{
|
||||
cantResolveType();
|
||||
return null;
|
||||
}
|
||||
|
||||
public function represent(object:T, ?style:String):String
|
||||
{
|
||||
cantRepresentType();
|
||||
return null;
|
||||
}
|
||||
|
||||
function cantResolveType(?info:PosInfos):Dynamic
|
||||
{
|
||||
throw new ResolveTypeException("", null, info);
|
||||
return null;
|
||||
}
|
||||
|
||||
function cantRepresentType(?info:PosInfos):Dynamic
|
||||
{
|
||||
throw new RepresentTypeException("", null, info);
|
||||
return null;
|
||||
}
|
||||
|
||||
function validateLoaderOptions()
|
||||
{
|
||||
if (loader.skip != true && 'string' != loader.kind && 'array' != loader.kind && 'object' != loader.kind)
|
||||
{
|
||||
throw new YamlException('Unacceptable "kind" setting of a type loader: ' + loader.kind);
|
||||
}
|
||||
}
|
||||
|
||||
function validateDumperOptions()
|
||||
{
|
||||
if (dumper.skip != true &&
|
||||
'undefined' != dumper.kind &&
|
||||
'null' != dumper.kind &&
|
||||
'boolean' != dumper.kind &&
|
||||
'integer' != dumper.kind &&
|
||||
'float' != dumper.kind &&
|
||||
'string' != dumper.kind &&
|
||||
'array' != dumper.kind &&
|
||||
'object' != dumper.kind &&
|
||||
'binary' != dumper.kind &&
|
||||
'function' != dumper.kind)
|
||||
{
|
||||
throw new YamlException('Unacceptable "kind" setting of a type dumper: ' + dumper.kind);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ResolveTypeException extends YamlException
|
||||
{
|
||||
public function new(?message:String="", ?cause:Dynamic = null, ?info:PosInfos)
|
||||
{
|
||||
super(message, cause, info);
|
||||
}
|
||||
}
|
||||
|
||||
class RepresentTypeException extends YamlException
|
||||
{
|
||||
public function new(?message:String="", ?cause:Dynamic = null, ?info:PosInfos)
|
||||
{
|
||||
super(message, cause, info);
|
||||
}
|
||||
}
|
||||
|
||||
11
src/main/yaml/schema/DefaultSchema.hx
Normal file
11
src/main/yaml/schema/DefaultSchema.hx
Normal file
@@ -0,0 +1,11 @@
|
||||
package yaml.schema;
|
||||
|
||||
import yaml.Schema;
|
||||
|
||||
class DefaultSchema extends Schema
|
||||
{
|
||||
public function new()
|
||||
{
|
||||
super([new SafeSchema()], null);//[new TRegex(), new TFunction()]);
|
||||
}
|
||||
}
|
||||
14
src/main/yaml/schema/MinimalSchema.hx
Normal file
14
src/main/yaml/schema/MinimalSchema.hx
Normal file
@@ -0,0 +1,14 @@
|
||||
package yaml.schema;
|
||||
|
||||
import yaml.type.YSeq;
|
||||
import yaml.type.YMap;
|
||||
import yaml.type.YString;
|
||||
import yaml.Schema;
|
||||
|
||||
class MinimalSchema extends Schema
|
||||
{
|
||||
public function new()
|
||||
{
|
||||
super([], [new YString(), new YSeq(), new YMap()]);
|
||||
}
|
||||
}
|
||||
24
src/main/yaml/schema/SafeSchema.hx
Normal file
24
src/main/yaml/schema/SafeSchema.hx
Normal file
@@ -0,0 +1,24 @@
|
||||
package yaml.schema;
|
||||
|
||||
import yaml.type.YOmap;
|
||||
import yaml.type.YMerge;
|
||||
import yaml.type.YTimestamp;
|
||||
import yaml.type.YSet;
|
||||
import yaml.type.YPairs;
|
||||
import yaml.type.YInt;
|
||||
import yaml.type.YNull;
|
||||
import yaml.schema.MinimalSchema;
|
||||
import yaml.type.YFloat;
|
||||
import yaml.type.YBool;
|
||||
import yaml.type.YBinary;
|
||||
import yaml.Schema;
|
||||
|
||||
class SafeSchema extends Schema
|
||||
{
|
||||
public function new()
|
||||
{
|
||||
super([new MinimalSchema()],
|
||||
[new YBinary(), new YOmap(), new YPairs(), new YSet()],
|
||||
[new YNull(), new YBool(), new YInt(), new YFloat(), new YTimestamp(), new YMerge()]);
|
||||
}
|
||||
}
|
||||
119
src/main/yaml/type/YBinary.hx
Normal file
119
src/main/yaml/type/YBinary.hx
Normal file
@@ -0,0 +1,119 @@
|
||||
package yaml.type;
|
||||
|
||||
import haxe.io.Bytes;
|
||||
import haxe.Utf8;
|
||||
import yaml.YamlType;
|
||||
|
||||
class YBinary extends yaml.StringYamlType<Bytes>
|
||||
{
|
||||
static inline var BASE64_PADDING_CODE = 0x3D;
|
||||
static inline var BASE64_PADDING_CHAR = '=';
|
||||
|
||||
static var BASE64_BINTABLE = [
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
|
||||
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, 0, -1, -1,
|
||||
-1, 0, 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, -1, -1, -1, -1, -1,
|
||||
-1, 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, -1, -1, -1, -1, -1
|
||||
];
|
||||
|
||||
static var BASE64_CHARTABLE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split('');
|
||||
|
||||
public function new()
|
||||
{
|
||||
super('tag:yaml.org,2002:binary', {kind:"string"}, {kind:"binary", instanceOf:Bytes});
|
||||
}
|
||||
|
||||
override public function resolve(object:String, ?usingMaps:Bool = true, ?explicit:Bool):Bytes
|
||||
{
|
||||
var length = Utf8.length(object);
|
||||
var idx = 0;
|
||||
var result = [];
|
||||
var leftbits = 0; // number of bits decoded, but yet to be appended
|
||||
var leftdata = 0; // bits decoded, but yet to be appended
|
||||
|
||||
// Convert one by one.
|
||||
for (idx in 0...length)
|
||||
{
|
||||
var code = Utf8.charCodeAt(object, idx);
|
||||
var value = BASE64_BINTABLE[code & 0x7F];
|
||||
|
||||
// Skip LF(NL) || CR
|
||||
if (0x0A != code && 0x0D != code)
|
||||
{
|
||||
// Fail on illegal characters
|
||||
if (-1 == value)
|
||||
return cantResolveType();
|
||||
|
||||
// Collect data into leftdata, update bitcount
|
||||
leftdata = (leftdata << 6) | value;
|
||||
leftbits += 6;
|
||||
|
||||
// If we have 8 or more bits, append 8 bits to the result
|
||||
if (leftbits >= 8) {
|
||||
leftbits -= 8;
|
||||
|
||||
// Append if not padding.
|
||||
if (BASE64_PADDING_CODE != code) {
|
||||
result.push((leftdata >> leftbits) & 0xFF);
|
||||
}
|
||||
|
||||
leftdata &= (1 << leftbits) - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If there are any bits left, the base64 string was corrupted
|
||||
if (leftbits != 0)
|
||||
cantResolveType();
|
||||
|
||||
var bytes = Bytes.alloc(result.length);
|
||||
for (i in 0...result.length)
|
||||
bytes.set(i, result[i]);
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
override public function represent(object:Bytes, ?style:String):String
|
||||
{
|
||||
var result = '';
|
||||
var index = 0;
|
||||
var max = object.length - 2;
|
||||
|
||||
// Convert every three bytes to 4 ASCII characters.
|
||||
while (index < max)
|
||||
{
|
||||
result += BASE64_CHARTABLE[object.get(index + 0) >> 2];
|
||||
result += BASE64_CHARTABLE[((object.get(index + 0) & 0x03) << 4) + (object.get(index + 1) >> 4)];
|
||||
result += BASE64_CHARTABLE[((object.get(index + 1) & 0x0F) << 2) + (object.get(index + 2) >> 6)];
|
||||
result += BASE64_CHARTABLE[object.get(index + 2) & 0x3F];
|
||||
index += 3;
|
||||
}
|
||||
|
||||
var rest = object.length % 3;
|
||||
|
||||
// Convert the remaining 1 or 2 bytes, padding out to 4 characters.
|
||||
if (0 != rest)
|
||||
{
|
||||
index = object.length - rest;
|
||||
result += BASE64_CHARTABLE[object.get(index + 0) >> 2];
|
||||
|
||||
if (2 == rest)
|
||||
{
|
||||
result += BASE64_CHARTABLE[((object.get(index + 0) & 0x03) << 4) + (object.get(index + 1) >> 4)];
|
||||
result += BASE64_CHARTABLE[(object.get(index + 1) & 0x0F) << 2];
|
||||
result += BASE64_PADDING_CHAR;
|
||||
}
|
||||
else
|
||||
{
|
||||
result += BASE64_CHARTABLE[(object.get(index + 0) & 0x03) << 4];
|
||||
result += BASE64_PADDING_CODE + BASE64_PADDING_CHAR;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
92
src/main/yaml/type/YBool.hx
Normal file
92
src/main/yaml/type/YBool.hx
Normal file
@@ -0,0 +1,92 @@
|
||||
package yaml.type;
|
||||
|
||||
import yaml.util.StringMap;
|
||||
import yaml.YamlException;
|
||||
import yaml.YamlType;
|
||||
|
||||
class YBool extends StringYamlType<Bool>
|
||||
{
|
||||
static var YAML_IMPLICIT_BOOLEAN_MAP:StringMap<Bool> =
|
||||
{
|
||||
var hash = new StringMap<Bool>();
|
||||
hash.set("true", true);
|
||||
hash.set("True", true);
|
||||
hash.set("TRUE", true);
|
||||
hash.set("false", false);
|
||||
hash.set("False", false);
|
||||
hash.set("FALSE", false);
|
||||
hash;
|
||||
};
|
||||
|
||||
static var YAML_EXPLICIT_BOOLEAN_MAP =
|
||||
{
|
||||
var hash = new StringMap<Bool>();
|
||||
hash.set("true", true);
|
||||
hash.set("True", true);
|
||||
hash.set("TRUE", true);
|
||||
hash.set("false", false);
|
||||
hash.set("False", false);
|
||||
hash.set("FALSE", false);
|
||||
hash.set("y", true);
|
||||
hash.set("Y", true);
|
||||
hash.set("yes", true);
|
||||
hash.set("Yes", true);
|
||||
hash.set("YES", true);
|
||||
hash.set("n", false);
|
||||
hash.set("N", false);
|
||||
hash.set("no", false);
|
||||
hash.set("No", false);
|
||||
hash.set("NO", false);
|
||||
hash.set("on", true);
|
||||
hash.set("On", true);
|
||||
hash.set("ON", true);
|
||||
hash.set("off", false);
|
||||
hash.set("Off", false);
|
||||
hash.set("OFF", false);
|
||||
hash;
|
||||
};
|
||||
|
||||
public function new()
|
||||
{
|
||||
super('tag:yaml.org,2002:bool', {kind:"string"}, {kind:"boolean", defaultStyle:"lowercase"});
|
||||
}
|
||||
|
||||
override public function resolve(object:String, ?usingMaps:Bool = true, ?explicit:Bool):Bool
|
||||
{
|
||||
if (explicit)
|
||||
{
|
||||
if (YAML_EXPLICIT_BOOLEAN_MAP.exists(object))
|
||||
{
|
||||
return YAML_EXPLICIT_BOOLEAN_MAP.get(object);
|
||||
}
|
||||
else
|
||||
{
|
||||
return cantResolveType();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (YAML_IMPLICIT_BOOLEAN_MAP.exists(object))
|
||||
{
|
||||
return YAML_IMPLICIT_BOOLEAN_MAP.get(object);
|
||||
}
|
||||
else
|
||||
{
|
||||
return cantResolveType();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override public function represent(object:Bool, ?style:String):String
|
||||
{
|
||||
return switch (style)
|
||||
{
|
||||
case "uppercase": object ? 'TRUE' : 'FALSE';
|
||||
case "lowercase": object ? 'true' : 'false';
|
||||
case "camelcase": object ? 'True' : 'False';
|
||||
default:
|
||||
throw new YamlException("Style not supported: " + style);
|
||||
null;
|
||||
}
|
||||
}
|
||||
}
|
||||
107
src/main/yaml/type/YFloat.hx
Normal file
107
src/main/yaml/type/YFloat.hx
Normal file
@@ -0,0 +1,107 @@
|
||||
package yaml.type;
|
||||
|
||||
import yaml.YamlType;
|
||||
import yaml.util.Floats;
|
||||
|
||||
class YFloat extends yaml.StringYamlType<Null<Float>>
|
||||
{
|
||||
static var YAML_FLOAT_PATTERN = new EReg(
|
||||
'^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?' +
|
||||
'|\\.[0-9_]+(?:[eE][-+][0-9]+)?' +
|
||||
'|[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*' +
|
||||
'|[-+]?\\.(?:inf|Inf|INF)' +
|
||||
'|\\.(?:nan|NaN|NAN))$', "iu");
|
||||
|
||||
public function new()
|
||||
{
|
||||
super('tag:yaml.org,2002:float', {kind:"string"}, {kind:"float", defaultStyle:"lowercase"});
|
||||
}
|
||||
|
||||
override public function resolve(object:String, ?usingMaps:Bool = true, ?explicit:Bool):Null<Float>
|
||||
{
|
||||
if (!YAML_FLOAT_PATTERN.match(object))
|
||||
cantResolveType();
|
||||
|
||||
var value:String = StringTools.replace(object, '_', '').toLowerCase();
|
||||
var sign = ('-' == value.charAt(0)) ? -1 : 1;
|
||||
|
||||
if (0 <= '+-'.indexOf(value.charAt(0)))
|
||||
{
|
||||
value = value.substr(1);
|
||||
}
|
||||
|
||||
if ('.inf' == value)
|
||||
{
|
||||
return (1 == sign) ? Math.POSITIVE_INFINITY : Math.NEGATIVE_INFINITY;
|
||||
}
|
||||
else if ('.nan' == value)
|
||||
{
|
||||
return Math.NaN;
|
||||
}
|
||||
else if (0 <= value.indexOf(':'))
|
||||
{
|
||||
var digits:Array<Float> = [];
|
||||
for (v in value.split(':'))
|
||||
{
|
||||
digits.unshift(Std.parseFloat(v));
|
||||
}
|
||||
|
||||
var v = 0.0;
|
||||
var base = 1;
|
||||
|
||||
for (d in digits)
|
||||
{
|
||||
v += d * base;
|
||||
base *= 60;
|
||||
}
|
||||
|
||||
return sign * v;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
return sign * Std.parseFloat(value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override public function represent(object:Null<Float>, ?style:String):String
|
||||
{
|
||||
if (Math.isNaN(object))
|
||||
{
|
||||
return switch (style)
|
||||
{
|
||||
case 'lowercase': '.nan';
|
||||
case 'uppercase': '.NAN';
|
||||
case 'camelcase': '.NaN';
|
||||
default: ".nan";
|
||||
}
|
||||
}
|
||||
else if (Math.POSITIVE_INFINITY == object)
|
||||
{
|
||||
return switch (style)
|
||||
{
|
||||
case 'lowercase': '.inf';
|
||||
case 'uppercase': '.INF';
|
||||
case 'camelcase': '.Inf';
|
||||
default: ".inf";
|
||||
}
|
||||
}
|
||||
else if (Math.NEGATIVE_INFINITY == object)
|
||||
{
|
||||
return switch (style)
|
||||
{
|
||||
case 'lowercase': '-.inf';
|
||||
case 'uppercase': '-.INF';
|
||||
case 'camelcase': '-.Inf';
|
||||
default: "-.inf";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return Floats.toString(object);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
103
src/main/yaml/type/YInt.hx
Normal file
103
src/main/yaml/type/YInt.hx
Normal file
@@ -0,0 +1,103 @@
|
||||
package yaml.type;
|
||||
|
||||
import yaml.YamlException;
|
||||
import yaml.util.StringMap;
|
||||
import yaml.util.Ints;
|
||||
import yaml.YamlType;
|
||||
|
||||
class YInt extends yaml.StringYamlType<Null<Int>>
|
||||
{
|
||||
static var YAML_INTEGER_PATTERN = new EReg(
|
||||
'^(?:[-+]?0b[0-1_]+' +
|
||||
'|[-+]?0[0-7_]+' +
|
||||
'|[-+]?(?:0|[1-9][0-9_]*)' +
|
||||
'|[-+]?0x[0-9a-fA-F_]+' +
|
||||
'|[-+]?[1-9][0-9_]*(?::[0-5]?[0-9])+)$', "iu");
|
||||
|
||||
public function new()
|
||||
{
|
||||
super('tag:yaml.org,2002:int', {kind:"string"}, {kind:"integer", defaultStyle:"decimal", styleAliases:createStyleAliases()});
|
||||
}
|
||||
|
||||
function createStyleAliases()
|
||||
{
|
||||
var styleAliases = new StringMap<String>();
|
||||
styleAliases.set('bin', "binary");
|
||||
styleAliases.set('2', "binary");
|
||||
styleAliases.set('oct', "octal");
|
||||
styleAliases.set('8', "octal");
|
||||
styleAliases.set('dec', "decimal");
|
||||
styleAliases.set('hex', "hexadecimal");
|
||||
styleAliases.set('16', "hexadecimal");
|
||||
return styleAliases;
|
||||
}
|
||||
|
||||
override public function resolve(object:String, ?usingMaps:Bool = true, ?explicit:Bool):Null<Int>
|
||||
{
|
||||
if (!YAML_INTEGER_PATTERN.match(object))
|
||||
cantResolveType();
|
||||
|
||||
var value = StringTools.replace(object, '_', '').toLowerCase();
|
||||
var sign = ('-' == value.charAt(0)) ? -1 : 1;
|
||||
var digits = [];
|
||||
|
||||
if (0 <= '+-'.indexOf(value.charAt(0)))
|
||||
{
|
||||
value = value.substr(1);
|
||||
}
|
||||
|
||||
if ('0' == value)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if (value.indexOf("0b") == 0)
|
||||
{
|
||||
return sign * Ints.parseInt(value.substr(2), 2);
|
||||
|
||||
}
|
||||
else if (value.indexOf("0x") == 0)
|
||||
{
|
||||
return sign * Ints.parseInt(value, 16);
|
||||
}
|
||||
else if (value.indexOf("0") == 0)
|
||||
{
|
||||
return sign * Ints.parseInt(value, 8);
|
||||
}
|
||||
else if (0 <= value.indexOf(':')) // base 60
|
||||
{
|
||||
for (v in value.split(':'))
|
||||
{
|
||||
digits.unshift(Ints.parseInt(v, 10));
|
||||
}
|
||||
|
||||
var result = 0;
|
||||
var base = 1;
|
||||
|
||||
for (d in digits)
|
||||
{
|
||||
result += (d * base);
|
||||
base *= 60;
|
||||
}
|
||||
|
||||
return sign * result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return sign * Ints.parseInt(value, 10);
|
||||
}
|
||||
}
|
||||
|
||||
override public function represent(object:Null<Int>, ?style:String):String
|
||||
{
|
||||
return switch (style)
|
||||
{
|
||||
case "binary": '0b' + Ints.toString(object, 2);
|
||||
case "octal": '0' + Ints.toString(object, 8);
|
||||
case "decimal": Ints.toString(object, 10);
|
||||
case "hexadecimal": '0x' + Ints.toString(object, 16);
|
||||
default:
|
||||
throw new YamlException("Style not supported: " + style);
|
||||
null;
|
||||
}
|
||||
}
|
||||
}
|
||||
12
src/main/yaml/type/YMap.hx
Normal file
12
src/main/yaml/type/YMap.hx
Normal file
@@ -0,0 +1,12 @@
|
||||
package yaml.type;
|
||||
|
||||
import yaml.util.ObjectMap;
|
||||
import yaml.YamlType;
|
||||
|
||||
class YMap extends yaml.StringYamlType<Dynamic>
|
||||
{
|
||||
public function new()
|
||||
{
|
||||
super('tag:yaml.org,2002:map', {kind:"object", skip:true}, {skip:true});
|
||||
}
|
||||
}
|
||||
21
src/main/yaml/type/YMerge.hx
Normal file
21
src/main/yaml/type/YMerge.hx
Normal file
@@ -0,0 +1,21 @@
|
||||
package yaml.type;
|
||||
|
||||
import yaml.YamlType;
|
||||
|
||||
class YMerge extends yaml.StringYamlType<String>
|
||||
{
|
||||
public function new()
|
||||
{
|
||||
super('tag:yaml.org,2002:merge', {kind:"string"}, {skip:true});
|
||||
}
|
||||
|
||||
override public function resolve(object:String, ?usingMaps:Bool = true, ?explicit:Bool):String
|
||||
{
|
||||
return ('<<' == object) ? object : cantResolveType();
|
||||
}
|
||||
|
||||
override public function represent(object:String, ?style:String):String
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
38
src/main/yaml/type/YNull.hx
Normal file
38
src/main/yaml/type/YNull.hx
Normal file
@@ -0,0 +1,38 @@
|
||||
package yaml.type;
|
||||
|
||||
import yaml.util.StringMap;
|
||||
import yaml.YamlType;
|
||||
|
||||
class YNull extends yaml.StringYamlType<Dynamic>
|
||||
{
|
||||
static var YAML_NULL_MAP:StringMap<Bool> = {
|
||||
var hash = new StringMap<Bool>();
|
||||
hash.set('~', true);
|
||||
hash.set('null', true);
|
||||
hash.set('Null', true);
|
||||
hash.set('NULL', true);
|
||||
hash;
|
||||
};
|
||||
|
||||
public function new()
|
||||
{
|
||||
super('tag:yaml.org,2002:null', {kind:"string"}, {kind:"null", defaultStyle:"lowercase"});
|
||||
}
|
||||
|
||||
override public function resolve(object:String, ?usingMaps:Bool = true, ?explicit:Bool = false):Dynamic
|
||||
{
|
||||
return YAML_NULL_MAP.exists(object) ? null : cantResolveType();
|
||||
}
|
||||
|
||||
override public function represent(object:Dynamic, ?style:String):String
|
||||
{
|
||||
return switch (style)
|
||||
{
|
||||
case "canonical": "~";
|
||||
case "lowercase": "null";
|
||||
case "uppercase": "NULL";
|
||||
case "camelcase": "Null";
|
||||
default: "~";
|
||||
}
|
||||
}
|
||||
}
|
||||
76
src/main/yaml/type/YOmap.hx
Normal file
76
src/main/yaml/type/YOmap.hx
Normal file
@@ -0,0 +1,76 @@
|
||||
package yaml.type;
|
||||
|
||||
import yaml.util.StringMap;
|
||||
import yaml.util.ObjectMap;
|
||||
import Type;
|
||||
|
||||
class YOmap extends yaml.YamlType<Array<Dynamic>, Array<Dynamic>>
|
||||
{
|
||||
public function new()
|
||||
{
|
||||
super("tag:yaml.org,2002:omap", {kind:"array"}, {skip:true});
|
||||
}
|
||||
|
||||
// For omap this method is only doing a validation that no duplicates are present and that
|
||||
// each pair has only one key. It's not really 'resolving' the value...
|
||||
override public function resolve(object:Array<Dynamic>, ?usingMaps:Bool = true, ?explicit:Bool = false):Array<Dynamic>
|
||||
{
|
||||
usingMaps ? validateOMap(cast object) : validateObjectOMap(object);
|
||||
return object;
|
||||
}
|
||||
|
||||
function validateOMap(object:Array<AnyObjectMap>)
|
||||
{
|
||||
var objectKeys = new ObjectMap<Dynamic, Dynamic>();
|
||||
for (pair in object)
|
||||
{
|
||||
var pairHasKey = false;
|
||||
var pairKey:Dynamic = null;
|
||||
|
||||
if (!Std.is(pair, AnyObjectMap))
|
||||
cantResolveType();
|
||||
|
||||
for (key in pair.keys())
|
||||
{
|
||||
if (pairKey == null) pairKey = key;
|
||||
else cantResolveType(); // can only have one key
|
||||
}
|
||||
|
||||
if (pairKey == null) // must have a key
|
||||
cantResolveType();
|
||||
|
||||
if (objectKeys.exists(pairKey))
|
||||
cantResolveType(); // no duplicate keys allowed
|
||||
else
|
||||
objectKeys.set(pairKey, null);
|
||||
}
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
function validateObjectOMap(object:Array<Dynamic>)
|
||||
{
|
||||
var objectKeys = new StringMap<Dynamic>();
|
||||
for (pair in object)
|
||||
{
|
||||
var pairHasKey = false;
|
||||
var pairKey:String = null;
|
||||
|
||||
if (Type.typeof(pair) != ValueType.TObject)
|
||||
cantResolveType();
|
||||
|
||||
for (key in Reflect.fields(pair))
|
||||
{
|
||||
if (pairKey == null) pairKey = key;
|
||||
else cantResolveType(); // can only have one key
|
||||
}
|
||||
|
||||
if (pairKey == null) // must have a key
|
||||
cantResolveType();
|
||||
|
||||
|
||||
if (objectKeys.exists(pairKey)) cantResolveType(); // no duplicate keys allowed
|
||||
else objectKeys.set(pairKey, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
69
src/main/yaml/type/YPairs.hx
Normal file
69
src/main/yaml/type/YPairs.hx
Normal file
@@ -0,0 +1,69 @@
|
||||
package yaml.type;
|
||||
|
||||
import yaml.util.ObjectMap;
|
||||
import yaml.YamlType;
|
||||
import Type;
|
||||
|
||||
class YPairs extends YamlType<Array<Array<Dynamic>>, Array<Dynamic>>
|
||||
{
|
||||
public function new()
|
||||
{
|
||||
super("tag:yaml.org,2002:pairs", {kind:"array"}, {skip:true});
|
||||
}
|
||||
|
||||
override public function resolve(object:Array<Dynamic>, ?usingMaps:Bool = true, ?explicit:Bool = false):Array<Array<Dynamic>>
|
||||
{
|
||||
if (usingMaps)
|
||||
return resolveMapPair(cast object);
|
||||
else
|
||||
return resolveObjectPair(object);
|
||||
}
|
||||
|
||||
function resolveMapPair(object:Array<AnyObjectMap>)
|
||||
{
|
||||
var result:Array<Array<Dynamic>> = [];
|
||||
for (pair in object)
|
||||
{
|
||||
if (!Std.is(pair, AnyObjectMap))
|
||||
cantResolveType();
|
||||
|
||||
var fieldCount = 0;
|
||||
var keyPair:Dynamic = null;
|
||||
for (key in pair.keys())
|
||||
{
|
||||
keyPair = key;
|
||||
if (fieldCount++ > 1) break;
|
||||
}
|
||||
|
||||
if (fieldCount != 1) // must have one key
|
||||
cantResolveType();
|
||||
|
||||
result.push([keyPair, pair.get(keyPair)]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function resolveObjectPair(object:Array<Dynamic>)
|
||||
{
|
||||
var result:Array<Array<Dynamic>> = [];
|
||||
for (pair in object)
|
||||
{
|
||||
if (Type.typeof(pair) != ValueType.TObject)
|
||||
cantResolveType();
|
||||
|
||||
var fieldCount = 0;
|
||||
var keyPair:Dynamic = null;
|
||||
for (key in Reflect.fields(pair))
|
||||
{
|
||||
keyPair = key;
|
||||
if (fieldCount++ > 1) break;
|
||||
}
|
||||
|
||||
if (fieldCount != 1) // must have one key
|
||||
cantResolveType();
|
||||
|
||||
result.push([keyPair, Reflect.field(pair, keyPair)]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
11
src/main/yaml/type/YSeq.hx
Normal file
11
src/main/yaml/type/YSeq.hx
Normal file
@@ -0,0 +1,11 @@
|
||||
package yaml.type;
|
||||
|
||||
import yaml.YamlType;
|
||||
|
||||
class YSeq extends StringYamlType<Array<Dynamic>>
|
||||
{
|
||||
public function new()
|
||||
{
|
||||
super('tag:yaml.org,2002:seq', {kind:"array", skip:true}, {skip:true});
|
||||
}
|
||||
}
|
||||
33
src/main/yaml/type/YSet.hx
Normal file
33
src/main/yaml/type/YSet.hx
Normal file
@@ -0,0 +1,33 @@
|
||||
package yaml.type;
|
||||
|
||||
import yaml.util.ObjectMap;
|
||||
import yaml.YamlType;
|
||||
|
||||
class YSet extends YamlType<Dynamic, Dynamic>
|
||||
{
|
||||
public function new()
|
||||
{
|
||||
super('tag:yaml.org,2002:set', {kind:"object"}, {skip:true});
|
||||
}
|
||||
|
||||
override public function resolve(object:Dynamic, ?usingMaps:Bool = true, ?explicit:Bool = false):Dynamic
|
||||
{
|
||||
// again this is just validation, not resolving anything.
|
||||
usingMaps ? validateSet(object) : validateObjectSet(object);
|
||||
return object;
|
||||
}
|
||||
|
||||
function validateSet(object:AnyObjectMap)
|
||||
{
|
||||
for (key in object.keys())
|
||||
if (object.get(key) != null)
|
||||
cantResolveType();
|
||||
}
|
||||
|
||||
function validateObjectSet(object:Dynamic)
|
||||
{
|
||||
for (key in Reflect.fields(object))
|
||||
if (Reflect.field(object, key) != null)
|
||||
cantResolveType();
|
||||
}
|
||||
}
|
||||
11
src/main/yaml/type/YString.hx
Normal file
11
src/main/yaml/type/YString.hx
Normal file
@@ -0,0 +1,11 @@
|
||||
package yaml.type;
|
||||
|
||||
import yaml.YamlType;
|
||||
|
||||
class YString extends yaml.StringYamlType<String>
|
||||
{
|
||||
public function new()
|
||||
{
|
||||
super('tag:yaml.org,2002:str', {kind:"string", skip:true}, {skip:true});
|
||||
}
|
||||
}
|
||||
135
src/main/yaml/type/YTimestamp.hx
Normal file
135
src/main/yaml/type/YTimestamp.hx
Normal file
@@ -0,0 +1,135 @@
|
||||
package yaml.type;
|
||||
|
||||
import yaml.YamlType;
|
||||
|
||||
//class TTimestamp extends StringYamlType<Date>
|
||||
class YTimestamp extends YamlType<Date, String>
|
||||
{
|
||||
static var YAML_TIMESTAMP_REGEXP = new EReg(
|
||||
'^([0-9][0-9][0-9][0-9])' + // [1] year
|
||||
'-([0-9][0-9]?)' + // [2] month
|
||||
'-([0-9][0-9]?)' + // [3] day
|
||||
'(?:(?:[Tt]|[ \\t]+)' + // ...
|
||||
'([0-9][0-9]?)' + // [4] hour
|
||||
':([0-9][0-9])' + // [5] minute
|
||||
':([0-9][0-9])' + // [6] second
|
||||
'(?:\\.([0-9]*))?' + // [7] fraction
|
||||
'(?:[ \\t]*(Z|([-+])([0-9][0-9]?)' + // [8] tz [9] tz_sign [10] tz_hour
|
||||
'(?::([0-9][0-9]))?))?)?$', "iu"); // [11] tz_minute
|
||||
|
||||
public function new()
|
||||
{
|
||||
super('tag:yaml.org,2002:timestamp', {kind:"string"}, {kind:"object", instanceOf:Date});
|
||||
}
|
||||
|
||||
override public function resolve(object:String, ?usingMaps:Bool = true, ?explicit:Bool = false):Date
|
||||
{
|
||||
if (!YAML_TIMESTAMP_REGEXP.match(object))
|
||||
cantResolveType();
|
||||
|
||||
// match: [1] year [2] month [3] day
|
||||
var year:Null<Int> = 0;
|
||||
var month:Null<Int> = 0;
|
||||
var day:Null<Int> = 0;
|
||||
var hour:Null<Int> = 0;
|
||||
var minute:Null<Int> = 0;
|
||||
var second:Null<Int> = 0;
|
||||
var fraction:Null<Int> = 0;
|
||||
var delta:Null<Int> = 0;
|
||||
|
||||
try
|
||||
{
|
||||
year = Std.parseInt(YAML_TIMESTAMP_REGEXP.matched(1));
|
||||
month = Std.parseInt(YAML_TIMESTAMP_REGEXP.matched(2)) - 1; // month starts with 0
|
||||
day = Std.parseInt(YAML_TIMESTAMP_REGEXP.matched(3));
|
||||
hour = Std.parseInt(YAML_TIMESTAMP_REGEXP.matched(4));
|
||||
minute = Std.parseInt(YAML_TIMESTAMP_REGEXP.matched(5));
|
||||
second = Std.parseInt(YAML_TIMESTAMP_REGEXP.matched(6));
|
||||
|
||||
// EReg.matched doesn't throw exception under neko for whatever reason so we need to
|
||||
// check for null on each matched call
|
||||
var matched = -1;
|
||||
if (year == null) matched = year = 0;
|
||||
if (month == null) matched = month = 0;
|
||||
if (day == null) matched = day = 0;
|
||||
if (hour == null) matched = hour = 0;
|
||||
if (minute == null) matched = minute = 0;
|
||||
if (second == null) matched = second = 0;
|
||||
|
||||
if (matched == 0)
|
||||
throw "Nothing left to match";
|
||||
|
||||
var msecs = YAML_TIMESTAMP_REGEXP.matched(7);
|
||||
if (msecs == null)
|
||||
throw "Nothing left to match";
|
||||
|
||||
var f = msecs.substring(0, 3);
|
||||
while (f.length < 3)
|
||||
f += '0';
|
||||
|
||||
fraction = Std.parseInt(f);
|
||||
|
||||
if (YAML_TIMESTAMP_REGEXP.matched(9) != null)
|
||||
{
|
||||
var tz_hour:Null<Int> = Std.parseInt(YAML_TIMESTAMP_REGEXP.matched(10));
|
||||
if (tz_hour == null)
|
||||
throw "Nothing left to match";
|
||||
|
||||
var tz_minute:Null<Int> = 0;
|
||||
try {
|
||||
tz_minute = Std.parseInt(YAML_TIMESTAMP_REGEXP.matched(11));
|
||||
if (tz_minute == null)
|
||||
tz_minute = 0;
|
||||
}
|
||||
catch(e:Dynamic) {}
|
||||
|
||||
delta = (tz_hour * 60 + tz_minute) * 60000; // delta in mili-seconds
|
||||
if ('-' == YAML_TIMESTAMP_REGEXP.matched(9))
|
||||
delta = -delta;
|
||||
}
|
||||
}
|
||||
catch(e:Dynamic) {}
|
||||
|
||||
#if (js || flash)
|
||||
var stamp:Float = nativeDate().UTC(year, month, day, hour, minute, second, fraction);
|
||||
|
||||
if (delta != 0)
|
||||
stamp = stamp - delta;
|
||||
|
||||
return Date.fromTime(stamp);
|
||||
|
||||
#else
|
||||
trace("Warning: UTC dates are not supported under this target");
|
||||
|
||||
var date = new Date(year, month, day, hour, minute, second);
|
||||
// if (delta != 0)
|
||||
// stamp = stamp - delta;
|
||||
return date;
|
||||
#end
|
||||
}
|
||||
|
||||
#if (flash || js)
|
||||
static function nativeDate():Dynamic
|
||||
{
|
||||
#if flash9
|
||||
return untyped __global__["Date"];
|
||||
#elseif flash
|
||||
return untyped _global["Date"];
|
||||
#elseif js
|
||||
return untyped __js__("Date");
|
||||
#end
|
||||
return null;
|
||||
}
|
||||
#end
|
||||
|
||||
override public function represent(object:Date, ?style:String):String
|
||||
{
|
||||
#if (flash || js)
|
||||
return yaml.util.Dates.toISOString(object);
|
||||
#else
|
||||
trace("Warning: UTC dates are not supported under this target");
|
||||
return object.toString();
|
||||
#end
|
||||
|
||||
}
|
||||
}
|
||||
69
src/main/yaml/util/Dates.hx
Normal file
69
src/main/yaml/util/Dates.hx
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
Copyright (c) 2012 Massive Interactive
|
||||
|
||||
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 yaml.util;
|
||||
|
||||
/**
|
||||
Utility methods for working with dates
|
||||
*/
|
||||
class Dates
|
||||
{
|
||||
#if (flash || js)
|
||||
|
||||
static function getNativeDate():Dynamic
|
||||
{
|
||||
#if flash9
|
||||
return untyped __global__["Date"];
|
||||
#elseif flash
|
||||
return untyped _global["Date"];
|
||||
#elseif js
|
||||
return untyped __js__("Date");
|
||||
#end
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
Converts a Date to UTC ISO-8601 compliant string.
|
||||
|
||||
Example: 2012-06-20T12:11:08.188Z
|
||||
|
||||
Currently only supported under JS, AS3 and AS2.
|
||||
|
||||
@param date the date to convert to utc iso string
|
||||
@return ISO-8601 compliant timestamp
|
||||
*/
|
||||
public static function toISOString(date:Date):String
|
||||
{
|
||||
var NativeDate = getNativeDate();
|
||||
var d = untyped __new__(NativeDate, date.getTime());
|
||||
|
||||
return d.getUTCFullYear() + '-'
|
||||
+ StringTools.lpad("" + (d.getUTCMonth() + 1), "0", 2) + '-'
|
||||
+ StringTools.lpad("" + d.getUTCDate(), "0", 2) + 'T'
|
||||
+ StringTools.lpad("" + d.getUTCHours(), "0", 2) + ':'
|
||||
+ StringTools.lpad("" + d.getUTCMinutes(), "0", 2) + ':'
|
||||
+ StringTools.lpad("" + d.getUTCSeconds(), "0", 2) + '.'
|
||||
+ StringTools.rpad(("" + (Floats.round(d.getUTCMilliseconds()/1000, 3))).substr(2, 5), "0", 3)
|
||||
+ 'Z';
|
||||
}
|
||||
#end
|
||||
}
|
||||
69
src/main/yaml/util/Floats.hx
Normal file
69
src/main/yaml/util/Floats.hx
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
Copyright (c) 2012 Massive Interactive
|
||||
|
||||
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 yaml.util;
|
||||
|
||||
/**
|
||||
Utility methods for working with float values.
|
||||
*/
|
||||
class Floats
|
||||
{
|
||||
/**
|
||||
Returns the string representation of a float.
|
||||
|
||||
Under cpp will convert large floats with a positive exponent (eg date.getTime()) to a decimal string.
|
||||
e.g 1.347420344e+12 -> 1347420344000
|
||||
*/
|
||||
public static function toString(value:Float):String
|
||||
{
|
||||
#if cpp
|
||||
var str = Std.string(value);
|
||||
if (str.indexOf("e+") != -1)
|
||||
{
|
||||
var parts = str.split(".");
|
||||
var exp = parts[1].split("e+");
|
||||
str = parts[0] + StringTools.rpad(exp[0], "0", Std.parseInt(exp[1]));
|
||||
}
|
||||
return str;
|
||||
#else
|
||||
return Std.string(value);
|
||||
#end
|
||||
}
|
||||
|
||||
/**
|
||||
Rounds a value to a specific decimal precision
|
||||
|
||||
Example:
|
||||
<pre>
|
||||
FloatUtil.round(1.6666667 3);//returns 1.667;
|
||||
</pre>
|
||||
|
||||
@param value value to round
|
||||
@param precision precision in decimals
|
||||
@return the rounded value
|
||||
*/
|
||||
static public function round(value:Float, precision:Int):Float
|
||||
{
|
||||
value = value * Math.pow(10, precision);
|
||||
return Math.round(value) / Math.pow(10, precision);
|
||||
}
|
||||
}
|
||||
7
src/main/yaml/util/IntMap.hx
Normal file
7
src/main/yaml/util/IntMap.hx
Normal file
@@ -0,0 +1,7 @@
|
||||
package yaml.util;
|
||||
|
||||
#if haxe3
|
||||
typedef IntMap<T> = haxe.ds.IntMap<T>;
|
||||
#else
|
||||
typedef IntMap<T> = IntHash<T>;
|
||||
#end
|
||||
167
src/main/yaml/util/Ints.hx
Normal file
167
src/main/yaml/util/Ints.hx
Normal file
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
Copyright (c) 2012 Massive Interactive
|
||||
|
||||
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 yaml.util;
|
||||
|
||||
/**
|
||||
Utility methods for working with int values.
|
||||
*/
|
||||
class Ints
|
||||
{
|
||||
// Base used for toString/parseInt conversions. Supporting base 2 to 36 for now as common standard.
|
||||
static var BASE = "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
/**
|
||||
Returns the string representation of an integer value based on an optional radix (base).
|
||||
|
||||
A default base of 10 is used if none is supplied.
|
||||
|
||||
A base below 2 or above 36 will cause an exception.
|
||||
|
||||
@param value The integer value to return the string representation of.
|
||||
@param radix An integer between 2 and 36 to be used as the base for conversion. Defaults to 10.
|
||||
@return The string representation of the integer at the defined radix.
|
||||
*/
|
||||
public static function toString(value:Int, ?radix:Int = 10):String
|
||||
{
|
||||
if (radix < 2 || radix > BASE.length)
|
||||
throw "Unsupported radix " + radix;
|
||||
|
||||
#if (js || flash)
|
||||
|
||||
return untyped value.toString(radix);
|
||||
|
||||
#else
|
||||
|
||||
if (radix == 10) return Std.string(value);
|
||||
else if (value == 0) return '0';
|
||||
else // do the conversion ourselves
|
||||
{
|
||||
var sign = "";
|
||||
if (value < 0)
|
||||
{
|
||||
sign = '-';
|
||||
value = -value;
|
||||
}
|
||||
|
||||
var result = '';
|
||||
while (value > 0)
|
||||
{
|
||||
result = BASE.charAt(value % radix) + result;
|
||||
value = Std.int(value / radix);
|
||||
}
|
||||
|
||||
return sign + result;
|
||||
}
|
||||
|
||||
#end
|
||||
}
|
||||
|
||||
/**
|
||||
Parses a string and returns the decimal integer value it represents or `null` if no value could be parsed.
|
||||
|
||||
An optional radix can be supplied to indicate the base the value should be parsed under.
|
||||
If no base is supplied a base of 10 will be assumed, unless the value begins with '0x', in which case
|
||||
a base of 16 (hex) is assumed.
|
||||
|
||||
Parsing continues until complete or an invalid char is found. In that case the value parsed up until that point
|
||||
is returned. e.g. `parseInt("44dae", 10)` returns `44`.
|
||||
|
||||
The reason for returning `null` instead of `Math.NaN` when parsing fails completely is that NaN is a Float which
|
||||
would force the return type to also be Float. This would mean `var a:Int = parseInt(value)` would become invalid,
|
||||
which is unintuitive. A return type of Dynamic would fix this on most systems, but not flash (avm2) which
|
||||
will auto cast the Float to an Int meaning Math.isNaN test would always fail.
|
||||
|
||||
@param value The value to parse into an integer
|
||||
@param radix The radix to base the conversion on. Default is 16 for string starting with '0x' otherwise 10.
|
||||
@return The decimal integer value which the supplied string represents, or null if it could not be parsed.
|
||||
*/
|
||||
public static function parseInt(value:String, ?radix:Null<Int>):Null<Int>
|
||||
{
|
||||
if (radix != null && (radix < 2 || radix > BASE.length))
|
||||
throw "Unsupported radix " + radix;
|
||||
|
||||
#if js
|
||||
|
||||
var v = untyped __js__("parseInt")(value, radix);
|
||||
return (untyped __js__("isNaN")(v)) ? null : v;
|
||||
|
||||
#elseif flash9
|
||||
|
||||
if (radix == null) radix = 0;
|
||||
var v = untyped __global__["parseInt"](value, radix);
|
||||
return (untyped __global__["isNaN"](v)) ? null : v;
|
||||
|
||||
#elseif flash8
|
||||
|
||||
var v = _global["parseInt"](value, radix);
|
||||
return _global["isNaN"](v) ? null : v;
|
||||
|
||||
#else // do the conversion ourselves
|
||||
|
||||
value = StringTools.trim(value).toLowerCase();
|
||||
|
||||
if (value.length == 0)
|
||||
return null;
|
||||
|
||||
var s = 0;
|
||||
var neg = false;
|
||||
if (value.indexOf("-") == 0)
|
||||
{
|
||||
neg = true;
|
||||
s = 1;
|
||||
}
|
||||
else if (value.indexOf("+") == 0)
|
||||
{
|
||||
s = 1;
|
||||
}
|
||||
|
||||
if (s == 1 && value.length == 1)
|
||||
return null;
|
||||
|
||||
var j = value.indexOf("0x");
|
||||
if ((j == 0 || (j == 1 && s == 1)) && (radix == null || radix == 16))
|
||||
{
|
||||
s += 2;
|
||||
if (radix == null) radix = 16;
|
||||
}
|
||||
else if (radix == null)
|
||||
{
|
||||
radix = 10;
|
||||
}
|
||||
|
||||
var result = 0;
|
||||
for (i in s...value.length)
|
||||
{
|
||||
var x = BASE.indexOf(value.charAt(i));
|
||||
if (x == -1 || x >= radix)
|
||||
{
|
||||
if (i == s) return null;
|
||||
else return neg ? -result : result;
|
||||
}
|
||||
result = (result * radix) + x;
|
||||
}
|
||||
|
||||
return neg ? -result : result;
|
||||
#end
|
||||
}
|
||||
}
|
||||
103
src/main/yaml/util/ObjectMap.hx
Normal file
103
src/main/yaml/util/ObjectMap.hx
Normal file
@@ -0,0 +1,103 @@
|
||||
package yaml.util;
|
||||
|
||||
/// Wanted to use haxe.ds.ObjectMap under haxe3 but it doesn't support primitive keys on all targets so
|
||||
/// we'll use our own TObjectMap instead.
|
||||
|
||||
//#if haxe3
|
||||
//under haxe 3 use built in map for speed, even though this prevents us using a null key.
|
||||
//typedef ObjectMap<K:{}, V> = haxe.ds.ObjectMap<K, V>;
|
||||
//typedef AnyObjectMap = ObjectMap<{}, Dynamic>;
|
||||
//#else
|
||||
typedef ObjectMap<K, V> = TObjectMap<K, V>;
|
||||
typedef AnyObjectMap = ObjectMap<Dynamic, Dynamic>;
|
||||
|
||||
/**
|
||||
Cross platform object map which also supports the option of one null key.
|
||||
*/
|
||||
class TObjectMap<K, V>
|
||||
{
|
||||
var _keys:Array<K>;
|
||||
var values:Array<V>;
|
||||
|
||||
public function new(?weakKeys:Bool = false)
|
||||
{
|
||||
_keys = [];
|
||||
values = [];
|
||||
}
|
||||
|
||||
public function set(key:K, value:V):Void
|
||||
{
|
||||
for (i in 0..._keys.length)
|
||||
{
|
||||
if (_keys[i] == key)
|
||||
{
|
||||
_keys[i] = key;
|
||||
values[i] = value;
|
||||
return;
|
||||
}
|
||||
}
|
||||
_keys.push(key);
|
||||
values.push(value);
|
||||
}
|
||||
|
||||
public function get(key:K):Null<V>
|
||||
{
|
||||
for (i in 0..._keys.length)
|
||||
{
|
||||
if (_keys[i] == key)
|
||||
return values[i];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function exists(key:K):Bool
|
||||
{
|
||||
for (k in _keys)
|
||||
if (k == key)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public function remove(key:K):Bool
|
||||
{
|
||||
for (i in 0..._keys.length)
|
||||
{
|
||||
if (_keys[i] == key)
|
||||
{
|
||||
_keys.splice(i, 1);
|
||||
values.splice(i, 1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function keys():Iterator<K>
|
||||
{
|
||||
return _keys.iterator();
|
||||
}
|
||||
|
||||
public function iterator():Iterator<V>
|
||||
{
|
||||
return values.iterator();
|
||||
}
|
||||
|
||||
public function toString():String
|
||||
{
|
||||
var s = "{";
|
||||
var ks:Dynamic = _keys;
|
||||
var vs:Dynamic = values;
|
||||
for (i in 0..._keys.length)
|
||||
{
|
||||
var k = (Std.is(ks[i], Array)) ? "[" + ks[i] + "]" : ks[i];
|
||||
var v = (Std.is(vs[i], Array)) ? "[" + vs[i] + "]" : vs[i];
|
||||
s += k + " => " + v + ", ";
|
||||
}
|
||||
|
||||
if (_keys.length > 0)
|
||||
s = s.substr(0, s.length - 2);
|
||||
|
||||
return s + "}";
|
||||
}
|
||||
}
|
||||
//#end
|
||||
7
src/main/yaml/util/StringMap.hx
Normal file
7
src/main/yaml/util/StringMap.hx
Normal file
@@ -0,0 +1,7 @@
|
||||
package yaml.util;
|
||||
|
||||
#if haxe3
|
||||
typedef StringMap<T> = haxe.ds.StringMap<T>;
|
||||
#else
|
||||
typedef StringMap<T> = Hash<T>;
|
||||
#end
|
||||
40
src/main/yaml/util/Strings.hx
Normal file
40
src/main/yaml/util/Strings.hx
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
Copyright (c) 2012 Massive Interactive
|
||||
|
||||
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 yaml.util;
|
||||
|
||||
/**
|
||||
Utility methods for working with strings.
|
||||
*/
|
||||
class Strings
|
||||
{
|
||||
/**
|
||||
Concatenate a source string with itself N number of times.
|
||||
*/
|
||||
public static function repeat(source:String, times:Int):String
|
||||
{
|
||||
var result = "";
|
||||
for (i in 0...times)
|
||||
result += source;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
27
src/main/yaml/util/Utf8.hx
Normal file
27
src/main/yaml/util/Utf8.hx
Normal file
@@ -0,0 +1,27 @@
|
||||
package yaml.util;
|
||||
|
||||
class Utf8
|
||||
{
|
||||
public static function substring(value:String, startIndex:Int, ?endIndex:Null<Int>):String
|
||||
{
|
||||
var size = haxe.Utf8.length(value);
|
||||
var pos = startIndex;
|
||||
var length = 0;
|
||||
|
||||
if (endIndex == null)
|
||||
{
|
||||
length = size - pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (startIndex > endIndex)
|
||||
{
|
||||
pos = endIndex;
|
||||
endIndex = startIndex;
|
||||
}
|
||||
length = endIndex - pos;
|
||||
}
|
||||
|
||||
return haxe.Utf8.sub(value, pos, length);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user