Implement 'this' context parsing and serialization; Other minor improvements

This commit is contained in:
dcodeIO
2018-05-30 16:22:56 +02:00
parent c9ed03028d
commit 9d25f78fc1
18 changed files with 1589 additions and 1464 deletions

View File

@ -19,7 +19,8 @@ import {
import {
normalizePath,
resolvePath
resolvePath,
CharCode
} from "./util";
export { Token, Range };
@ -180,7 +181,7 @@ export abstract class Node {
): SignatureNode {
var sig = new SignatureNode();
sig.range = range;
sig.parameterTypes = parameters; setParent(parameters, sig);
sig.parameters = parameters; setParent(parameters, sig);
sig.returnType = returnType; returnType.parent = sig;
sig.explicitThisType = explicitThisType; if (explicitThisType) explicitThisType.parent = sig;
sig.isNullable = isNullable;
@ -1037,7 +1038,7 @@ export class SignatureNode extends CommonTypeNode {
kind = NodeKind.SIGNATURE;
/** Accepted parameters. */
parameterTypes: ParameterNode[];
parameters: ParameterNode[];
/** Return type. */
returnType: CommonTypeNode;
/** Explicitly provided this type, if any. */
@ -1058,14 +1059,30 @@ export enum DecoratorKind {
/** Returns the decorator kind represented by the specified string. */
export function stringToDecoratorKind(str: string): DecoratorKind {
switch (str) {
case "global": return DecoratorKind.GLOBAL;
case "operator": return DecoratorKind.OPERATOR;
case "unmanaged": return DecoratorKind.UNMANAGED;
case "sealed": return DecoratorKind.SEALED;
case "inline": return DecoratorKind.INLINE;
default: return DecoratorKind.CUSTOM;
assert(str.length);
switch (str.charCodeAt(0)) {
case CharCode.g: {
if (str == "global") return DecoratorKind.GLOBAL;
break;
}
case CharCode.i: {
if (str == "inline") return DecoratorKind.INLINE;
break;
}
case CharCode.o: {
if (str == "operator") return DecoratorKind.OPERATOR;
break;
}
case CharCode.s: {
if (str == "sealed") return DecoratorKind.SEALED;
break;
}
case CharCode.u: {
if (str == "unmanaged") return DecoratorKind.UNMANAGED;
break;
}
}
return DecoratorKind.CUSTOM;
}
/** Represents a decorator. */

View File

@ -4708,7 +4708,7 @@ export class Compiler extends DiagnosticEmitter {
inferredTypes.set(typeParameters[i].name.text, null);
}
// let numInferred = 0;
let parameterTypes = prototype.declaration.signature.parameterTypes;
let parameterTypes = prototype.declaration.signature.parameters;
let numParameterTypes = parameterTypes.length;
let argumentExpressions = expression.arguments;
let numArguments = argumentExpressions.length;
@ -4718,7 +4718,7 @@ export class Compiler extends DiagnosticEmitter {
let name = typeNode.kind == NodeKind.TYPE ? (<TypeNode>typeNode).name.text : null;
let argumentExpression = i < numArguments
? argumentExpressions[i]
: prototype.declaration.signature.parameterTypes[i].initializer;
: prototype.declaration.signature.parameters[i].initializer;
if (!argumentExpression) { // missing initializer -> too few arguments
this.error(
DiagnosticCode.Expected_0_arguments_but_got_1,
@ -5088,7 +5088,7 @@ export class Compiler extends DiagnosticEmitter {
var numParameters = signature.parameterTypes.length;
for (let i = numArguments; i < numParameters; ++i) {
let initExpr = this.compileExpression(
assert(declaration.signature.parameterTypes[i].initializer),
assert(declaration.signature.parameters[i].initializer),
parameterTypes[i],
ConversionKind.IMPLICIT,
WrapMode.WRAP
@ -5158,7 +5158,7 @@ export class Compiler extends DiagnosticEmitter {
var originalSignature = original.signature;
var originalName = original.internalName;
var originalParameterTypes = originalSignature.parameterTypes;
var originalParameterDeclarations = original.prototype.declaration.signature.parameterTypes;
var originalParameterDeclarations = original.prototype.declaration.signature.parameters;
var commonReturnType = originalSignature.returnType;
var commonThisType = originalSignature.thisType;
var isInstance = original.is(CommonFlags.INSTANCE);
@ -5345,7 +5345,7 @@ export class Compiler extends DiagnosticEmitter {
operands.length = 0;
}
let parameterTypes = instance.signature.parameterTypes;
let parameterNodes = instance.prototype.declaration.signature.parameterTypes;
let parameterNodes = instance.prototype.declaration.signature.parameters;
let allOptionalsAreConstant = true;
for (let i = numArguments; i < maxArguments; ++i) {
let initializer = parameterNodes[i].initializer;

View File

@ -380,7 +380,7 @@ export class ASTBuilder {
sb.push("this: ");
this.visitTypeNode(explicitThisType);
}
var parameters = node.parameterTypes;
var parameters = node.parameters;
var numParameters = parameters.length;
if (numParameters) {
if (explicitThisType) sb.push(", ");
@ -1003,13 +1003,19 @@ export class ASTBuilder {
}
}
sb.push("(");
var parameterTypes = signature.parameterTypes;
var numParameterTypes = parameterTypes.length;
if (numParameterTypes) {
this.serializeParameter(parameterTypes[0]);
for (let i = 1; i < numParameterTypes; ++i) {
var parameters = signature.parameters;
var numParameters = parameters.length;
var explicitThisType = signature.explicitThisType;
if (explicitThisType) {
sb.push("this: ");
this.visitTypeNode(explicitThisType);
}
if (numParameters) {
if (explicitThisType) sb.push(", ");
this.serializeParameter(parameters[0]);
for (let i = 1; i < numParameters; ++i) {
sb.push(", ");
this.serializeParameter(parameterTypes[i]);
this.serializeParameter(parameters[i]);
}
}
var body = node.body;

View File

@ -87,10 +87,12 @@ export class Parser extends DiagnosticEmitter {
/** Program being created. */
program: Program;
/** Log of source file names to be requested. */
/** Source file names to be requested next. */
backlog: string[] = new Array();
/** Log of source file names already processed. */
/** Source file names already seen, that is processed or backlogged. */
seenlog: Set<string> = new Set();
/** Source file names already completely processed. */
donelog: Set<string> = new Set();
/** Optional handler to intercept comments while tokenizing. */
onComment: CommentHandler | null = null;
@ -106,16 +108,13 @@ export class Parser extends DiagnosticEmitter {
path: string,
isEntry: bool
): void {
var program = this.program;
// check if already parsed
var normalizedPath = normalizePath(path);
var internalPath = mangleInternalPath(normalizedPath);
var sources = program.sources;
for (let i = 0, k = sources.length; i < k; ++i) {
if (sources[i].internalPath == internalPath) return;
}
this.seenlog.add(internalPath);
// check if already processed
if (this.donelog.has(internalPath)) return;
this.donelog.add(internalPath); // do not parse again
this.seenlog.add(internalPath); // do not request again
// create the source element
var source = new Source(
@ -127,7 +126,8 @@ export class Parser extends DiagnosticEmitter {
? SourceKind.LIBRARY
: SourceKind.DEFAULT
);
sources.push(source);
var program = this.program;
program.sources.push(source);
// mark the special builtins library file
if (source.normalizedPath == builtinsFile) {
@ -350,6 +350,7 @@ export class Parser extends DiagnosticEmitter {
if (this.backlog.length) throw new Error("backlog is not empty");
this.backlog = [];
this.seenlog.clear();
this.donelog.clear();
return this.program;
}
@ -979,6 +980,8 @@ export class Parser extends DiagnosticEmitter {
return null;
}
private parseParametersThis: TypeNode | null = null;
parseParameters(
tn: Tokenizer,
isConstructor: bool = false
@ -990,9 +993,44 @@ export class Parser extends DiagnosticEmitter {
var seenRest: ParameterNode | null = null;
var seenOptional = false;
var reportedRest = false;
var thisType: CommonTypeNode | null = null;
// check if there is a leading `this` parameter
this.parseParametersThis = null;
if (tn.skip(Token.THIS)) {
if (tn.skip(Token.COLON)) {
thisType = this.parseType(tn); // reports
if (!thisType) return null;
if (thisType.kind == NodeKind.TYPE) {
this.parseParametersThis = <TypeNode>thisType;
} else {
this.error(
DiagnosticCode.Operation_not_supported,
thisType.range
);
}
} else {
this.error(
DiagnosticCode._0_expected,
tn.range(), ":"
);
return null;
}
if (!tn.skip(Token.COMMA)) {
if (tn.skip(Token.CLOSEPAREN)) {
return parameters;
} else {
this.error(
DiagnosticCode._0_expected,
tn.range(), ")"
);
return null;
}
}
}
while (!tn.skip(Token.CLOSEPAREN)) {
let param = this.parseParameter(tn, isConstructor);
let param = this.parseParameter(tn, isConstructor); // reports
if (!param) return null;
if (seenRest && !reportedRest) {
this.error(
@ -1187,6 +1225,7 @@ export class Parser extends DiagnosticEmitter {
var parameters = this.parseParameters(tn);
if (!parameters) return null;
var thisType = this.parseParametersThis;
var isSetter = (flags & CommonFlags.SET) != 0;
if (isSetter) {
@ -1234,7 +1273,7 @@ export class Parser extends DiagnosticEmitter {
var signature = Node.createSignature(
parameters,
returnType,
null,
thisType,
false,
tn.range(signatureStart, tn.pos)
);
@ -1349,7 +1388,7 @@ export class Parser extends DiagnosticEmitter {
var signature = Node.createSignature(
parameters,
returnType,
null,
null, // TODO?
false,
tn.range(signatureStart, tn.pos)
);
@ -1653,6 +1692,7 @@ export class Parser extends DiagnosticEmitter {
let signatureStart = tn.tokenPos;
let parameters = this.parseParameters(tn, isConstructor);
if (!parameters) return null;
let thisType = this.parseParametersThis;
if (isConstructor) {
for (let i = 0, k = parameters.length; i < k; ++i) {
let parameter = parameters[i];
@ -1726,7 +1766,7 @@ export class Parser extends DiagnosticEmitter {
let signature = Node.createSignature(
parameters,
returnType,
null,
thisType,
false,
tn.range(signatureStart, tn.pos)
);
@ -1907,7 +1947,7 @@ export class Parser extends DiagnosticEmitter {
}
let ret = Node.createExportStatement(members, path, flags, tn.range(startPos, tn.pos));
let internalPath = ret.internalPath;
if (internalPath != null && !this.seenlog.has(internalPath)) {
if (internalPath !== null && !this.seenlog.has(internalPath)) {
this.backlog.push(internalPath);
this.seenlog.add(internalPath);
}

View File

@ -100,6 +100,7 @@ import {
getConstValueF64,
getConstValueI64Low
} from "./module";
import { CharCode } from "./util";
/** Path delimiter inserted between file system levels. */
export const PATH_DELIMITER = "/";
@ -166,26 +167,79 @@ export enum OperatorKind {
}
function operatorKindFromString(str: string): OperatorKind {
switch (str) {
case "[]" : return OperatorKind.INDEXED_GET;
case "[]=": return OperatorKind.INDEXED_SET;
case "{}" : return OperatorKind.UNCHECKED_INDEXED_GET;
case "{}=": return OperatorKind.UNCHECKED_INDEXED_SET;
case "+" : return OperatorKind.ADD;
case "-" : return OperatorKind.SUB;
case "*" : return OperatorKind.MUL;
case "/" : return OperatorKind.DIV;
case "%" : return OperatorKind.REM;
case "**" : return OperatorKind.POW;
case "&" : return OperatorKind.AND;
case "|" : return OperatorKind.OR;
case "^" : return OperatorKind.XOR;
case "==" : return OperatorKind.EQ;
case "!=" : return OperatorKind.NE;
case ">" : return OperatorKind.GT;
case ">=" : return OperatorKind.GE;
case "<" : return OperatorKind.LT;
case "<=" : return OperatorKind.LE;
assert(str.length);
switch (str.charCodeAt(0)) {
case CharCode.OPENBRACKET: {
switch (str) {
case "[]" : return OperatorKind.INDEXED_GET;
case "[]=": return OperatorKind.INDEXED_SET;
}
break;
}
case CharCode.OPENBRACE: {
switch (str) {
case "{}" : return OperatorKind.UNCHECKED_INDEXED_GET;
case "{}=": return OperatorKind.UNCHECKED_INDEXED_SET;
}
break;
}
case CharCode.PLUS: {
if (str.length == 1) return OperatorKind.ADD;
break;
}
case CharCode.MINUS: {
if (str.length == 1) return OperatorKind.SUB;
break;
}
case CharCode.ASTERISK: {
switch (str) {
case "*" : return OperatorKind.MUL;
case "**": return OperatorKind.POW;
}
break;
}
case CharCode.SLASH: {
if (str.length == 1) return OperatorKind.DIV;
break;
}
case CharCode.PERCENT: {
if (str.length == 1) return OperatorKind.REM;
break;
}
case CharCode.AMPERSAND: {
if (str.length == 1) return OperatorKind.AND;
break;
}
case CharCode.BAR: {
if (str.length == 1) return OperatorKind.OR;
break;
}
case CharCode.CARET: {
if (str.length == 1) return OperatorKind.XOR;
break;
}
case CharCode.EQUALS: {
if (str == "==") return OperatorKind.EQ;
break;
}
case CharCode.EXCLAMATION: {
if (str == "!=") return OperatorKind.NE;
break;
}
case CharCode.GREATERTHAN: {
switch (str) {
case ">" : return OperatorKind.GT;
case ">=": return OperatorKind.GE;
}
break;
}
case CharCode.LESSTHAN: {
switch (str) {
case "<" : return OperatorKind.LT;
case "<=": return OperatorKind.LE;
}
break;
}
}
return OperatorKind.INVALID;
}
@ -1674,7 +1728,7 @@ export class Program extends DiagnosticEmitter {
);
if (!thisType) return null;
}
var parameterTypeNodes = node.parameterTypes;
var parameterTypeNodes = node.parameters;
var numParameters = parameterTypeNodes.length;
var parameterTypes = new Array<Type>(numParameters);
var parameterNames = new Array<string>(numParameters);
@ -2664,7 +2718,7 @@ export class FunctionPrototype extends Element {
}
// resolve signature node
var signatureParameters = signatureNode.parameterTypes;
var signatureParameters = signatureNode.parameters;
var signatureParameterCount = signatureParameters.length;
var parameterTypes = new Array<Type>(signatureParameterCount);
var parameterNames = new Array<string>(signatureParameterCount);

View File

@ -173,7 +173,8 @@ export enum IdentifierHandling {
}
export function tokenFromKeyword(text: string): Token {
switch (text.length && text.charCodeAt(0)) {
assert(text.length);
switch (text.charCodeAt(0)) {
case CharCode.a: {
switch (text) {
case "abstract": return Token.ABSTRACT;