Begin transition of Babel to a more scalable architecture, async flow to allow for RPC and better build system for multiple packages
This commit is contained in:
823
src/plugins/flow.js
Normal file
823
src/plugins/flow.js
Normal file
@@ -0,0 +1,823 @@
|
||||
import { types as tt } from "../tokentype";
|
||||
import { Parser } from "../state";
|
||||
|
||||
var pp = Parser.prototype;
|
||||
|
||||
pp.isRelational = function (op) {
|
||||
return this.type === tt.relational && this.value === op;
|
||||
};
|
||||
|
||||
pp.expectRelational = function (op) {
|
||||
if (this.isRelational(op)) {
|
||||
this.next();
|
||||
} else {
|
||||
this.unexpected();
|
||||
}
|
||||
};
|
||||
|
||||
pp.flowParseTypeInitialiser = function (tok) {
|
||||
var oldInType = this.inType;
|
||||
this.inType = true;
|
||||
this.expect(tok || tt.colon);
|
||||
var type = this.flowParseType();
|
||||
this.inType = oldInType;
|
||||
return type;
|
||||
};
|
||||
|
||||
pp.flowParseDeclareClass = function (node) {
|
||||
this.next();
|
||||
this.flowParseInterfaceish(node, true);
|
||||
return this.finishNode(node, "DeclareClass");
|
||||
};
|
||||
|
||||
pp.flowParseDeclareFunction = function (node) {
|
||||
this.next();
|
||||
|
||||
var id = node.id = this.parseIdent();
|
||||
|
||||
var typeNode = this.startNode();
|
||||
var typeContainer = this.startNode();
|
||||
|
||||
if (this.isRelational("<")) {
|
||||
typeNode.typeParameters = this.flowParseTypeParameterDeclaration();
|
||||
} else {
|
||||
typeNode.typeParameters = null;
|
||||
}
|
||||
|
||||
this.expect(tt.parenL);
|
||||
var tmp = this.flowParseFunctionTypeParams();
|
||||
typeNode.params = tmp.params;
|
||||
typeNode.rest = tmp.rest;
|
||||
this.expect(tt.parenR);
|
||||
typeNode.returnType = this.flowParseTypeInitialiser();
|
||||
|
||||
typeContainer.typeAnnotation = this.finishNode(typeNode, "FunctionTypeAnnotation");
|
||||
id.typeAnnotation = this.finishNode(typeContainer, "TypeAnnotation");
|
||||
|
||||
this.finishNode(id, id.type);
|
||||
|
||||
this.semicolon();
|
||||
|
||||
return this.finishNode(node, "DeclareFunction");
|
||||
};
|
||||
|
||||
pp.flowParseDeclare = function (node) {
|
||||
if (this.type === tt._class) {
|
||||
return this.flowParseDeclareClass(node);
|
||||
} else if (this.type === tt._function) {
|
||||
return this.flowParseDeclareFunction(node);
|
||||
} else if (this.type === tt._var) {
|
||||
return this.flowParseDeclareVariable(node);
|
||||
} else if (this.isContextual("module")) {
|
||||
return this.flowParseDeclareModule(node);
|
||||
} else {
|
||||
this.unexpected();
|
||||
}
|
||||
};
|
||||
|
||||
pp.flowParseDeclareVariable = function (node) {
|
||||
this.next();
|
||||
node.id = this.flowParseTypeAnnotatableIdentifier();
|
||||
this.semicolon();
|
||||
return this.finishNode(node, "DeclareVariable");
|
||||
};
|
||||
|
||||
pp.flowParseDeclareModule = function (node) {
|
||||
this.next();
|
||||
|
||||
if (this.type === tt.string) {
|
||||
node.id = this.parseExprAtom();
|
||||
} else {
|
||||
node.id = this.parseIdent();
|
||||
}
|
||||
|
||||
var bodyNode = node.body = this.startNode();
|
||||
var body = bodyNode.body = [];
|
||||
this.expect(tt.braceL);
|
||||
while (this.type !== tt.braceR) {
|
||||
var node2 = this.startNode();
|
||||
|
||||
// todo: declare check
|
||||
this.next();
|
||||
|
||||
body.push(this.flowParseDeclare(node2));
|
||||
}
|
||||
this.expect(tt.braceR);
|
||||
|
||||
this.finishNode(bodyNode, "BlockStatement");
|
||||
return this.finishNode(node, "DeclareModule");
|
||||
};
|
||||
|
||||
|
||||
// Interfaces
|
||||
|
||||
pp.flowParseInterfaceish = function (node, allowStatic) {
|
||||
node.id = this.parseIdent();
|
||||
|
||||
if (this.isRelational("<")) {
|
||||
node.typeParameters = this.flowParseTypeParameterDeclaration();
|
||||
} else {
|
||||
node.typeParameters = null;
|
||||
}
|
||||
|
||||
node.extends = [];
|
||||
|
||||
if (this.eat(tt._extends)) {
|
||||
do {
|
||||
node.extends.push(this.flowParseInterfaceExtends());
|
||||
} while(this.eat(tt.comma));
|
||||
}
|
||||
|
||||
node.body = this.flowParseObjectType(allowStatic);
|
||||
};
|
||||
|
||||
pp.flowParseInterfaceExtends = function () {
|
||||
var node = this.startNode();
|
||||
|
||||
node.id = this.parseIdent();
|
||||
if (this.isRelational("<")) {
|
||||
node.typeParameters = this.flowParseTypeParameterInstantiation();
|
||||
} else {
|
||||
node.typeParameters = null;
|
||||
}
|
||||
|
||||
return this.finishNode(node, "InterfaceExtends");
|
||||
};
|
||||
|
||||
pp.flowParseInterface = function (node) {
|
||||
this.flowParseInterfaceish(node, false);
|
||||
return this.finishNode(node, "InterfaceDeclaration");
|
||||
};
|
||||
|
||||
// Type aliases
|
||||
|
||||
pp.flowParseTypeAlias = function (node) {
|
||||
node.id = this.parseIdent();
|
||||
|
||||
if (this.isRelational("<")) {
|
||||
node.typeParameters = this.flowParseTypeParameterDeclaration();
|
||||
} else {
|
||||
node.typeParameters = null;
|
||||
}
|
||||
|
||||
node.right = this.flowParseTypeInitialiser(tt.eq);
|
||||
this.semicolon();
|
||||
|
||||
return this.finishNode(node, "TypeAlias");
|
||||
};
|
||||
|
||||
// Type annotations
|
||||
|
||||
pp.flowParseTypeParameterDeclaration = function () {
|
||||
var node = this.startNode();
|
||||
node.params = [];
|
||||
|
||||
this.expectRelational("<");
|
||||
while (!this.isRelational(">")) {
|
||||
node.params.push(this.flowParseTypeAnnotatableIdentifier());
|
||||
if (!this.isRelational(">")) {
|
||||
this.expect(tt.comma);
|
||||
}
|
||||
}
|
||||
this.expectRelational(">");
|
||||
|
||||
return this.finishNode(node, "TypeParameterDeclaration");
|
||||
};
|
||||
|
||||
pp.flowParseTypeParameterInstantiation = function () {
|
||||
var node = this.startNode(), oldInType = this.inType;
|
||||
node.params = [];
|
||||
|
||||
this.inType = true;
|
||||
|
||||
this.expectRelational("<");
|
||||
while (!this.isRelational(">")) {
|
||||
node.params.push(this.flowParseType());
|
||||
if (!this.isRelational(">")) {
|
||||
this.expect(tt.comma);
|
||||
}
|
||||
}
|
||||
this.expectRelational(">");
|
||||
|
||||
this.inType = oldInType;
|
||||
|
||||
return this.finishNode(node, "TypeParameterInstantiation");
|
||||
};
|
||||
|
||||
pp.flowParseObjectPropertyKey = function () {
|
||||
return (this.type === tt.num || this.type === tt.string) ? this.parseExprAtom() : this.parseIdent(true);
|
||||
};
|
||||
|
||||
pp.flowParseObjectTypeIndexer = function (node, isStatic) {
|
||||
node.static = isStatic;
|
||||
|
||||
this.expect(tt.bracketL);
|
||||
node.id = this.flowParseObjectPropertyKey();
|
||||
node.key = this.flowParseTypeInitialiser();
|
||||
this.expect(tt.bracketR);
|
||||
node.value = this.flowParseTypeInitialiser();
|
||||
|
||||
this.flowObjectTypeSemicolon();
|
||||
return this.finishNode(node, "ObjectTypeIndexer");
|
||||
};
|
||||
|
||||
pp.flowParseObjectTypeMethodish = function (node) {
|
||||
node.params = [];
|
||||
node.rest = null;
|
||||
node.typeParameters = null;
|
||||
|
||||
if (this.isRelational("<")) {
|
||||
node.typeParameters = this.flowParseTypeParameterDeclaration();
|
||||
}
|
||||
|
||||
this.expect(tt.parenL);
|
||||
while (this.type === tt.name) {
|
||||
node.params.push(this.flowParseFunctionTypeParam());
|
||||
if (this.type !== tt.parenR) {
|
||||
this.expect(tt.comma);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.eat(tt.ellipsis)) {
|
||||
node.rest = this.flowParseFunctionTypeParam();
|
||||
}
|
||||
this.expect(tt.parenR);
|
||||
node.returnType = this.flowParseTypeInitialiser();
|
||||
|
||||
return this.finishNode(node, "FunctionTypeAnnotation");
|
||||
};
|
||||
|
||||
pp.flowParseObjectTypeMethod = function (startPos, startLoc, isStatic, key) {
|
||||
var node = this.startNodeAt(startPos, startLoc);
|
||||
node.value = this.flowParseObjectTypeMethodish(this.startNodeAt(startPos, startLoc));
|
||||
node.static = isStatic;
|
||||
node.key = key;
|
||||
node.optional = false;
|
||||
this.flowObjectTypeSemicolon();
|
||||
return this.finishNode(node, "ObjectTypeProperty");
|
||||
};
|
||||
|
||||
pp.flowParseObjectTypeCallProperty = function (node, isStatic) {
|
||||
var valueNode = this.startNode();
|
||||
node.static = isStatic;
|
||||
node.value = this.flowParseObjectTypeMethodish(valueNode);
|
||||
this.flowObjectTypeSemicolon();
|
||||
return this.finishNode(node, "ObjectTypeCallProperty");
|
||||
};
|
||||
|
||||
pp.flowParseObjectType = function (allowStatic) {
|
||||
var nodeStart = this.startNode();
|
||||
var node;
|
||||
var optional = false;
|
||||
var propertyKey;
|
||||
var isStatic;
|
||||
|
||||
nodeStart.callProperties = [];
|
||||
nodeStart.properties = [];
|
||||
nodeStart.indexers = [];
|
||||
|
||||
this.expect(tt.braceL);
|
||||
|
||||
while (this.type !== tt.braceR) {
|
||||
var startPos = this.start, startLoc = this.startLoc;
|
||||
node = this.startNode();
|
||||
if (allowStatic && this.isContextual("static")) {
|
||||
this.next();
|
||||
isStatic = true;
|
||||
}
|
||||
|
||||
if (this.type === tt.bracketL) {
|
||||
nodeStart.indexers.push(this.flowParseObjectTypeIndexer(node, isStatic));
|
||||
} else if (this.type === tt.parenL || this.isRelational("<")) {
|
||||
nodeStart.callProperties.push(this.flowParseObjectTypeCallProperty(node, allowStatic));
|
||||
} else {
|
||||
if (isStatic && this.type === tt.colon) {
|
||||
propertyKey = this.parseIdent();
|
||||
} else {
|
||||
propertyKey = this.flowParseObjectPropertyKey();
|
||||
}
|
||||
if (this.isRelational("<") || this.type === tt.parenL) {
|
||||
// This is a method property
|
||||
nodeStart.properties.push(this.flowParseObjectTypeMethod(startPos, startLoc, isStatic, propertyKey));
|
||||
} else {
|
||||
if (this.eat(tt.question)) {
|
||||
optional = true;
|
||||
}
|
||||
node.key = propertyKey;
|
||||
node.value = this.flowParseTypeInitialiser();
|
||||
node.optional = optional;
|
||||
node.static = isStatic;
|
||||
this.flowObjectTypeSemicolon();
|
||||
nodeStart.properties.push(this.finishNode(node, "ObjectTypeProperty"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.expect(tt.braceR);
|
||||
|
||||
return this.finishNode(nodeStart, "ObjectTypeAnnotation");
|
||||
};
|
||||
|
||||
pp.flowObjectTypeSemicolon = function () {
|
||||
if (!this.eat(tt.semi) && !this.eat(tt.comma) && this.type !== tt.braceR) {
|
||||
this.unexpected();
|
||||
}
|
||||
};
|
||||
|
||||
pp.flowParseGenericType = function (startPos, startLoc, id) {
|
||||
var node = this.startNodeAt(startPos, startLoc);
|
||||
|
||||
node.typeParameters = null;
|
||||
node.id = id;
|
||||
|
||||
while (this.eat(tt.dot)) {
|
||||
var node2 = this.startNodeAt(startPos, startLoc);
|
||||
node2.qualification = node.id;
|
||||
node2.id = this.parseIdent();
|
||||
node.id = this.finishNode(node2, "QualifiedTypeIdentifier");
|
||||
}
|
||||
|
||||
if (this.isRelational("<")) {
|
||||
node.typeParameters = this.flowParseTypeParameterInstantiation();
|
||||
}
|
||||
|
||||
return this.finishNode(node, "GenericTypeAnnotation");
|
||||
};
|
||||
|
||||
pp.flowParseTypeofType = function () {
|
||||
var node = this.startNode();
|
||||
this.expect(tt._typeof);
|
||||
node.argument = this.flowParsePrimaryType();
|
||||
return this.finishNode(node, "TypeofTypeAnnotation");
|
||||
};
|
||||
|
||||
pp.flowParseTupleType = function () {
|
||||
var node = this.startNode();
|
||||
node.types = [];
|
||||
this.expect(tt.bracketL);
|
||||
// We allow trailing commas
|
||||
while (this.pos < this.input.length && this.type !== tt.bracketR) {
|
||||
node.types.push(this.flowParseType());
|
||||
if (this.type === tt.bracketR) break;
|
||||
this.expect(tt.comma);
|
||||
}
|
||||
this.expect(tt.bracketR);
|
||||
return this.finishNode(node, "TupleTypeAnnotation");
|
||||
};
|
||||
|
||||
pp.flowParseFunctionTypeParam = function () {
|
||||
var optional = false;
|
||||
var node = this.startNode();
|
||||
node.name = this.parseIdent();
|
||||
if (this.eat(tt.question)) {
|
||||
optional = true;
|
||||
}
|
||||
node.optional = optional;
|
||||
node.typeAnnotation = this.flowParseTypeInitialiser();
|
||||
return this.finishNode(node, "FunctionTypeParam");
|
||||
};
|
||||
|
||||
pp.flowParseFunctionTypeParams = function () {
|
||||
var ret = { params: [], rest: null };
|
||||
while (this.type === tt.name) {
|
||||
ret.params.push(this.flowParseFunctionTypeParam());
|
||||
if (this.type !== tt.parenR) {
|
||||
this.expect(tt.comma);
|
||||
}
|
||||
}
|
||||
if (this.eat(tt.ellipsis)) {
|
||||
ret.rest = this.flowParseFunctionTypeParam();
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
|
||||
pp.flowIdentToTypeAnnotation = function (startPos, startLoc, node, id) {
|
||||
switch (id.name) {
|
||||
case "any":
|
||||
return this.finishNode(node, "AnyTypeAnnotation");
|
||||
|
||||
case "void":
|
||||
return this.finishNode(node, "VoidTypeAnnotation");
|
||||
|
||||
case "bool":
|
||||
case "boolean":
|
||||
return this.finishNode(node, "BooleanTypeAnnotation");
|
||||
|
||||
case "mixed":
|
||||
return this.finishNode(node, "MixedTypeAnnotation");
|
||||
|
||||
case "number":
|
||||
return this.finishNode(node, "NumberTypeAnnotation");
|
||||
|
||||
case "string":
|
||||
return this.finishNode(node, "StringTypeAnnotation");
|
||||
|
||||
default:
|
||||
return this.flowParseGenericType(startPos, startLoc, id);
|
||||
}
|
||||
};
|
||||
|
||||
// The parsing of types roughly parallels the parsing of expressions, and
|
||||
// primary types are kind of like primary expressions...they're the
|
||||
// primitives with which other types are constructed.
|
||||
pp.flowParsePrimaryType = function () {
|
||||
var startPos = this.start, startLoc = this.startLoc;
|
||||
var node = this.startNode();
|
||||
var tmp;
|
||||
var type;
|
||||
var isGroupedType = false;
|
||||
|
||||
switch (this.type) {
|
||||
case tt.name:
|
||||
return this.flowIdentToTypeAnnotation(startPos, startLoc, node, this.parseIdent());
|
||||
|
||||
case tt.braceL:
|
||||
return this.flowParseObjectType();
|
||||
|
||||
case tt.bracketL:
|
||||
return this.flowParseTupleType();
|
||||
|
||||
case tt.relational:
|
||||
if (this.value === "<") {
|
||||
node.typeParameters = this.flowParseTypeParameterDeclaration();
|
||||
this.expect(tt.parenL);
|
||||
tmp = this.flowParseFunctionTypeParams();
|
||||
node.params = tmp.params;
|
||||
node.rest = tmp.rest;
|
||||
this.expect(tt.parenR);
|
||||
|
||||
this.expect(tt.arrow);
|
||||
|
||||
node.returnType = this.flowParseType();
|
||||
|
||||
return this.finishNode(node, "FunctionTypeAnnotation");
|
||||
}
|
||||
|
||||
case tt.parenL:
|
||||
this.next();
|
||||
|
||||
// Check to see if this is actually a grouped type
|
||||
if (this.type !== tt.parenR && this.type !== tt.ellipsis) {
|
||||
if (this.type === tt.name) {
|
||||
var token = this.lookahead().type;
|
||||
isGroupedType = token !== tt.question && token !== tt.colon;
|
||||
} else {
|
||||
isGroupedType = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (isGroupedType) {
|
||||
type = this.flowParseType();
|
||||
this.expect(tt.parenR);
|
||||
|
||||
// If we see a => next then someone was probably confused about
|
||||
// function types, so we can provide a better error message
|
||||
if (this.eat(tt.arrow)) {
|
||||
this.raise(node,
|
||||
"Unexpected token =>. It looks like " +
|
||||
"you are trying to write a function type, but you ended up " +
|
||||
"writing a grouped type followed by an =>, which is a syntax " +
|
||||
"error. Remember, function type parameters are named so function " +
|
||||
"types look like (name1: type1, name2: type2) => returnType. You " +
|
||||
"probably wrote (type1) => returnType"
|
||||
);
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
tmp = this.flowParseFunctionTypeParams();
|
||||
node.params = tmp.params;
|
||||
node.rest = tmp.rest;
|
||||
|
||||
this.expect(tt.parenR);
|
||||
|
||||
this.expect(tt.arrow);
|
||||
|
||||
node.returnType = this.flowParseType();
|
||||
node.typeParameters = null;
|
||||
|
||||
return this.finishNode(node, "FunctionTypeAnnotation");
|
||||
|
||||
case tt.string:
|
||||
node.value = this.value;
|
||||
node.raw = this.input.slice(this.start, this.end);
|
||||
this.next();
|
||||
return this.finishNode(node, "StringLiteralTypeAnnotation");
|
||||
|
||||
default:
|
||||
if (this.type.keyword === "typeof") {
|
||||
return this.flowParseTypeofType();
|
||||
}
|
||||
}
|
||||
|
||||
this.unexpected();
|
||||
};
|
||||
|
||||
pp.flowParsePostfixType = function () {
|
||||
var node = this.startNode();
|
||||
var type = node.elementType = this.flowParsePrimaryType();
|
||||
if (this.type === tt.bracketL) {
|
||||
this.expect(tt.bracketL);
|
||||
this.expect(tt.bracketR);
|
||||
return this.finishNode(node, "ArrayTypeAnnotation");
|
||||
} else {
|
||||
return type;
|
||||
}
|
||||
};
|
||||
|
||||
pp.flowParsePrefixType = function () {
|
||||
var node = this.startNode();
|
||||
if (this.eat(tt.question)) {
|
||||
node.typeAnnotation = this.flowParsePrefixType();
|
||||
return this.finishNode(node, "NullableTypeAnnotation");
|
||||
} else {
|
||||
return this.flowParsePostfixType();
|
||||
}
|
||||
};
|
||||
|
||||
pp.flowParseIntersectionType = function () {
|
||||
var node = this.startNode();
|
||||
var type = this.flowParsePrefixType();
|
||||
node.types = [type];
|
||||
while (this.eat(tt.bitwiseAND)) {
|
||||
node.types.push(this.flowParsePrefixType());
|
||||
}
|
||||
return node.types.length === 1 ? type : this.finishNode(node, "IntersectionTypeAnnotation");
|
||||
};
|
||||
|
||||
pp.flowParseUnionType = function () {
|
||||
var node = this.startNode();
|
||||
var type = this.flowParseIntersectionType();
|
||||
node.types = [type];
|
||||
while (this.eat(tt.bitwiseOR)) {
|
||||
node.types.push(this.flowParseIntersectionType());
|
||||
}
|
||||
return node.types.length === 1 ? type : this.finishNode(node, "UnionTypeAnnotation");
|
||||
};
|
||||
|
||||
pp.flowParseType = function () {
|
||||
var oldInType = this.inType;
|
||||
this.inType = true;
|
||||
var type = this.flowParseUnionType();
|
||||
this.inType = oldInType;
|
||||
return type;
|
||||
};
|
||||
|
||||
pp.flowParseTypeAnnotation = function () {
|
||||
var node = this.startNode();
|
||||
node.typeAnnotation = this.flowParseTypeInitialiser();
|
||||
return this.finishNode(node, "TypeAnnotation");
|
||||
};
|
||||
|
||||
pp.flowParseTypeAnnotatableIdentifier = function (requireTypeAnnotation, canBeOptionalParam) {
|
||||
var ident = this.parseIdent();
|
||||
var isOptionalParam = false;
|
||||
|
||||
if (canBeOptionalParam && this.eat(tt.question)) {
|
||||
this.expect(tt.question);
|
||||
isOptionalParam = true;
|
||||
}
|
||||
|
||||
if (requireTypeAnnotation || this.type === tt.colon) {
|
||||
ident.typeAnnotation = this.flowParseTypeAnnotation();
|
||||
this.finishNode(ident, ident.type);
|
||||
}
|
||||
|
||||
if (isOptionalParam) {
|
||||
ident.optional = true;
|
||||
this.finishNode(ident, ident.type);
|
||||
}
|
||||
|
||||
return ident;
|
||||
};
|
||||
|
||||
export default function (instance) {
|
||||
// function name(): string {}
|
||||
instance.extend("parseFunctionBody", function (inner) {
|
||||
return function (node, allowExpression) {
|
||||
if (this.type === tt.colon) {
|
||||
node.returnType = this.flowParseTypeAnnotation();
|
||||
}
|
||||
|
||||
return inner.call(this, node, allowExpression);
|
||||
};
|
||||
});
|
||||
|
||||
instance.extend("parseStatement", function (inner) {
|
||||
return function (declaration, topLevel) {
|
||||
// strict mode handling of `interface` since it's a reserved word
|
||||
if (this.strict && this.type === tt.name && this.value === "interface") {
|
||||
var node = this.startNode();
|
||||
this.next();
|
||||
return this.flowParseInterface(node);
|
||||
} else {
|
||||
return inner.call(this, declaration, topLevel);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
instance.extend("parseExpressionStatement", function (inner) {
|
||||
return function (node, expr) {
|
||||
if (expr.type === "Identifier") {
|
||||
if (expr.name === "declare") {
|
||||
if (this.type === tt._class || this.type === tt.name || this.type === tt._function || this.type === tt._var) {
|
||||
return this.flowParseDeclare(node);
|
||||
}
|
||||
} else if (this.type === tt.name) {
|
||||
if (expr.name === "interface") {
|
||||
return this.flowParseInterface(node);
|
||||
} else if (expr.name === "type") {
|
||||
return this.flowParseTypeAlias(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return inner.call(this, node, expr);
|
||||
};
|
||||
});
|
||||
|
||||
instance.extend("shouldParseExportDeclaration", function (inner) {
|
||||
return function () {
|
||||
return this.isContextual("type") || inner.call(this);
|
||||
};
|
||||
});
|
||||
|
||||
instance.extend("parseParenItem", function () {
|
||||
return function (node, startLoc, startPos) {
|
||||
if (this.type === tt.colon) {
|
||||
var typeCastNode = this.startNodeAt(startLoc, startPos);
|
||||
typeCastNode.expression = node;
|
||||
typeCastNode.typeAnnotation = this.flowParseTypeAnnotation();
|
||||
return this.finishNode(typeCastNode, "TypeCastExpression");
|
||||
} else {
|
||||
return node;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
instance.extend("parseClassId", function (inner) {
|
||||
return function (node, isStatement) {
|
||||
inner.call(this, node, isStatement);
|
||||
if (this.isRelational("<")) {
|
||||
node.typeParameters = this.flowParseTypeParameterDeclaration();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
// don't consider `void` to be a keyword as then it'll use the void token type
|
||||
// and set startExpr
|
||||
instance.extend("isKeyword", function (inner) {
|
||||
return function (name) {
|
||||
if (this.inType && name === "void") {
|
||||
return false;
|
||||
} else {
|
||||
return inner.call(this, name);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
instance.extend("readToken", function (inner) {
|
||||
return function (code) {
|
||||
if (this.inType && (code === 62 || code === 60)) {
|
||||
return this.finishOp(tt.relational, 1);
|
||||
} else {
|
||||
return inner.call(this, code);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
instance.extend("jsx_readToken", function (inner) {
|
||||
return function () {
|
||||
if (!this.inType) return inner.call(this);
|
||||
};
|
||||
});
|
||||
|
||||
instance.extend("parseParenArrowList", function (inner) {
|
||||
return function (startPos, startLoc, exprList, isAsync) {
|
||||
for (var i = 0; i < exprList.length; i++) {
|
||||
var listItem = exprList[i];
|
||||
if (listItem.type === "TypeCastExpression") {
|
||||
var expr = listItem.expression;
|
||||
expr.typeAnnotation = listItem.typeAnnotation;
|
||||
exprList[i] = expr;
|
||||
}
|
||||
}
|
||||
return inner.call(this, startPos, startLoc, exprList, isAsync);
|
||||
};
|
||||
});
|
||||
|
||||
instance.extend("parseClassProperty", function (inner) {
|
||||
return function (node) {
|
||||
if (this.type === tt.colon) {
|
||||
node.typeAnnotation = this.flowParseTypeAnnotation();
|
||||
}
|
||||
return inner.call(this, node);
|
||||
};
|
||||
});
|
||||
|
||||
instance.extend("isClassProperty", function (inner) {
|
||||
return function () {
|
||||
return this.type === tt.colon || inner.call(this);
|
||||
};
|
||||
});
|
||||
|
||||
instance.extend("parseClassMethod", function () {
|
||||
return function (classBody, method, isGenerator, isAsync) {
|
||||
var typeParameters;
|
||||
if (this.isRelational("<")) {
|
||||
typeParameters = this.flowParseTypeParameterDeclaration();
|
||||
}
|
||||
method.value = this.parseMethod(isGenerator, isAsync);
|
||||
method.value.typeParameters = typeParameters;
|
||||
classBody.body.push(this.finishNode(method, "MethodDefinition"));
|
||||
};
|
||||
});
|
||||
|
||||
instance.extend("parseClassSuper", function (inner) {
|
||||
return function (node, isStatement) {
|
||||
inner.call(this, node, isStatement);
|
||||
if (node.superClass && this.isRelational("<")) {
|
||||
node.superTypeParameters = this.flowParseTypeParameterInstantiation();
|
||||
}
|
||||
if (this.isContextual("implements")) {
|
||||
this.next();
|
||||
var implemented = node.implements = [];
|
||||
do {
|
||||
let node = this.startNode();
|
||||
node.id = this.parseIdent();
|
||||
if (this.isRelational("<")) {
|
||||
node.typeParameters = this.flowParseTypeParameterInstantiation();
|
||||
} else {
|
||||
node.typeParameters = null;
|
||||
}
|
||||
implemented.push(this.finishNode(node, "ClassImplements"));
|
||||
} while(this.eat(tt.comma))
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
instance.extend("parseObjPropValue", function (inner) {
|
||||
return function (prop) {
|
||||
var typeParameters;
|
||||
if (this.isRelational("<")) {
|
||||
typeParameters = this.flowParseTypeParameterDeclaration();
|
||||
if (this.type !== tt.parenL) this.unexpected();
|
||||
}
|
||||
inner.apply(this, arguments);
|
||||
prop.value.typeParameters = typeParameters;
|
||||
};
|
||||
});
|
||||
|
||||
instance.extend("parseAssignableListItemTypes", function () {
|
||||
return function (param) {
|
||||
if (this.eat(tt.question)) {
|
||||
param.optional = true;
|
||||
}
|
||||
if (this.type === tt.colon) {
|
||||
param.typeAnnotation = this.flowParseTypeAnnotation();
|
||||
}
|
||||
this.finishNode(param, param.type);
|
||||
return param;
|
||||
};
|
||||
});
|
||||
|
||||
instance.extend("parseImportSpecifiers", function (inner) {
|
||||
return function (node) {
|
||||
node.isType = false;
|
||||
if (this.isContextual("type")) {
|
||||
var startPos = this.start, startLoc = this.startLoc;
|
||||
var typeId = this.parseIdent();
|
||||
if ((this.type === tt.name && this.value !== "from") || this.type === tt.braceL || this.type === tt.star) {
|
||||
node.isType = true;
|
||||
} else {
|
||||
node.specifiers.push(this.parseImportSpecifierDefault(typeId, startPos, startLoc));
|
||||
if (this.isContextual("from")) return;
|
||||
this.eat(tt.comma);
|
||||
}
|
||||
}
|
||||
inner.call(this, node);
|
||||
};
|
||||
});
|
||||
|
||||
// function foo<T>() {}
|
||||
instance.extend("parseFunctionParams", function (inner) {
|
||||
return function (node) {
|
||||
if (this.isRelational("<")) {
|
||||
node.typeParameters = this.flowParseTypeParameterDeclaration();
|
||||
}
|
||||
inner.call(this, node);
|
||||
};
|
||||
});
|
||||
|
||||
// var foo: string = bar
|
||||
instance.extend("parseVarHead", function (inner) {
|
||||
return function (decl) {
|
||||
inner.call(this, decl);
|
||||
if (this.type === tt.colon) {
|
||||
decl.id.typeAnnotation = this.flowParseTypeAnnotation();
|
||||
this.finishNode(decl.id, decl.id.type);
|
||||
}
|
||||
};
|
||||
});
|
||||
};
|
||||
421
src/plugins/jsx/index.js
Normal file
421
src/plugins/jsx/index.js
Normal file
@@ -0,0 +1,421 @@
|
||||
import XHTMLEntities from "./xhtml";
|
||||
import { TokenType, types as tt } from "../../tokentype";
|
||||
import { TokContext, types as tc } from "../../tokencontext";
|
||||
import { Parser } from "../../state";
|
||||
import { isIdentifierChar, isIdentifierStart } from "../../identifier";
|
||||
import { isNewLine, lineBreak, lineBreakG } from "../../whitespace";
|
||||
|
||||
const HEX_NUMBER = /^[\da-fA-F]+$/;
|
||||
const DECIMAL_NUMBER = /^\d+$/;
|
||||
|
||||
tc.j_oTag = new TokContext("<tag", false);
|
||||
tc.j_cTag = new TokContext("</tag", false);
|
||||
tc.j_expr = new TokContext("<tag>...</tag>", true, true);
|
||||
|
||||
tt.jsxName = new TokenType("jsxName");
|
||||
tt.jsxText = new TokenType("jsxText", { beforeExpr: true });
|
||||
tt.jsxTagStart = new TokenType("jsxTagStart");
|
||||
tt.jsxTagEnd = new TokenType("jsxTagEnd");
|
||||
|
||||
tt.jsxTagStart.updateContext = function() {
|
||||
this.context.push(tc.j_expr); // treat as beginning of JSX expression
|
||||
this.context.push(tc.j_oTag); // start opening tag context
|
||||
this.exprAllowed = false;
|
||||
};
|
||||
|
||||
tt.jsxTagEnd.updateContext = function(prevType) {
|
||||
var out = this.context.pop();
|
||||
if (out === tc.j_oTag && prevType === tt.slash || out === tc.j_cTag) {
|
||||
this.context.pop();
|
||||
this.exprAllowed = this.curContext() === tc.j_expr;
|
||||
} else {
|
||||
this.exprAllowed = true;
|
||||
}
|
||||
};
|
||||
|
||||
var pp = Parser.prototype;
|
||||
|
||||
// Reads inline JSX contents token.
|
||||
|
||||
pp.jsxReadToken = function() {
|
||||
var out = "", chunkStart = this.pos;
|
||||
for (;;) {
|
||||
if (this.pos >= this.input.length)
|
||||
this.raise(this.start, "Unterminated JSX contents");
|
||||
var ch = this.input.charCodeAt(this.pos);
|
||||
|
||||
switch (ch) {
|
||||
case 60: // "<"
|
||||
case 123: // "{"
|
||||
if (this.pos === this.start) {
|
||||
if (ch === 60 && this.exprAllowed) {
|
||||
++this.pos;
|
||||
return this.finishToken(tt.jsxTagStart);
|
||||
}
|
||||
return this.getTokenFromCode(ch);
|
||||
}
|
||||
out += this.input.slice(chunkStart, this.pos);
|
||||
return this.finishToken(tt.jsxText, out);
|
||||
|
||||
case 38: // "&"
|
||||
out += this.input.slice(chunkStart, this.pos);
|
||||
out += this.jsxReadEntity();
|
||||
chunkStart = this.pos;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (isNewLine(ch)) {
|
||||
out += this.input.slice(chunkStart, this.pos);
|
||||
out += this.jsxReadNewLine(true);
|
||||
chunkStart = this.pos;
|
||||
} else {
|
||||
++this.pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
pp.jsxReadNewLine = function(normalizeCRLF) {
|
||||
var ch = this.input.charCodeAt(this.pos);
|
||||
var out;
|
||||
++this.pos;
|
||||
if (ch === 13 && this.input.charCodeAt(this.pos) === 10) {
|
||||
++this.pos;
|
||||
out = normalizeCRLF ? "\n" : "\r\n";
|
||||
} else {
|
||||
out = String.fromCharCode(ch);
|
||||
}
|
||||
if (this.options.locations) {
|
||||
++this.curLine;
|
||||
this.lineStart = this.pos;
|
||||
}
|
||||
|
||||
return out;
|
||||
};
|
||||
|
||||
pp.jsxReadString = function(quote) {
|
||||
var out = "", chunkStart = ++this.pos;
|
||||
for (;;) {
|
||||
if (this.pos >= this.input.length)
|
||||
this.raise(this.start, "Unterminated string constant");
|
||||
var ch = this.input.charCodeAt(this.pos);
|
||||
if (ch === quote) break;
|
||||
if (ch === 38) { // "&"
|
||||
out += this.input.slice(chunkStart, this.pos);
|
||||
out += this.jsxReadEntity();
|
||||
chunkStart = this.pos;
|
||||
} else if (isNewLine(ch)) {
|
||||
out += this.input.slice(chunkStart, this.pos);
|
||||
out += this.jsxReadNewLine(false);
|
||||
chunkStart = this.pos;
|
||||
} else {
|
||||
++this.pos;
|
||||
}
|
||||
}
|
||||
out += this.input.slice(chunkStart, this.pos++);
|
||||
return this.finishToken(tt.string, out);
|
||||
};
|
||||
|
||||
pp.jsxReadEntity = function() {
|
||||
var str = "", count = 0, entity;
|
||||
var ch = this.input[this.pos];
|
||||
if (ch !== "&")
|
||||
this.raise(this.pos, "Entity must start with an ampersand");
|
||||
var startPos = ++this.pos;
|
||||
while (this.pos < this.input.length && count++ < 10) {
|
||||
ch = this.input[this.pos++];
|
||||
if (ch === ";") {
|
||||
if (str[0] === "#") {
|
||||
if (str[1] === "x") {
|
||||
str = str.substr(2);
|
||||
if (HEX_NUMBER.test(str))
|
||||
entity = String.fromCharCode(parseInt(str, 16));
|
||||
} else {
|
||||
str = str.substr(1);
|
||||
if (DECIMAL_NUMBER.test(str))
|
||||
entity = String.fromCharCode(parseInt(str, 10));
|
||||
}
|
||||
} else {
|
||||
entity = XHTMLEntities[str];
|
||||
}
|
||||
break;
|
||||
}
|
||||
str += ch;
|
||||
}
|
||||
if (!entity) {
|
||||
this.pos = startPos;
|
||||
return "&";
|
||||
}
|
||||
return entity;
|
||||
};
|
||||
|
||||
|
||||
// Read a JSX identifier (valid tag or attribute name).
|
||||
//
|
||||
// Optimized version since JSX identifiers can"t contain
|
||||
// escape characters and so can be read as single slice.
|
||||
// Also assumes that first character was already checked
|
||||
// by isIdentifierStart in readToken.
|
||||
|
||||
pp.jsxReadWord = function() {
|
||||
var ch, start = this.pos;
|
||||
do {
|
||||
ch = this.input.charCodeAt(++this.pos);
|
||||
} while (isIdentifierChar(ch) || ch === 45); // "-"
|
||||
return this.finishToken(tt.jsxName, this.input.slice(start, this.pos));
|
||||
};
|
||||
|
||||
// Transforms JSX element name to string.
|
||||
|
||||
function getQualifiedJSXName(object) {
|
||||
if (object.type === "JSXIdentifier")
|
||||
return object.name;
|
||||
|
||||
if (object.type === "JSXNamespacedName")
|
||||
return object.namespace.name + ":" + object.name.name;
|
||||
|
||||
if (object.type === "JSXMemberExpression")
|
||||
return getQualifiedJSXName(object.object) + "." +
|
||||
getQualifiedJSXName(object.property);
|
||||
}
|
||||
|
||||
// Parse next token as JSX identifier
|
||||
|
||||
pp.jsxParseIdentifier = function() {
|
||||
var node = this.startNode();
|
||||
if (this.type === tt.jsxName)
|
||||
node.name = this.value;
|
||||
else if (this.type.keyword)
|
||||
node.name = this.type.keyword;
|
||||
else
|
||||
this.unexpected();
|
||||
this.next();
|
||||
return this.finishNode(node, "JSXIdentifier");
|
||||
};
|
||||
|
||||
// Parse namespaced identifier.
|
||||
|
||||
pp.jsxParseNamespacedName = function() {
|
||||
var startPos = this.start, startLoc = this.startLoc;
|
||||
var name = this.jsxParseIdentifier();
|
||||
if (!this.eat(tt.colon)) return name;
|
||||
var node = this.startNodeAt(startPos, startLoc);
|
||||
node.namespace = name;
|
||||
node.name = this.jsxParseIdentifier();
|
||||
return this.finishNode(node, "JSXNamespacedName");
|
||||
};
|
||||
|
||||
// Parses element name in any form - namespaced, member
|
||||
// or single identifier.
|
||||
|
||||
pp.jsxParseElementName = function() {
|
||||
var startPos = this.start, startLoc = this.startLoc;
|
||||
var node = this.jsxParseNamespacedName();
|
||||
while (this.eat(tt.dot)) {
|
||||
var newNode = this.startNodeAt(startPos, startLoc);
|
||||
newNode.object = node;
|
||||
newNode.property = this.jsxParseIdentifier();
|
||||
node = this.finishNode(newNode, "JSXMemberExpression");
|
||||
}
|
||||
return node;
|
||||
};
|
||||
|
||||
// Parses any type of JSX attribute value.
|
||||
|
||||
pp.jsxParseAttributeValue = function() {
|
||||
switch (this.type) {
|
||||
case tt.braceL:
|
||||
var node = this.jsxParseExpressionContainer();
|
||||
if (node.expression.type === "JSXEmptyExpression")
|
||||
this.raise(node.start, "JSX attributes must only be assigned a non-empty expression");
|
||||
return node;
|
||||
|
||||
case tt.jsxTagStart:
|
||||
case tt.string:
|
||||
return this.parseExprAtom();
|
||||
|
||||
default:
|
||||
this.raise(this.start, "JSX value should be either an expression or a quoted JSX text");
|
||||
}
|
||||
};
|
||||
|
||||
// JSXEmptyExpression is unique type since it doesn"t actually parse anything,
|
||||
// and so it should start at the end of last read token (left brace) and finish
|
||||
// at the beginning of the next one (right brace).
|
||||
|
||||
pp.jsxParseEmptyExpression = function() {
|
||||
var tmp = this.start;
|
||||
this.start = this.lastTokEnd;
|
||||
this.lastTokEnd = tmp;
|
||||
|
||||
tmp = this.startLoc;
|
||||
this.startLoc = this.lastTokEndLoc;
|
||||
this.lastTokEndLoc = tmp;
|
||||
|
||||
return this.finishNode(this.startNode(), "JSXEmptyExpression");
|
||||
};
|
||||
|
||||
// Parses JSX expression enclosed into curly brackets.
|
||||
|
||||
|
||||
pp.jsxParseExpressionContainer = function() {
|
||||
var node = this.startNode();
|
||||
this.next();
|
||||
node.expression = this.type === tt.braceR
|
||||
? this.jsxParseEmptyExpression()
|
||||
: this.parseExpression();
|
||||
this.expect(tt.braceR);
|
||||
return this.finishNode(node, "JSXExpressionContainer");
|
||||
};
|
||||
|
||||
// Parses following JSX attribute name-value pair.
|
||||
|
||||
pp.jsxParseAttribute = function() {
|
||||
var node = this.startNode();
|
||||
if (this.eat(tt.braceL)) {
|
||||
this.expect(tt.ellipsis);
|
||||
node.argument = this.parseMaybeAssign();
|
||||
this.expect(tt.braceR);
|
||||
return this.finishNode(node, "JSXSpreadAttribute");
|
||||
}
|
||||
node.name = this.jsxParseNamespacedName();
|
||||
node.value = this.eat(tt.eq) ? this.jsxParseAttributeValue() : null;
|
||||
return this.finishNode(node, "JSXAttribute");
|
||||
};
|
||||
|
||||
// Parses JSX opening tag starting after "<".
|
||||
|
||||
pp.jsxParseOpeningElementAt = function(startPos, startLoc) {
|
||||
var node = this.startNodeAt(startPos, startLoc);
|
||||
node.attributes = [];
|
||||
node.name = this.jsxParseElementName();
|
||||
while (this.type !== tt.slash && this.type !== tt.jsxTagEnd)
|
||||
node.attributes.push(this.jsxParseAttribute());
|
||||
node.selfClosing = this.eat(tt.slash);
|
||||
this.expect(tt.jsxTagEnd);
|
||||
return this.finishNode(node, "JSXOpeningElement");
|
||||
};
|
||||
|
||||
// Parses JSX closing tag starting after "</".
|
||||
|
||||
pp.jsxParseClosingElementAt = function(startPos, startLoc) {
|
||||
var node = this.startNodeAt(startPos, startLoc);
|
||||
node.name = this.jsxParseElementName();
|
||||
this.expect(tt.jsxTagEnd);
|
||||
return this.finishNode(node, "JSXClosingElement");
|
||||
};
|
||||
|
||||
// Parses entire JSX element, including it"s opening tag
|
||||
// (starting after "<"), attributes, contents and closing tag.
|
||||
|
||||
pp.jsxParseElementAt = function(startPos, startLoc) {
|
||||
var node = this.startNodeAt(startPos, startLoc);
|
||||
var children = [];
|
||||
var openingElement = this.jsxParseOpeningElementAt(startPos, startLoc);
|
||||
var closingElement = null;
|
||||
|
||||
if (!openingElement.selfClosing) {
|
||||
contents: for (;;) {
|
||||
switch (this.type) {
|
||||
case tt.jsxTagStart:
|
||||
startPos = this.start; startLoc = this.startLoc;
|
||||
this.next();
|
||||
if (this.eat(tt.slash)) {
|
||||
closingElement = this.jsxParseClosingElementAt(startPos, startLoc);
|
||||
break contents;
|
||||
}
|
||||
children.push(this.jsxParseElementAt(startPos, startLoc));
|
||||
break;
|
||||
|
||||
case tt.jsxText:
|
||||
children.push(this.parseExprAtom());
|
||||
break;
|
||||
|
||||
case tt.braceL:
|
||||
children.push(this.jsxParseExpressionContainer());
|
||||
break;
|
||||
|
||||
default:
|
||||
this.unexpected();
|
||||
}
|
||||
}
|
||||
if (getQualifiedJSXName(closingElement.name) !== getQualifiedJSXName(openingElement.name)) {
|
||||
this.raise(
|
||||
closingElement.start,
|
||||
"Expected corresponding JSX closing tag for <" + getQualifiedJSXName(openingElement.name) + ">");
|
||||
}
|
||||
}
|
||||
|
||||
node.openingElement = openingElement;
|
||||
node.closingElement = closingElement;
|
||||
node.children = children;
|
||||
if (this.type === tt.relational && this.value === "<") {
|
||||
this.raise(this.start, "Adjacent JSX elements must be wrapped in an enclosing tag");
|
||||
}
|
||||
return this.finishNode(node, "JSXElement");
|
||||
};
|
||||
|
||||
// Parses entire JSX element from current position.
|
||||
|
||||
pp.jsxParseElement = function() {
|
||||
var startPos = this.start, startLoc = this.startLoc;
|
||||
this.next();
|
||||
return this.jsxParseElementAt(startPos, startLoc);
|
||||
};
|
||||
|
||||
export default function(instance) {
|
||||
instance.extend("parseExprAtom", function(inner) {
|
||||
return function(refShortHandDefaultPos) {
|
||||
if (this.type === tt.jsxText)
|
||||
return this.parseLiteral(this.value);
|
||||
else if (this.type === tt.jsxTagStart)
|
||||
return this.jsxParseElement();
|
||||
else
|
||||
return inner.call(this, refShortHandDefaultPos);
|
||||
};
|
||||
});
|
||||
|
||||
instance.extend("readToken", function(inner) {
|
||||
return function(code) {
|
||||
var context = this.curContext();
|
||||
|
||||
if (context === tc.j_expr) return this.jsxReadToken();
|
||||
|
||||
if (context === tc.j_oTag || context === tc.j_cTag) {
|
||||
if (isIdentifierStart(code)) return this.jsxReadWord();
|
||||
|
||||
if (code === 62) {
|
||||
++this.pos;
|
||||
return this.finishToken(tt.jsxTagEnd);
|
||||
}
|
||||
|
||||
if ((code === 34 || code === 39) && context === tc.j_oTag)
|
||||
return this.jsxReadString(code);
|
||||
}
|
||||
|
||||
if (code === 60 && this.exprAllowed) {
|
||||
++this.pos;
|
||||
return this.finishToken(tt.jsxTagStart);
|
||||
}
|
||||
return inner.call(this, code);
|
||||
};
|
||||
});
|
||||
|
||||
instance.extend("updateContext", function(inner) {
|
||||
return function(prevType) {
|
||||
if (this.type === tt.braceL) {
|
||||
var curContext = this.curContext();
|
||||
if (curContext === tc.j_oTag) this.context.push(tc.b_expr);
|
||||
else if (curContext === tc.j_expr) this.context.push(tc.b_tmpl);
|
||||
else inner.call(this, prevType);
|
||||
this.exprAllowed = true;
|
||||
} else if (this.type === tt.slash && prevType === tt.jsxTagStart) {
|
||||
this.context.length -= 2; // do not consider JSX expr -> JSX open tag -> ... anymore
|
||||
this.context.push(tc.j_cTag); // reconsider as closing tag context
|
||||
this.exprAllowed = false;
|
||||
} else {
|
||||
return inner.call(this, prevType);
|
||||
}
|
||||
};
|
||||
});
|
||||
};
|
||||
255
src/plugins/jsx/xhtml.js
Normal file
255
src/plugins/jsx/xhtml.js
Normal file
@@ -0,0 +1,255 @@
|
||||
export default {
|
||||
quot: "\u0022",
|
||||
amp: "&",
|
||||
apos: "\u0027",
|
||||
lt: "<",
|
||||
gt: ">",
|
||||
nbsp: "\u00A0",
|
||||
iexcl: "\u00A1",
|
||||
cent: "\u00A2",
|
||||
pound: "\u00A3",
|
||||
curren: "\u00A4",
|
||||
yen: "\u00A5",
|
||||
brvbar: "\u00A6",
|
||||
sect: "\u00A7",
|
||||
uml: "\u00A8",
|
||||
copy: "\u00A9",
|
||||
ordf: "\u00AA",
|
||||
laquo: "\u00AB",
|
||||
not: "\u00AC",
|
||||
shy: "\u00AD",
|
||||
reg: "\u00AE",
|
||||
macr: "\u00AF",
|
||||
deg: "\u00B0",
|
||||
plusmn: "\u00B1",
|
||||
sup2: "\u00B2",
|
||||
sup3: "\u00B3",
|
||||
acute: "\u00B4",
|
||||
micro: "\u00B5",
|
||||
para: "\u00B6",
|
||||
middot: "\u00B7",
|
||||
cedil: "\u00B8",
|
||||
sup1: "\u00B9",
|
||||
ordm: "\u00BA",
|
||||
raquo: "\u00BB",
|
||||
frac14: "\u00BC",
|
||||
frac12: "\u00BD",
|
||||
frac34: "\u00BE",
|
||||
iquest: "\u00BF",
|
||||
Agrave: "\u00C0",
|
||||
Aacute: "\u00C1",
|
||||
Acirc: "\u00C2",
|
||||
Atilde: "\u00C3",
|
||||
Auml: "\u00C4",
|
||||
Aring: "\u00C5",
|
||||
AElig: "\u00C6",
|
||||
Ccedil: "\u00C7",
|
||||
Egrave: "\u00C8",
|
||||
Eacute: "\u00C9",
|
||||
Ecirc: "\u00CA",
|
||||
Euml: "\u00CB",
|
||||
Igrave: "\u00CC",
|
||||
Iacute: "\u00CD",
|
||||
Icirc: "\u00CE",
|
||||
Iuml: "\u00CF",
|
||||
ETH: "\u00D0",
|
||||
Ntilde: "\u00D1",
|
||||
Ograve: "\u00D2",
|
||||
Oacute: "\u00D3",
|
||||
Ocirc: "\u00D4",
|
||||
Otilde: "\u00D5",
|
||||
Ouml: "\u00D6",
|
||||
times: "\u00D7",
|
||||
Oslash: "\u00D8",
|
||||
Ugrave: "\u00D9",
|
||||
Uacute: "\u00DA",
|
||||
Ucirc: "\u00DB",
|
||||
Uuml: "\u00DC",
|
||||
Yacute: "\u00DD",
|
||||
THORN: "\u00DE",
|
||||
szlig: "\u00DF",
|
||||
agrave: "\u00E0",
|
||||
aacute: "\u00E1",
|
||||
acirc: "\u00E2",
|
||||
atilde: "\u00E3",
|
||||
auml: "\u00E4",
|
||||
aring: "\u00E5",
|
||||
aelig: "\u00E6",
|
||||
ccedil: "\u00E7",
|
||||
egrave: "\u00E8",
|
||||
eacute: "\u00E9",
|
||||
ecirc: "\u00EA",
|
||||
euml: "\u00EB",
|
||||
igrave: "\u00EC",
|
||||
iacute: "\u00ED",
|
||||
icirc: "\u00EE",
|
||||
iuml: "\u00EF",
|
||||
eth: "\u00F0",
|
||||
ntilde: "\u00F1",
|
||||
ograve: "\u00F2",
|
||||
oacute: "\u00F3",
|
||||
ocirc: "\u00F4",
|
||||
otilde: "\u00F5",
|
||||
ouml: "\u00F6",
|
||||
divide: "\u00F7",
|
||||
oslash: "\u00F8",
|
||||
ugrave: "\u00F9",
|
||||
uacute: "\u00FA",
|
||||
ucirc: "\u00FB",
|
||||
uuml: "\u00FC",
|
||||
yacute: "\u00FD",
|
||||
thorn: "\u00FE",
|
||||
yuml: "\u00FF",
|
||||
OElig: "\u0152",
|
||||
oelig: "\u0153",
|
||||
Scaron: "\u0160",
|
||||
scaron: "\u0161",
|
||||
Yuml: "\u0178",
|
||||
fnof: "\u0192",
|
||||
circ: "\u02C6",
|
||||
tilde: "\u02DC",
|
||||
Alpha: "\u0391",
|
||||
Beta: "\u0392",
|
||||
Gamma: "\u0393",
|
||||
Delta: "\u0394",
|
||||
Epsilon: "\u0395",
|
||||
Zeta: "\u0396",
|
||||
Eta: "\u0397",
|
||||
Theta: "\u0398",
|
||||
Iota: "\u0399",
|
||||
Kappa: "\u039A",
|
||||
Lambda: "\u039B",
|
||||
Mu: "\u039C",
|
||||
Nu: "\u039D",
|
||||
Xi: "\u039E",
|
||||
Omicron: "\u039F",
|
||||
Pi: "\u03A0",
|
||||
Rho: "\u03A1",
|
||||
Sigma: "\u03A3",
|
||||
Tau: "\u03A4",
|
||||
Upsilon: "\u03A5",
|
||||
Phi: "\u03A6",
|
||||
Chi: "\u03A7",
|
||||
Psi: "\u03A8",
|
||||
Omega: "\u03A9",
|
||||
alpha: "\u03B1",
|
||||
beta: "\u03B2",
|
||||
gamma: "\u03B3",
|
||||
delta: "\u03B4",
|
||||
epsilon: "\u03B5",
|
||||
zeta: "\u03B6",
|
||||
eta: "\u03B7",
|
||||
theta: "\u03B8",
|
||||
iota: "\u03B9",
|
||||
kappa: "\u03BA",
|
||||
lambda: "\u03BB",
|
||||
mu: "\u03BC",
|
||||
nu: "\u03BD",
|
||||
xi: "\u03BE",
|
||||
omicron: "\u03BF",
|
||||
pi: "\u03C0",
|
||||
rho: "\u03C1",
|
||||
sigmaf: "\u03C2",
|
||||
sigma: "\u03C3",
|
||||
tau: "\u03C4",
|
||||
upsilon: "\u03C5",
|
||||
phi: "\u03C6",
|
||||
chi: "\u03C7",
|
||||
psi: "\u03C8",
|
||||
omega: "\u03C9",
|
||||
thetasym: "\u03D1",
|
||||
upsih: "\u03D2",
|
||||
piv: "\u03D6",
|
||||
ensp: "\u2002",
|
||||
emsp: "\u2003",
|
||||
thinsp: "\u2009",
|
||||
zwnj: "\u200C",
|
||||
zwj: "\u200D",
|
||||
lrm: "\u200E",
|
||||
rlm: "\u200F",
|
||||
ndash: "\u2013",
|
||||
mdash: "\u2014",
|
||||
lsquo: "\u2018",
|
||||
rsquo: "\u2019",
|
||||
sbquo: "\u201A",
|
||||
ldquo: "\u201C",
|
||||
rdquo: "\u201D",
|
||||
bdquo: "\u201E",
|
||||
dagger: "\u2020",
|
||||
Dagger: "\u2021",
|
||||
bull: "\u2022",
|
||||
hellip: "\u2026",
|
||||
permil: "\u2030",
|
||||
prime: "\u2032",
|
||||
Prime: "\u2033",
|
||||
lsaquo: "\u2039",
|
||||
rsaquo: "\u203A",
|
||||
oline: "\u203E",
|
||||
frasl: "\u2044",
|
||||
euro: "\u20AC",
|
||||
image: "\u2111",
|
||||
weierp: "\u2118",
|
||||
real: "\u211C",
|
||||
trade: "\u2122",
|
||||
alefsym: "\u2135",
|
||||
larr: "\u2190",
|
||||
uarr: "\u2191",
|
||||
rarr: "\u2192",
|
||||
darr: "\u2193",
|
||||
harr: "\u2194",
|
||||
crarr: "\u21B5",
|
||||
lArr: "\u21D0",
|
||||
uArr: "\u21D1",
|
||||
rArr: "\u21D2",
|
||||
dArr: "\u21D3",
|
||||
hArr: "\u21D4",
|
||||
forall: "\u2200",
|
||||
part: "\u2202",
|
||||
exist: "\u2203",
|
||||
empty: "\u2205",
|
||||
nabla: "\u2207",
|
||||
isin: "\u2208",
|
||||
notin: "\u2209",
|
||||
ni: "\u220B",
|
||||
prod: "\u220F",
|
||||
sum: "\u2211",
|
||||
minus: "\u2212",
|
||||
lowast: "\u2217",
|
||||
radic: "\u221A",
|
||||
prop: "\u221D",
|
||||
infin: "\u221E",
|
||||
ang: "\u2220",
|
||||
and: "\u2227",
|
||||
or: "\u2228",
|
||||
cap: "\u2229",
|
||||
cup: "\u222A",
|
||||
"int": "\u222B",
|
||||
there4: "\u2234",
|
||||
sim: "\u223C",
|
||||
cong: "\u2245",
|
||||
asymp: "\u2248",
|
||||
ne: "\u2260",
|
||||
equiv: "\u2261",
|
||||
le: "\u2264",
|
||||
ge: "\u2265",
|
||||
sub: "\u2282",
|
||||
sup: "\u2283",
|
||||
nsub: "\u2284",
|
||||
sube: "\u2286",
|
||||
supe: "\u2287",
|
||||
oplus: "\u2295",
|
||||
otimes: "\u2297",
|
||||
perp: "\u22A5",
|
||||
sdot: "\u22C5",
|
||||
lceil: "\u2308",
|
||||
rceil: "\u2309",
|
||||
lfloor: "\u230A",
|
||||
rfloor: "\u230B",
|
||||
lang: "\u2329",
|
||||
rang: "\u232A",
|
||||
loz: "\u25CA",
|
||||
spades: "\u2660",
|
||||
clubs: "\u2663",
|
||||
hearts: "\u2665",
|
||||
diams: "\u2666"
|
||||
};
|
||||
Reference in New Issue
Block a user