From 9c21e257937f4757dea11065938f40267daf1d59 Mon Sep 17 00:00:00 2001 From: Yesterday17 Date: Mon, 28 Jan 2019 17:15:48 +0800 Subject: [PATCH] Function Declaration Interpreter. --- server/parser/index.d.ts | 15 ++++-- server/parser/zsInterpreter.ts | 95 +++++++++++++++++++++++----------- server/parser/zsParser.ts | 91 +++++++++++++++++--------------- server/server.ts | 14 ++++- 4 files changed, 139 insertions(+), 76 deletions(-) diff --git a/server/parser/index.d.ts b/server/parser/index.d.ts index dd5b821..dd7bb5c 100644 --- a/server/parser/index.d.ts +++ b/server/parser/index.d.ts @@ -10,9 +10,10 @@ export interface ASTNode { export interface ASTNodeProgram extends ASTNode { type: string = 'program'; - import: []; - global: []; - static: []; + import: Map; + global: Map; + static: Map; + function: Map; } export interface ASTNodeDeclare extends ASTNode { @@ -22,6 +23,14 @@ export interface ASTNodeDeclare extends ASTNode { value: any; } +export interface ASTNodeFunction extends ASTNode { + type: 'function'; + fName: string; + fPara: any[]; + fType: any; + fBody: any; +} + export interface ASTNodePackage extends ASTNode { type: string = 'package'; item: string[]; diff --git a/server/parser/zsInterpreter.ts b/server/parser/zsInterpreter.ts index f3470a5..94462e0 100644 --- a/server/parser/zsInterpreter.ts +++ b/server/parser/zsInterpreter.ts @@ -7,6 +7,7 @@ import { ASTNodeProgram, NodeContext, ASTNodeMap, + ASTNodeFunction, } from '.'; import { ZSParser } from './zsParser'; @@ -19,9 +20,10 @@ class ZenScriptInterpreter extends ZSParser.getBaseCstVisitorConstructor() { public Program(ctx: NodeContext): ASTNodeProgram { const program: ASTNodeProgram = { type: 'program', - import: [], - global: [], - static: [], + import: new Map(), + global: new Map(), + static: new Map(), + function: new Map(), }; if (ctx.ImportList) { @@ -30,8 +32,23 @@ class ZenScriptInterpreter extends ZSParser.getBaseCstVisitorConstructor() { if (ctx.GlobalStaticDeclaration) { ctx.GlobalStaticDeclaration.forEach((element: any) => { - const node = this.visit(element); - program[node.type].push(node); + const node: ASTNodeDeclare = this.visit(element); + if (!program[node.type].has(node.vName)) { + program[node.type].set(node.vName, node); + } else { + // TODO: Error + } + }); + } + + if (ctx.FunctionDeclaration) { + ctx.FunctionDeclaration.forEach((element: any) => { + const func: ASTNodeFunction = this.visit(element); + if (!program.function.has(func.fName)) { + program.function.set(func.fName, func); + } else { + // TODO: Error + } }); } @@ -44,9 +61,7 @@ class ZenScriptInterpreter extends ZSParser.getBaseCstVisitorConstructor() { */ public ImportList(ctx: NodeContext) { - const packages = ctx.Package.map((pkg: CstNode) => this.visit(pkg)); - - return packages; + return ctx.Package.map((pkg: CstNode) => this.visit(pkg)); } public GlobalStaticDeclaration(ctx: NodeContext): ASTNodeDeclare { @@ -69,9 +84,13 @@ class ZenScriptInterpreter extends ZSParser.getBaseCstVisitorConstructor() { return declaration; } - public FunctionDeclaration(ctx: NodeContext): ASTNode { + public FunctionDeclaration(ctx: NodeContext): ASTNodeFunction { return { type: 'function', + fName: ctx.FunctionName[0].image, + fPara: ctx.ParameterList ? this.visit(ctx.ParameterList) : [], + fType: ctx.TypeDeclare ? this.visit(ctx.TypeDeclare) : 'any', + fBody: this.visit(ctx.StatementBody), }; } @@ -251,18 +270,25 @@ class ZenScriptInterpreter extends ZSParser.getBaseCstVisitorConstructor() { }; } + // TODO: Debug protected InBracket(ctx: NodeContext): ASTNode { - return { - type: 'inbracket', - }; + return this.visit(ctx.AssignExpression); } + // TODO: Debug protected BracketHandler(ctx: NodeContext): ASTNode { return { type: 'bracket-handler', + item: ctx.$BracketHandlerItem.map((item: any) => this.visit(item)), }; } + // TODO: Debug + protected BracketHandler$BracketHandlerItem(ctx: NodeContext) { + return ctx[Object.keys(ctx)[0]].image; + } + + // TODO: Debug protected ZSArray(ctx: NodeContext): ASTNodeArray { const arr: any[] = []; if (ctx.AssignExpression) { @@ -277,20 +303,19 @@ class ZenScriptInterpreter extends ZSParser.getBaseCstVisitorConstructor() { }; } + // TODO: Debug protected ZSMap(ctx: NodeContext): ASTNodeMap { const map = new Map(); - if (ctx.KEY) { - const keys = ctx.KEY.map((key: any) => this.visit(key)); - const values = ctx.VALUE.map((value: any) => this.visit(value)); - for (const i in keys) { - if (keys.hasOwnProperty(i) && values.hasOwnProperty(i)) { - if (map.has(keys[i])) { - // TODO: throw error here. - } else { - map.set(keys[i], values[i]); - } + + if (ctx.$MapEntry) { + ctx.$MapEntry.forEach((entry: any) => { + const e = this.visit(entry); + if (!map.has(e[0])) { + map.set(e[0], e[1]); + } else { + // TODO: Error here. } - } + }); } return { @@ -299,6 +324,11 @@ class ZenScriptInterpreter extends ZSParser.getBaseCstVisitorConstructor() { }; } + // TODO: Debug + protected ZSMap$MapEntry(ctx: NodeContext) { + return [this.visit(ctx.KEY), this.visit(ctx.VALUE)]; + } + protected Package(ctx: NodeContext): ASTNodePackage { return { type: 'package', @@ -306,15 +336,20 @@ class ZenScriptInterpreter extends ZSParser.getBaseCstVisitorConstructor() { }; } + // TODO: Debug protected ParameterList(ctx: NodeContext): ASTNode { return { type: 'parameter-list', + item: ctx.Parameter.map((item: any) => this.visit(item)), }; } + // TODO: Debug protected Parameter(ctx: NodeContext): ASTNode { return { type: 'parameter', + pName: ctx.IDENTIFIER[0].image, + pType: ctx.TypeDeclare ? this.visit(ctx.TypeDeclare[0]) : undefined, }; } @@ -323,13 +358,6 @@ class ZenScriptInterpreter extends ZSParser.getBaseCstVisitorConstructor() { } protected TypeAnnotation(ctx: NodeContext): ASTNode { - // Type from ANY - STRING - if (Object.keys(ctx).length === 1) { - return { - type: Object.keys(ctx)[0], - }; - } - // Imported type if (ctx.IDENTIFIER) { return { @@ -338,6 +366,13 @@ class ZenScriptInterpreter extends ZSParser.getBaseCstVisitorConstructor() { }; } + // Type from ANY - STRING + if (Object.keys(ctx).length === 1) { + return { + type: Object.keys(ctx)[0], + }; + } + // Function type if (ctx.FUNCTION) { return { diff --git a/server/parser/zsParser.ts b/server/parser/zsParser.ts index 99d9a12..325d696 100644 --- a/server/parser/zsParser.ts +++ b/server/parser/zsParser.ts @@ -18,7 +18,6 @@ import { DOT, DOT2, DOUBLE, - DOUBLE_QUOTED_STRING, ELSE, EQ, FALSE, @@ -50,7 +49,6 @@ import { RETURN, SEMICOLON, SHORT, - SINGLE_QUOTED_STRING, SQBR_CLOSE, SQBR_OPEN, STATIC, @@ -166,7 +164,10 @@ export class ZenScriptParser extends Parser { */ protected FunctionDeclaration = this.RULE('FunctionDeclaration', () => { this.CONSUME(FUNCTION); - this.CONSUME(IDENTIFIER, { ERR_MSG: 'Identifier Expected.' }); + this.CONSUME(IDENTIFIER, { + LABEL: 'FunctionName', + ERR_MSG: 'Identifier Expected.', + }); this.CONSUME(BR_OPEN, { ERR_MSG: `Missing '('` }); this.OPTION(() => { this.SUBRULE(this.ParameterList); @@ -532,44 +533,49 @@ export class ZenScriptParser extends Parser { protected BracketHandler = this.RULE('BracketHandler', () => { this.CONSUME(LT); - this.AT_LEAST_ONE(() => { - this.OR([ - { ALT: () => this.CONSUME(IDENTIFIER) }, - { ALT: () => this.CONSUME(INT_VALUE) }, - { ALT: () => this.CONSUME(MUL) }, - { ALT: () => this.CONSUME(MINUS) }, - { ALT: () => this.CONSUME(COLON) }, - { ALT: () => this.CONSUME(DOT) }, - { ALT: () => this.CONSUME(ANY) }, - { ALT: () => this.CONSUME(BOOL) }, - { ALT: () => this.CONSUME(BYTE) }, - { ALT: () => this.CONSUME(SHORT) }, - { ALT: () => this.CONSUME(INT) }, - { ALT: () => this.CONSUME(LONG) }, - { ALT: () => this.CONSUME(FLOAT) }, - { ALT: () => this.CONSUME(DOUBLE) }, - { ALT: () => this.CONSUME(STRING) }, - { ALT: () => this.CONSUME(FUNCTION) }, - { ALT: () => this.CONSUME(IN) }, - { ALT: () => this.CONSUME(VOID) }, - { ALT: () => this.CONSUME(AS) }, - { ALT: () => this.CONSUME(VERSION) }, - { ALT: () => this.CONSUME(IF) }, - { ALT: () => this.CONSUME(ELSE) }, - { ALT: () => this.CONSUME(FOR) }, - { ALT: () => this.CONSUME(RETURN) }, - { ALT: () => this.CONSUME(VAR) }, - { ALT: () => this.CONSUME(VAL) }, - { ALT: () => this.CONSUME(GLOBAL_ZS) }, - { ALT: () => this.CONSUME(STATIC) }, - { ALT: () => this.CONSUME(INSTANCEOF) }, - { ALT: () => this.CONSUME(WHILE) }, - { ALT: () => this.CONSUME(BREAK) }, - { ALT: () => this.CONSUME(NULL) }, - { ALT: () => this.CONSUME(TRUE) }, - { ALT: () => this.CONSUME(FALSE) }, - { ALT: () => this.CONSUME(IMPORT) }, - ]); + this.AT_LEAST_ONE_SEP({ + SEP: COLON, + DEF: () => { + this.OR({ + NAME: '$BracketHandlerItem', + DEF: [ + { ALT: () => this.CONSUME(IDENTIFIER) }, + { ALT: () => this.CONSUME(INT_VALUE) }, + { ALT: () => this.CONSUME(MUL) }, + { ALT: () => this.CONSUME(MINUS) }, + { ALT: () => this.CONSUME(DOT) }, + { ALT: () => this.CONSUME(ANY) }, + { ALT: () => this.CONSUME(BOOL) }, + { ALT: () => this.CONSUME(BYTE) }, + { ALT: () => this.CONSUME(SHORT) }, + { ALT: () => this.CONSUME(INT) }, + { ALT: () => this.CONSUME(LONG) }, + { ALT: () => this.CONSUME(FLOAT) }, + { ALT: () => this.CONSUME(DOUBLE) }, + { ALT: () => this.CONSUME(STRING) }, + { ALT: () => this.CONSUME(FUNCTION) }, + { ALT: () => this.CONSUME(IN) }, + { ALT: () => this.CONSUME(VOID) }, + { ALT: () => this.CONSUME(AS) }, + { ALT: () => this.CONSUME(VERSION) }, + { ALT: () => this.CONSUME(IF) }, + { ALT: () => this.CONSUME(ELSE) }, + { ALT: () => this.CONSUME(FOR) }, + { ALT: () => this.CONSUME(RETURN) }, + { ALT: () => this.CONSUME(VAR) }, + { ALT: () => this.CONSUME(VAL) }, + { ALT: () => this.CONSUME(GLOBAL_ZS) }, + { ALT: () => this.CONSUME(STATIC) }, + { ALT: () => this.CONSUME(INSTANCEOF) }, + { ALT: () => this.CONSUME(WHILE) }, + { ALT: () => this.CONSUME(BREAK) }, + { ALT: () => this.CONSUME(NULL) }, + { ALT: () => this.CONSUME(TRUE) }, + { ALT: () => this.CONSUME(FALSE) }, + { ALT: () => this.CONSUME(IMPORT) }, + ], + }); + }, }); this.CONSUME(GT); }); @@ -588,6 +594,7 @@ export class ZenScriptParser extends Parser { protected ZSMap = this.RULE('ZSMap', () => { this.CONSUME(A_OPEN); this.MANY_SEP({ + NAME: '$MapEntry', SEP: COMMA, DEF: () => { this.SUBRULE(this.AssignExpression, { LABEL: 'KEY' }); @@ -608,7 +615,7 @@ export class ZenScriptParser extends Parser { }); protected ParameterList = this.RULE('ParameterList', () => { - this.MANY_SEP({ + this.AT_LEAST_ONE_SEP({ SEP: COMMA, DEF: () => this.SUBRULE(this.Parameter), }); diff --git a/server/server.ts b/server/server.ts index b3b3100..8642fbd 100644 --- a/server/server.ts +++ b/server/server.ts @@ -36,6 +36,7 @@ import { reloadRCFile } from './utils/zsrcFile'; import { PreProcessorCompletions } from './completion/preprocessor/preprocessors'; import { ZenScriptSettings } from './api'; import { ZSInterpreter } from './parser/zsInterpreter'; +import { ASTNodeProgram } from './parser'; // 创建一个服务的连接,连接使用 Node 的 IPC 作为传输 // 并且引入所有 LSP 特性, 包括 preview / proposed @@ -190,9 +191,20 @@ async function validateTextDocument(textDocument: TextDocument): Promise { documentTokens.set(textDocument.uri, lexResult.tokens); // save parsing result documentCSTs.set(textDocument.uri, ZSParser.parse(lexResult.tokens)); + // FIXME: debug + const ast: ASTNodeProgram = ZSInterpreter.visit( + documentCSTs.get(textDocument.uri) + ); connection.console.log( - JSON.stringify(ZSInterpreter.visit(documentCSTs.get(textDocument.uri))) + JSON.stringify({ + type: ast.type, + import: ast.import, + global: Array.from(ast.global), + static: Array.from(ast.static), + function: Array.from(ast.function), + error: ast.errors, + }) ); // save errors