src/resolver/base.js (237 lines of code) (raw):

'use strict'; const debug = require('../lib/debug'); const { AnnotationItem, TypeString, TypeArray, TypeInteger, TypeBytes, TypeMap, TypeObject, TypeGeneric, TypeStream, TypeVoid, TypeNumber, TypeBool, TypeNull, TypeDecimal } = require('../langs/common/items'); const { _isBasicType, _escape, _string } = require('../lib/helper'); const DSL = require('@darabonba/parser'); class BaseResolver { constructor(astNode, combinator, globalAst) { this.ast = astNode; this.combinator = combinator; this.config = combinator.config; this.comments = globalAst.comments ? globalAst.comments : {}; this.commentsSet = []; } resolveAnnotations(annotations, belong) { if (annotations.length > 0) { let comments = []; annotations.forEach(annotation => { comments.push(this.resolveAnnotation(annotation, belong)); }); return comments; } return []; } resolveAnnotation(annotation, belong) { let type = annotation.value.indexOf('/**') === 0 ? 'multi' : 'single'; let content = ''; if (type === 'multi') { content = annotation.value.substring(3, annotation.value.length - 2) .trim().split('\n').filter(c => c.length > 0).map(c => { if (c.indexOf(' * ') === 0) { return c.substring(3); } else if (c.indexOf('* ') === 0) { return c.substring(2); } return c; }); } else { content = annotation.value.substring(2).trim(); } return new AnnotationItem(belong, type, content); } getBackComments(index) { return DSL.comment.getBackComments(this.comments, index); } getBetweenComments(begin, end) { return DSL.comment.getBetweenComments(this.comments, begin, end); } getFrontComments(index) { return DSL.comment.getFrontComments(this.comments, index); } getComments(node, position = 'front') { if (typeof node.tokenRange === 'undefined') { return []; } switch (position) { case 'back': return this.getBackComments(node.tokenRange[1]); case 'between': return this.getBetweenComments(node.tokenRange[0], node.tokenRange[1]); default: return this.getFrontComments(node.tokenRange[0]); } } addAnnotations(obj, node, position = 'front') { let comments = this.getComments(node, position); if (comments.length > 0) { comments.forEach(c => { if (this.commentsSet.indexOf(c.index) < 0) { if (typeof obj.annotations !== 'undefined') { obj.annotations.push(this.resolveAnnotation(c, obj.index)); } else { debug.stack(obj, node); } this.commentsSet.push(c.index); } }); } } findComments(obj, node, position = 'front') { let comments = this.getComments(node, position); if (comments.length > 0) { comments.forEach(c => { if (this.commentsSet.indexOf(c.index) < 0) { if (typeof obj.body !== 'undefined') { obj.body.push(this.resolveAnnotation(c, obj.index)); } else if (typeof obj.value !== 'undefined') { obj.value.push(this.resolveAnnotation(c, obj.index)); } else { debug.stack('Invalid data node', obj, node); } this.commentsSet.push(c.index); } }); } } initAnnotation(annotation) { let topComments = this.getFrontComments(annotation.index); topComments.map(c => { this.object.topAnnotation.push(this.resolveAnnotation(c, this.object.index)); }); if (annotation && annotation.value) { this.object.annotations.push(this.resolveAnnotation(annotation, this.object.index)); } } resolveTypeItem(typeNode, sourceNode = null) { if (typeNode.idType) { if (typeNode.idType === 'model') { return new TypeObject(`#${typeNode.lexeme}`); } else if (typeNode.idType === 'module') { return new TypeObject(`^${typeNode.lexeme}`); } else if (typeNode.idType === 'builtin_model') { return new TypeObject(`^${typeNode.lexeme}`); } debug.stack(typeNode, sourceNode); } else if (typeNode.type) { if (typeNode.type === 'fieldType') { if (typeNode.fieldType.idType) { if (typeNode.fieldType.idType === 'module') { return new TypeObject(`^${typeNode.fieldType.lexeme}`); } return new TypeObject(`#${typeNode.fieldType.lexeme}`); } return this.resolveTypeItem(typeNode.fieldType, typeNode); } else if (typeNode.type === 'modelBody') { // is sub model const modelName = `#${[this.object.name, _escape(sourceNode.fieldName.lexeme) || _string(sourceNode.fieldName)].join('.')}`; return new TypeObject(modelName); } else if (_isBasicType(typeNode.type)) { return this.resolveTypeItem(typeNode.type, typeNode); } else if (typeNode.type === 'basic') { return this.resolveTypeItem(typeNode.name, sourceNode); } else if (typeNode.type === 'model') { let name = typeNode.name; if (typeNode.moduleName) { name = typeNode.moduleName + '.' + name; } return new TypeObject(`#${name}`); } else if (typeNode.type === 'module_instance') { return new TypeObject(`^${typeNode.name}`); } else if (typeNode.type === 'param') { if (typeNode.paramType.idType) { return new TypeObject(`#${typeNode.paramType.lexeme}`); } return this.resolveTypeItem(typeNode.paramType, typeNode); } else if (typeNode.type === 'array') { const subType = typeNode.subType ? typeNode.subType : typeNode.itemType; return new TypeArray(this.resolveTypeItem(subType)); } else if (typeNode.type === 'moduleModel') { let tmp = []; typeNode.path.forEach(item => { tmp.push(item.lexeme); }); return new TypeObject(`#${tmp.join('.')}`); } else if (typeNode.type === 'subModel' || typeNode.type === 'subModel_or_moduleModel') { // subModel_or_moduleModel is retained for compatibility with older parser. let tmp = []; typeNode.path.forEach(item => { tmp.push(item.lexeme); }); return new TypeObject(`#${tmp.join('.')}`); } debug.stack(typeNode, sourceNode); } else if (typeNode.lexeme) { return this.resolveTypeItem(typeNode.lexeme, sourceNode); } else if (typeNode === 'string') { return new TypeString(); } else if (typeNode === 'bytes') { return new TypeBytes(); } else if (typeNode === 'array') { let itemType; if (sourceNode.fieldItemType.type === 'modelBody') { itemType = new TypeObject(`#${sourceNode.itemType}`); } else if (sourceNode.fieldItemType.idType === 'model') { itemType = new TypeObject(`#${sourceNode.fieldItemType.lexeme}`); } else { itemType = this.resolveTypeItem(sourceNode.fieldItemType, sourceNode); } return new TypeArray(itemType); } else if (typeNode === 'map') { const keyType = this.resolveTypeItem(sourceNode.keyType); const valType = this.resolveTypeItem(sourceNode.valueType); return new TypeMap(keyType, valType); } else if (typeNode === 'any') { return new TypeGeneric(); } else if (typeNode === 'object') { return new TypeMap(new TypeString(), new TypeGeneric()); } else if (typeNode === 'integer') { return new TypeInteger(); } else if (typeNode === 'readable') { return new TypeStream(false); } else if (typeNode === 'writable') { return new TypeStream(true); } else if (typeNode === 'class') { return new TypeObject(); } else if (typeNode === 'void') { return new TypeVoid(); } else if (typeNode === 'number') { return new TypeNumber(); } else if (typeNode === 'boolean') { return new TypeBool(); } else if (typeNode === 'null') { return new TypeNull(); } else if (typeNode === 'float') { return new TypeDecimal(4); } else if (typeNode === 'double') { return new TypeDecimal(8); } else if (typeNode === 'long') { return new TypeInteger(64); } else if (typeNode === 'ulong') { return new TypeInteger(64, true); } else if (typeNode.indexOf('int') === 0) { let len = typeNode.substring(3); return new TypeInteger(parseInt(len)); } else if (typeNode.indexOf('uint') === 0) { let len = typeNode.substring(4); return new TypeInteger(parseInt(len), true); } if (typeof typeNode === 'string' && typeNode.length > 0) { return new TypeObject(`#${typeNode}`); } debug.stack('Unsupported type node', { typeNode, sourceNode }); } } module.exports = BaseResolver;