import { AstWalker } from "./astWalker" ; import { findLowerBound } from "./misc" ; /**
 * Decompress the source mapping given by solc-bin.js
 */ export namespace SourceMappingDecoder { export type SourceLocation = { start : number ; length : number ; file : number ; jump ? : string ; } ; param { string } value return { Object } export function decode ( value ) { if ( value ) { value = value . split ( ':' ) ; return { start : parseInt ( value [ 0 ] ) , length : parseInt ( value [ 1 ] ) , file : parseInt ( value [ 2 ] ) } ; } } param { String } mapping return { Array } export function decompressAll ( mapping ) { let map = mapping . split ( ';' ) ; let ret = [ ] ; for ( let k in map ) { let compressed = map [ k ] . split ( ':' ) ; let sourceMap = { start : compressed [ 0 ] ? parseInt ( compressed [ 0 ] ) : ret [ ret . length - 1 ] . start , length : compressed [ 1 ] ? parseInt ( compressed [ 1 ] ) : ret [ ret . length - 1 ] . length , file : compressed [ 2 ] ? parseInt ( compressed [ 2 ] ) : ret [ ret . length - 1 ] . file , jump : compressed [ 3 ] ? compressed [ 3 ] : ret [ ret . length - 1 ] . jump } ; ret . push ( sourceMap ) ; } return ret ; } param { String } source return { Arrray } export function getLinebreakPositions ( source ) { let ret = [ ] ; for ( let pos = source . indexOf ( '\n' ) ; pos >= 0 ; pos = source . indexOf ( '\n' , pos + 1 ) ) { ret . push ( pos ) ; } return ret ; } param { Object } sourceLocation param { Array } lineBreakPositions return { Object } export function convertOffsetToLineColumn ( sourceLocation , lineBreakPositions ) { if ( sourceLocation . start >= 0 && sourceLocation . length >= 0 ) { return { start : convertFromCharPosition ( sourceLocation . start , lineBreakPositions ) , end : convertFromCharPosition ( sourceLocation . start + sourceLocation . length , lineBreakPositions ) } ; } else { return { start : null , end : null } ; } } export function convertFromCharPosition ( pos , lineBreakPositions ) { let line = findLowerBound ( pos , lineBreakPositions ) ; if ( lineBreakPositions [ line ] !== pos ) { line = line + 1 ; } let beginColumn = line === 0 ? 0 : ( lineBreakPositions [ line - 1 ] + 1 ) ; let column = pos - beginColumn ; return { line : line , column : column } ; } export function sourceLocationFromAstNode ( astNode ) { if ( astNode . src ) { let split = astNode . src . split ( ':' ) ; return { start : parseInt ( split [ 0 ] ) , length : parseInt ( split [ 1 ] ) , file : parseInt ( split [ 2 ] ) } ; } return null ; } param { String } astNodeType param { String } instIndex param { String } sourceMap param { Object } ast export function findNodeAtInstructionIndex ( astNodeType , instIndex , sourceMap , ast ) { let sourceLocation = atIndex ( instIndex , sourceMap ) ; return findNodeAtSourceLocation ( astNodeType , sourceLocation , ast ) ; } export function findNodeAtSourceLocation ( astNodeType , sourceLocation , ast ) { let astWalker = new AstWalker ( ) ; let callback = { } ; let found = null ; callback [ '*' ] = function ( node ) { let nodeLocation = sourceLocationFromAstNode ( node ) ; if ( ! nodeLocation ) { return true ; } if ( nodeLocation . start <= sourceLocation . start && nodeLocation . start + nodeLocation . length >= sourceLocation . start + sourceLocation . length ) { if ( astNodeType === node . name ) { found = node ; return false ; } else { return true ; } } else { return false ; } } ; astWalker . walk ( ast . AST , callback ) ; return found ; } param { String } astNodeType param { Int } position return { Object } export function nodesAtPosition ( astNodeType , position , ast ) { let astWalker = new AstWalker ( ) ; let callback = { } ; let found = [ ] ; callback [ '*' ] = function ( node ) { let nodeLocation = sourceLocationFromAstNode ( node ) ; if ( ! nodeLocation ) { return ; } if ( nodeLocation . start <= position && nodeLocation . start + nodeLocation . length >= position ) { if ( ! astNodeType || astNodeType === node . name ) { found . push ( node ) ; if ( astNodeType ) { return false ; } } return true ; } else { return false ; } } ; astWalker . walk ( ast . AST , callback ) ; return found ; } param { Integer } index param { String } mapping return { Object } export function atIndex ( index , mapping ) { let ret = { } ; let map = mapping . split ( ';' ) ; if ( index >= map . length ) { index = map . length - 1 ; } for ( let k = index ; k >= 0 ; k -- ) { let current = map [ k ] ; if ( ! current . length ) { continue ; } current = current . split ( ':' ) ; if ( ret . start === undefined && current [ 0 ] && current [ 0 ] !== '-1' && current [ 0 ] . length ) { ret . start = parseInt ( current [ 0 ] ) ; } if ( ret . length === undefined && current [ 1 ] && current [ 1 ] !== '-1' && current [ 1 ] . length ) { ret . length = parseInt ( current [ 1 ] ) ; } if ( ret . file === undefined && current [ 2 ] && current [ 2 ] !== '-1' && current [ 2 ] . length ) { ret . file = parseInt ( current [ 2 ] ) ; } if ( ret . jump === undefined && current [ 3 ] && current [ 3 ] . length ) { ret . jump = current [ 3 ] ; } if ( ret . start !== undefined && ret . length !== undefined && ret . file !== undefined && ret . jump !== undefined ) { break ; } } return ret ; } export function toIndex ( sourceLocation , mapping ) { let map = mapping . split ( ';' ) ; let index = null ; let decompressedCurrent = { } ; for ( let k = 0 ; k < map . length ; k ++ ) { let current = map [ k ] ; if ( ! current . length ) { continue ; } current = current . split ( ':' ) ; if ( decompressedCurrent . start === undefined && current [ 0 ] && current [ 0 ] !== '-1' && current [ 0 ] . length ) { let start = parseInt ( current [ 0 ] ) ; if ( start === sourceLocation . start ) { decompressedCurrent . start = start ; } } if ( decompressedCurrent . length === undefined && current [ 1 ] && current [ 1 ] !== '-1' && current [ 1 ] . length ) { let length = parseInt ( current [ 1 ] ) ; if ( length === sourceLocation . length ) { decompressedCurrent . length = length ; } } if ( decompressedCurrent . jump === undefined && current [ 3 ] && current [ 3 ] . length ) { let jump = current [ 3 ] ; if ( jump === sourceLocation . jump ) { decompressedCurrent . jump = jump ; } } if ( decompressedCurrent . start !== undefined && decompressedCurrent . length !== undefined && ( sourceLocation . jump === undefined || decompressedCurrent . jump !== undefined ) ) { index = k ; break ; } } return index ; } }