import * as C from '@france-ioi/persistent-c' ; import { evalExpr , readScalarBasic , stringifyExpr } from './utils' ; import { getCursorMap } from './array_utils' ; import { getMessage } from "../../../lang" ; export const extractView = function ( context , stackFrame , refExpr , options ) { const { programState } = context ; const localMap = stackFrame . get ( 'localMap' ) ; let ref ; try { ref = evalExpr ( programState , localMap , refExpr , false ) ; } catch ( ex ) { return { error : getMessage ( 'ARRAY2D_EXPR_NOVAL' ) . format ( { expr : stringifyExpr ( refExpr ) , ex : getMessage . format ( ex ) } ) } ; } if ( ref . type . kind !== 'pointer' ) { return { error : getMessage ( 'ARRAY2D_EXPR_NOPTR' ) . format ( { expr : stringifyExpr ( refExpr ) } ) } ; } const arrayType = ref . type . orig ; if ( arrayType === undefined || arrayType . kind !== 'array' ) { return { error : getMessage ( 'ARRAY2D_EXPR_NOARR' ) . format ( { expr : stringifyExpr ( refExpr ) } ) } ; } const rowCount = arrayType . count . toInteger ( ) ; const rowType = arrayType . elem ; if ( rowType . kind !== 'array' ) { return { error : getMessage ( 'ARRAY2D_EXPR_NOT2D' ) . format ( { expr : stringifyExpr ( refExpr ) } ) } ; } const colCount = rowType . count . toInteger ( ) ; const cellType = rowType . elem ; if ( cellType . kind !== 'builtin' ) { return { error : getMessage ( 'ARRAY2D_ELT_UNSUP' ) . format ( { expr : stringifyExpr ( refExpr ) } ) } ; } const rows = readArray2D ( context , arrayType , ref . address , rowCount , colCount , cellType ) ; const rowInfoMap = getCursorMap ( programState , localMap , options . rowCursors , { minIndex : 0 , maxIndex : rowCount + 1 , address : ref . address , cellSize : rowType . size } ) ; const colInfoMap = getCursorMap ( programState , localMap , options . colCursors , { minIndex : 0 , maxIndex : colCount + 1 , address : ref . address , cellSize : cellType . size , cellSizeMod : rowType . size } ) ; let nextStaggerPos = - 1 , cursorRow = 0 ; const colCursorRows = 2 ; for ( let index in colInfoMap ) { const cursor = colInfoMap [ index ] ; if ( nextStaggerPos === cursor . index ) { cursorRow = ( cursorRow + 1 ) % colCursorRows ; } else { cursorRow = 0 ; } nextStaggerPos = cursor . index + 1 ; cursor . row = cursorRow ; } return { rows , rowCount , colCount , rowInfoMap , colInfoMap } ; } ; const mapArray2D = function ( arrayBase , nRows , nCols , cellSize ) { const rowSize = nCols * cellSize ; const arrayLimit = arrayBase + ( nRows * rowSize ) - 1 ; return function ( ref , callback ) { const { address , type } = ref ; if ( arrayLimit < address ) return ; const refLimit = address + type . pointee . size - 1 ; if ( refLimit < arrayBase ) return ; const startAddress = Math . max ( arrayBase , address ) ; const endAddress = Math . min ( arrayLimit , refLimit ) ; let row = Math . floor ( ( startAddress - arrayBase ) / rowSize ) ; let col = Math . floor ( ( startAddress - row * rowSize ) / cellSize ) % nCols ; let cellLimit = arrayBase + row * rowSize + col * cellSize + cellSize - 1 ; while ( cellLimit <= endAddress ) { callback ( row , col ) ; col += 1 ; if ( col === nCols ) { col = 0 ; row += 1 ; } cellLimit += cellSize ; } } ; } ; const getOpsArray2D = function ( programState , address , nRows , nCols , cellSize ) { const cellOpsMap = [ ] ; const forEachCell = mapArray2D ( address , nRows , nCols , cellSize ) ; programState . memoryLog . forEach ( function ( entry , i ) { const op = entry [ 0 ] ; forEachCell ( entry [ 1 ] , function ( row , col ) { const key = `${ row },${ col }` ; let cellOps ; if ( key in cellOpsMap ) { cellOps = cellOpsMap [ key ] ; } else { cellOps = cellOpsMap [ key ] = { key } ; } cellOps [ op ] = i ; } ) ; } ) ; return cellOpsMap ; } ; const readArray2D = function ( context , arrayType , address , rowCount , colCount , cellType ) { const { programState , lastProgramState } = context ; const cellSize = cellType . size ; const mops = getOpsArray2D ( programState , address , rowCount , colCount , cellSize ) ; const rowSize = colCount * cellSize ; const cellRefType = C . pointerType ( cellType ) ; const rows = [ ] ; for ( let rowIndex = 0 ; rowIndex < rowCount ; rowIndex += 1 ) { const row = [ ] ; const rowAddress = address + rowIndex * rowSize ; for ( let colIndex = 0 ; colIndex < colCount ; colIndex += 1 ) { const cellAddress = rowAddress + colIndex * cellSize ; const content = readScalarBasic ( programState , cellRefType , cellAddress ) ; const key = `${ rowIndex },${ colIndex }` ; if ( key in mops ) { const mop = mops [ key ] ; if ( 'load' in mop ) { content . load = mop . load ; } if ( 'store' in mop ) { content . store = mop . store ; content . previous = C . readValue ( lastProgramState , content . ref ) ; } } row . push ( { index : colIndex , address : cellAddress , key , content } ) ; } rows . push ( { index : rowIndex , address : rowAddress , content : row } ) ; } return rows ; } ;