def parse_enum(self, leading_trivia, is_exported): if not self.reader.read_token("enum"): return None enum_start = self.reader.prev_token_offset name = self.reader.expect_identifier( "expected identifier after 'enum' keyword") self.context.append(f'''E:{name}''') members = [] self.reader.expect_token("{") if not self.reader.read_token("}"): while True: if self.reader.peek_token("}"): break # eg. "enum { A, B, }" (but multiline) enum_member = types.EnumMember(self.reader.expect_identifier()) members.append(enum_member) self.node_manager.add_node(enum_member, self.reader.prev_token_offset) # TODO: generated code compatibility self.reader.read_token(f'''= "{enum_member.name}"''') if not (self.reader.read_token(",")): break self.reader.expect_token("}") enum_obj = types.Enum(name, members, is_exported, leading_trivia) self.node_manager.add_node(enum_obj, enum_start) self.context.pop() return enum_obj
def new_workspace(self, pkg_name="@"): self.workspace = types.Workspace() for intf_pkg in self.pac_man.interfaces_pkgs: lib_name = f'''{intf_pkg.interface_yaml.vendor}.{intf_pkg.interface_yaml.name}-v{intf_pkg.interface_yaml.version}''' self.add_interface_package(lib_name, intf_pkg.definition) self.project_pkg = types.Package(pkg_name, False) self.workspace.add_package(self.project_pkg)
def add_interface_package(self, lib_name, definition_file_content): lib_pkg = types.Package(lib_name, True) file = typeScrPars.TypeScriptParser2.parse_file( definition_file_content, types.SourcePath(lib_pkg, types.Package.index)) self.setup_file(file) lib_pkg.add_file(file, True) self.workspace.add_package(lib_pkg)
def calculate_import_scope(cls, curr_scope, import_file): if import_file.startswith("."): # relative return types.ExportScopeRef( curr_scope.package_name, TypeScriptParser2.calculate_relative_path( curr_scope.scope_name, import_file)) else: path = re.split("/", import_file) pkg_name = path.pop(0) return types.ExportScopeRef( pkg_name, types.Package.index if len(path) == 0 else "/".join(path))
def resolve_type(self, type, must_resolve_all_generics): if isinstance(type, astTypes.GenericsType): resolved_type = self.resolution_map.get(type.type_var_name) if resolved_type == None and must_resolve_all_generics: raise Error( f'''Could not resolve generics type: {type.repr()}''') return resolved_type if resolved_type != None else type elif isinstance(type, astTypes.ClassType): return astTypes.ClassType( type.decl, list( map( lambda x: self.resolve_type(x, must_resolve_all_generics), type.type_arguments))) elif isinstance(type, astTypes.InterfaceType): return astTypes.InterfaceType( type.decl, list( map( lambda x: self.resolve_type(x, must_resolve_all_generics), type.type_arguments))) elif isinstance(type, astTypes.LambdaType): return astTypes.LambdaType( list( map( lambda x: types.MethodParameter( x.name, self.resolve_type(x.type, must_resolve_all_generics ), x.initializer, None), type.parameters)), self.resolve_type(type.return_type, must_resolve_all_generics)) else: return type
def infix_prehook(self, left): if isinstance( left, exprs.PropertyAccessExpression ) and self.reader.peek_regex("<[A-Za-z0-9_<>]*?>\\(") != None: type_args = self.parse_type_args() self.reader.expect_token("(") args = self.expression_parser.parse_call_arguments() return exprs.UnresolvedCallExpression(left, type_args, args) elif self.reader.read_token("instanceof"): type = self.parse_type() return exprs.InstanceOfExpression(left, type) elif isinstance(left, exprs.Identifier) and self.reader.read_token("=>"): block = self.parse_lambda_block() return types.Lambda( [types.MethodParameter(left.text, None, None, None)], block) return None
def parse_import(self, leading_trivia): if not self.reader.read_token("import"): return None import_start = self.reader.prev_token_offset import_all_alias = None import_parts = [] if self.reader.read_token("*"): self.reader.expect_token("as") import_all_alias = self.reader.expect_identifier() else: self.reader.expect_token("{") while True: if self.reader.peek_token("}"): break imp = self.reader.expect_identifier() if self.reader.read_token("as"): self.reader.fail("This is not yet supported") import_parts.append(types.UnresolvedImport(imp)) self.node_manager.add_node(imp, self.reader.prev_token_offset) if not (self.reader.read_token(",")): break self.reader.expect_token("}") self.reader.expect_token("from") module_name = self.reader.expect_string() self.reader.expect_token(";") import_scope = TypeScriptParser2.calculate_import_scope( self.export_scope, module_name) if self.export_scope != None else None imports = [] if len(import_parts) > 0: imports.append( types.Import(import_scope, False, import_parts, None, leading_trivia)) if import_all_alias != None: imports.append( types.Import(import_scope, True, None, import_all_alias, leading_trivia)) #this.nodeManager.addNode(imports, importStart); return imports
def parse_lambda_params(self): if not self.reader.read_token("("): return None params = [] if not self.reader.read_token(")"): while True: param_name = self.reader.expect_identifier() type = self.parse_type() if self.reader.read_token( ":") else None params.append( types.MethodParameter(param_name, type, None, None)) if not (self.reader.read_token(",")): break self.reader.expect_token(")") return params
def __init__(self, source, path=None): self.context = [] self.reader = None self.expression_parser = None self.node_manager = None self.export_scope = None self.missing_return_type_is_void = False self.allow_dollar_ids = False self.path = path self.reader = read.Reader(source) self.reader.hooks = self self.node_manager = nodeMan.NodeManager(self.reader) self.expression_parser = self.create_expression_parser( self.reader, self.node_manager) self.export_scope = types.ExportScopeRef( self.path.pkg.name, re.sub("\\.ts$", "", self.path.path) if self.path.path != None else None) if self.path != None else None
def setup_file(self, file): file.add_available_symbols(self.native_exports.get_all_exports()) file.literal_types = types.LiteralTypes( (file.available_symbols.get("TsBoolean")).type, (file.available_symbols.get("TsNumber")).type, (file.available_symbols.get("TsString")).type, (file.available_symbols.get("RegExp")).type, (file.available_symbols.get("TsArray")).type, (file.available_symbols.get("TsMap")).type, (file.available_symbols.get("Error")).type, (file.available_symbols.get("Promise")).type) file.array_types = [ (file.available_symbols.get("TsArray")).type, (file.available_symbols.get("IterableIterator")).type, (file.available_symbols.get("RegExpExecArray")).type, (file.available_symbols.get("TsString")).type, (file.available_symbols.get("Set")).type ]
def visit_expression(self, expr): expr = super().visit_expression(expr) if isinstance(expr, exprs.NullCoalesceExpression): if isinstance(expr.default_expr, refs.InstanceFieldReference) or isinstance( expr.default_expr, refs.StaticFieldReference): return expr var_name = self.var_names.use_name( self.expr_naming.get_name_for(expr.default_expr)) var_decl = stats.VariableDeclaration(var_name, expr.default_expr.get_type(), expr.default_expr) var_decl.mutability = types.MutabilityInfo(False, False, False) self.statements.append(var_decl) expr.default_expr = refs.VariableDeclarationReference(var_decl) return expr
def parse_class(self, leading_trivia, is_exported, declaration_only): cls_modifiers = self.reader.read_modifiers(["abstract"]) if not self.reader.read_token("class"): return None cls_start = self.reader.prev_token_offset cls_name = self.reader.expect_identifier( "expected identifier after 'class' keyword") self.context.append(f'''C:{cls_name}''') type_args = self.parse_generics_args() base_class = self.parse_specified_type() if self.reader.read_token( "extends") else None base_interfaces = [] if self.reader.read_token("implements"): while True: base_interfaces.append(self.parse_specified_type()) if not (self.reader.read_token(",")): break constructor = None fields = [] methods = [] properties = [] self.reader.expect_token("{") while not self.reader.read_token("}"): member_leading_trivia = self.reader.read_leading_trivia() member_start = self.reader.offset modifiers = self.reader.read_modifiers([ "static", "public", "protected", "private", "readonly", "async", "abstract" ]) is_static = "static" in modifiers is_async = "async" in modifiers is_abstract = "abstract" in modifiers visibility = types.VISIBILITY.PRIVATE if "private" in modifiers else types.VISIBILITY.PROTECTED if "protected" in modifiers else types.VISIBILITY.PUBLIC member_name = self.parse_identifier_or_string() method_type_args = self.parse_generics_args() if self.reader.read_token("("): # method is_constructor = member_name == "constructor" sig = self.parse_method_signature( is_constructor, declaration_only or is_abstract) if is_constructor: member = constructor = types.Constructor( sig.params, sig.body, sig.super_call_args, member_leading_trivia) for field in sig.fields: fields.append(field) else: method = types.Method(member_name, method_type_args, sig.params, sig.body, visibility, is_static, sig.returns, is_async, member_leading_trivia) methods.append(method) member = method self.node_manager.add_node(member, member_start) elif member_name == "get" or member_name == "set": # property prop_name = self.reader.expect_identifier() prop = next(filter(lambda x: x.name == prop_name, properties), None) prop_type = None getter = None setter = None if member_name == "get": # get propName(): propType { return ... } self.context.append(f'''P[G]:{prop_name}''') self.reader.expect_token( "()", "expected '()' after property getter name") prop_type = self.parse_type() if self.reader.read_token( ":") else None if declaration_only: if prop_type == None: self.reader.fail( "Type is missing for property in declare class" ) self.reader.expect_token(";") else: getter = self.expect_block( "property getter body is missing") if prop != None: prop.getter = getter elif member_name == "set": # set propName(value: propType) { ... } self.context.append(f'''P[S]:{prop_name}''') self.reader.expect_token( "(", "expected '(' after property setter name") self.reader.expect_identifier() prop_type = self.parse_type() if self.reader.read_token( ":") else None self.reader.expect_token(")") if declaration_only: if prop_type == None: self.reader.fail( "Type is missing for property in declare class" ) self.reader.expect_token(";") else: setter = self.expect_block( "property setter body is missing") if prop != None: prop.setter = setter if prop == None: prop = types.Property(prop_name, prop_type, getter, setter, visibility, is_static, member_leading_trivia) properties.append(prop) self.node_manager.add_node(prop, member_start) self.context.pop() else: self.context.append(f'''F:{member_name}''') type_and_init = self.parse_type_and_init() self.reader.expect_token(";") field = types.Field(member_name, type_and_init.type, type_and_init.init, visibility, is_static, None, member_leading_trivia) fields.append(field) self.node_manager.add_node(field, member_start) self.context.pop() cls_ = types.Class(cls_name, type_args, base_class, base_interfaces, fields, properties, constructor, methods, is_exported, leading_trivia) self.node_manager.add_node(cls_, cls_start) self.context.pop() return cls_
def get_var(self, var_ref): v = var_ref.get_variable() if v.mutability == None: v.mutability = types.MutabilityInfo(True, False, False) return v
def unary_prehook(self): if self.reader.read_token("null"): return exprs.NullLiteral() elif self.reader.read_token("true"): return exprs.BooleanLiteral(True) elif self.reader.read_token("false"): return exprs.BooleanLiteral(False) elif self.reader.read_token("`"): parts = [] lit_part = "" while True: if self.reader.read_exactly("`"): if lit_part != "": parts.append( exprs.TemplateStringPart.literal(lit_part)) lit_part = "" break elif self.reader.read_exactly("${"): if lit_part != "": parts.append( exprs.TemplateStringPart.literal(lit_part)) lit_part = "" expr = self.parse_expression() parts.append(exprs.TemplateStringPart.expression(expr)) self.reader.expect_token("}") elif self.allow_dollar_ids and self.reader.read_exactly("$"): if lit_part != "": parts.append( exprs.TemplateStringPart.literal(lit_part)) lit_part = "" id = self.reader.read_identifier() parts.append( exprs.TemplateStringPart.expression( exprs.Identifier(id))) elif self.reader.read_exactly("\\"): chr = self.reader.read_char() if chr == "n": lit_part += "\n" elif chr == "r": lit_part += "\r" elif chr == "t": lit_part += "\t" elif chr == "`": lit_part += "`" elif chr == "$": lit_part += "$" elif chr == "\\": lit_part += "\\" else: self.reader.fail("invalid escape", self.reader.offset - 1) else: chr = self.reader.read_char() chr_code = ord(chr[0]) if not (32 <= chr_code and chr_code <= 126) or chr == "`" or chr == "\\": self.reader.fail( f'''not allowed character (code={chr_code})''', self.reader.offset - 1) lit_part += chr return exprs.TemplateString(parts) elif self.reader.read_token("new"): type = self.parse_type() if isinstance(type, astTypes.UnresolvedType): self.reader.expect_token("(") args = self.expression_parser.parse_call_arguments() return exprs.UnresolvedNewExpression(type, args) else: raise Error( f'''[TypeScriptParser2] Expected UnresolvedType here!''') elif self.reader.read_token("<"): new_type = self.parse_type() self.reader.expect_token(">") expression = self.parse_expression() return exprs.CastExpression(new_type, expression) elif self.reader.read_token("/"): pattern = "" while True: chr = self.reader.read_char() if chr == "\\": chr2 = self.reader.read_char() pattern += "/" if chr2 == "/" else "\\" + chr2 elif chr == "/": break else: pattern += chr modifiers = self.reader.read_modifiers(["g", "i"]) return exprs.RegexLiteral(pattern, "i" in modifiers, "g" in modifiers) elif self.reader.read_token("typeof"): expr = self.expression_parser.parse( self.expression_parser.prefix_precedence) self.reader.expect_token("===") check = self.reader.expect_string() ts_type = None if check == "string": ts_type = "TsString" elif check == "boolean": ts_type = "TsBoolean" elif check == "object": ts_type = "Object" elif check == "function": # TODO: ??? ts_type = "Function" elif check == "undefined": # TODO: ??? ts_type = "Object" else: self.reader.fail("unexpected typeof comparison") return exprs.InstanceOfExpression( expr, astTypes.UnresolvedType(ts_type, [])) elif self.reader.peek_regex("\\([A-Za-z0-9_]+\\s*[:,]|\\(\\)") != None: params = self.parse_lambda_params() self.reader.expect_token("=>") block = self.parse_lambda_block() return types.Lambda(params, block) elif self.reader.read_token("await"): expression = self.parse_expression() return exprs.AwaitExpression(expression) map_literal = self.expression_parser.parse_map_literal() if map_literal != None: return map_literal array_literal = self.expression_parser.parse_array_literal() if array_literal != None: return array_literal return None
def parse_method_signature(self, is_constructor, declaration_only): params = [] fields = [] if not self.reader.read_token(")"): while True: leading_trivia = self.reader.read_leading_trivia() param_start = self.reader.offset is_public = self.reader.read_token("public") if is_public and not is_constructor: self.reader.fail( "public modifier is only allowed in constructor definition" ) param_name = self.reader.expect_identifier() self.context.append(f'''arg:{param_name}''') type_and_init = self.parse_type_and_init() param = types.MethodParameter(param_name, type_and_init.type, type_and_init.init, leading_trivia) params.append(param) # init should be used as only the constructor's method parameter, but not again as a field initializer too # (otherwise it would called twice if cloned or cause AST error is just referenced from two separate places) if is_public: field = types.Field(param_name, type_and_init.type, None, types.VISIBILITY.PUBLIC, False, param, param.leading_trivia) fields.append(field) param.field_decl = field self.node_manager.add_node(param, param_start) self.context.pop() if not (self.reader.read_token(",")): break self.reader.expect_token(")") returns = None if not is_constructor: # in case of constructor, "returns" won't be used returns = self.parse_type() if self.reader.read_token( ":" ) else astTypes.VoidType.instance if self.missing_return_type_is_void else None body = None super_call_args = None if declaration_only: self.reader.expect_token(";") else: body = self.expect_block("method body is missing") first_stmt = body.statements[0] if len( body.statements) > 0 else None if isinstance(first_stmt, stats.ExpressionStatement) and isinstance( first_stmt.expression, exprs.UnresolvedCallExpression) and isinstance( first_stmt.expression.func, exprs.Identifier ) and first_stmt.expression.func.text == "super": super_call_args = first_stmt.expression.args body.statements.pop(0) return MethodSignature(params, fields, body, returns, super_call_args)
def parse_source_file(self): imports = [] enums = [] intfs = [] classes = [] funcs = [] while True: leading_trivia = self.reader.read_leading_trivia() if self.reader.get_eof(): break imps = self.parse_import(leading_trivia) if imps != None: for imp in imps: imports.append(imp) continue modifiers = self.reader.read_modifiers(["export", "declare"]) is_exported = "export" in modifiers is_declaration = "declare" in modifiers cls_ = self.parse_class(leading_trivia, is_exported, is_declaration) if cls_ != None: classes.append(cls_) continue enum_obj = self.parse_enum(leading_trivia, is_exported) if enum_obj != None: enums.append(enum_obj) continue intf = self.parse_interface(leading_trivia, is_exported) if intf != None: intfs.append(intf) continue if self.reader.read_token("function"): func_name = self.read_identifier() self.reader.expect_token("(") sig = self.parse_method_signature(False, is_declaration) funcs.append( types.GlobalFunction(func_name, sig.params, sig.body, sig.returns, is_exported, leading_trivia)) continue break self.reader.skip_whitespace() stmts = [] while True: leading_trivia = self.reader.read_leading_trivia() if self.reader.get_eof(): break stmt = self.expect_statement() if stmt == None: continue stmt.leading_trivia = leading_trivia stmts.append(stmt) return types.SourceFile(imports, intfs, classes, enums, funcs, stats.Block(stmts), self.path, self.export_scope)
def parse_interface(self, leading_trivia, is_exported): if not self.reader.read_token("interface"): return None intf_start = self.reader.prev_token_offset intf_name = self.reader.expect_identifier( "expected identifier after 'interface' keyword") self.context.append(f'''I:{intf_name}''') intf_type_args = self.parse_generics_args() base_interfaces = [] if self.reader.read_token("extends"): while True: base_interfaces.append(self.parse_type()) if not (self.reader.read_token(",")): break methods = [] fields = [] self.reader.expect_token("{") while not self.reader.read_token("}"): member_leading_trivia = self.reader.read_leading_trivia() member_start = self.reader.offset member_name = self.parse_identifier_or_string() if self.reader.read_token(":"): self.context.append(f'''F:{member_name}''') field_type = self.parse_type() self.reader.expect_token(";") field = types.Field(member_name, field_type, None, types.VISIBILITY.PUBLIC, False, None, member_leading_trivia) fields.append(field) self.node_manager.add_node(field, member_start) self.context.pop() else: self.context.append(f'''M:{member_name}''') method_type_args = self.parse_generics_args() self.reader.expect_token("(") # method sig = self.parse_method_signature(False, True) method = types.Method(member_name, method_type_args, sig.params, sig.body, types.VISIBILITY.PUBLIC, False, sig.returns, False, member_leading_trivia) methods.append(method) self.node_manager.add_node(method, member_start) self.context.pop() intf = types.Interface(intf_name, intf_type_args, base_interfaces, fields, methods, is_exported, leading_trivia) self.node_manager.add_node(intf, intf_start) self.context.pop() return intf
def visit_variable(self, variable): if variable.mutability == None: variable.mutability = types.MutabilityInfo(True, False, False) return variable
def add_project_file(self, fn, content): file = typeScrPars.TypeScriptParser2.parse_file( content, types.SourcePath(self.project_pkg, re.sub("\\.ts$", "", fn))) self.setup_file(file) self.project_pkg.add_file(file)