Skip to content

Commit

Permalink
Add more structure to C directives
Browse files Browse the repository at this point in the history
  • Loading branch information
SebastienTainon committed May 22, 2024
1 parent 0b64a3e commit c7dbeed
Show file tree
Hide file tree
Showing 23 changed files with 119 additions and 162 deletions.
4 changes: 2 additions & 2 deletions backend/directives.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ g.numberExpr = g.number.map(function (match) {
return ['number', parseFloat(match)];
});
g.identExpr = g.ident.map(function (match) {
return match;
return ['ident', match];
});
g.parensExpr = PR.seq(g.lparen, () => g.expr, g.rparen).map(function (match) {
return match[1];
Expand All @@ -39,7 +39,7 @@ g.subscriptExpr = PR.seq(() => g.expr1, g.lbrack, () => g.expr, g.rbrack).map(fu
g.expr1 = PR.alt(g.numberExpr, g.identExpr, g.parensExpr, g.subscriptExpr);

g.listExpr = PR.seq(g.lbrack, PR.repeatSeparated(() => g.expr, g.coma, {min: 0}).optional(), g.rbrack).map(function (match) {
return match[1] || [];
return ['list', match[1] || []];
});
g.derefExpr = PR.seq(g.star, () => g.expr).map(function (match) {
return ['deref', match[1]];
Expand Down
2 changes: 2 additions & 0 deletions frontend/stepper/analysis/analysis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export interface AnalysisVariable extends DebugProtocol.Variable {
loaded?: boolean,
collapsed?: boolean,
withCurlyBraces?: boolean,
unixVariable?: {type: any, ref: any},
}

// Codecast format for visual display
Expand Down Expand Up @@ -58,6 +59,7 @@ export interface CodecastAnalysisVariable {
alreadyVisited?: boolean,
collapsed?: boolean,
withCurlyBraces?: boolean,
unixVariable?: {type: any, ref: any},
}

export interface AnalysisConversionOptions {
Expand Down
3 changes: 2 additions & 1 deletion frontend/stepper/analysis/directives/array1d.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {SvgPan} from '../../views/SvgPan';
import {DirectiveFrame} from '../../views/DirectiveFrame';
import {StepperControls} from "../../index";
import {CodecastAnalysisVariable} from "../analysis";
import {LayoutDirectiveContext} from '../../../task/layout/LayoutDirective';

const TEXT_LINE_HEIGHT = 18;
const TEXT_BASELINE = 5; // from bottom
Expand Down Expand Up @@ -130,7 +131,7 @@ function Cursor({view, cursor}) {
interface Array1DProps {
controls: StepperControls,
directive: any,
context: any,
context: LayoutDirectiveContext,
scale: any,
onChange: Function
}
Expand Down
3 changes: 2 additions & 1 deletion frontend/stepper/analysis/directives/array2d.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {SvgPan} from '../../views/SvgPan';
import {DirectiveFrame} from "../../views/DirectiveFrame";
import {StepperControls} from "../../index";
import {CodecastAnalysisVariable} from "../analysis";
import {LayoutDirectiveContext} from '../../../task/layout/LayoutDirective';

const TEXT_LINE_HEIGHT = 18;
const TEXT_BASELINE = 5; // from bottom
Expand Down Expand Up @@ -198,7 +199,7 @@ function drawColCursors(colCount, rowCount, infoMap) {
interface Array2DProps {
scale: any,
directive: any,
context: any,
context: LayoutDirectiveContext,
controls: StepperControls,
onChange: Function
}
Expand Down
13 changes: 6 additions & 7 deletions frontend/stepper/analysis/directives/array2d_model.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import {getVariable} from './utils';
import {DirectiveVariableName, getVariable} from './utils';
import {getCursorMap} from './array_utils';
import {getMessage} from "../../../lang";
import {LayoutDirectiveContext} from '../../../task/layout/LayoutDirective';

export const extractView = function(context, name: string, options) {
const {analysis} = context;

const ref = getVariable(analysis, name);
export const extractView = function (context: LayoutDirectiveContext, name: DirectiveVariableName, options) {
const ref = getVariable(context, name);
if (!ref) {
return {error: getMessage('ARRAY2D_REF_UNDEFINED').format({name})};
}
Expand All @@ -18,11 +17,11 @@ export const extractView = function(context, name: string, options) {
const colCount = (options.colCount) ? options.colCount : ref.variables[0].variables.length;

// Inspect cursors.
const rowInfoMap = getCursorMap(analysis, options.rowCursors, {
const rowInfoMap = getCursorMap(context, options.rowCursors, {
minIndex: 0,
maxIndex: rowCount + 1
});
const colInfoMap = getCursorMap(analysis, options.colCursors, {
const colInfoMap = getCursorMap(context, options.colCursors, {
minIndex: 0,
maxIndex: colCount + 1
});
Expand Down
19 changes: 9 additions & 10 deletions frontend/stepper/analysis/directives/array_utils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import range from 'node-range';

import {getVariable} from './utils';
import {DirectiveVariableName, getVariable} from './utils';
import {getMessage} from "../../../lang";
import {LayoutDirectiveContext} from '../../../task/layout/LayoutDirective';

/**
extractView(context, name, options) looks up `name` in `stackFrame` and
Expand Down Expand Up @@ -57,9 +58,7 @@ import {getMessage} from "../../../lang";
(up to `options.cursorRows` rows are used)
*/
export const extractView = function(context, name, options) {
const {analysis} = context;

export const extractView = function (context: LayoutDirectiveContext, name, options) {
// Normalize options.
const {dim} = options;
let {cursors, cursorRows, maxVisibleCells, pointsByKind} = options;
Expand Down Expand Up @@ -88,14 +87,14 @@ export const extractView = function(context, name, options) {
if (/^\d/.test(dim)) {
elemCount = dim;
} else {
const dimVariable = getVariable(analysis, dim);
const dimVariable = getVariable(context, dim);
if (dimVariable && dimVariable.value) {
elemCount = dimVariable.value;
elemCount = Number(dimVariable.value);
}
}
}

const ref = getVariable(analysis, name);
const ref = getVariable(context, name, elemCount);
if (!ref) {
return {error: getMessage('ARRAY1D_REF_UNDEFINED').format({name})};
}
Expand All @@ -108,7 +107,7 @@ export const extractView = function(context, name, options) {
elemCount = ref.variables.length;
}

const cursorMap = getCursorMap(analysis, cursors, {
const cursorMap = getCursorMap(context, cursors, {
minIndex: 0,
maxIndex: elemCount
});
Expand All @@ -129,12 +128,12 @@ export const extractView = function(context, name, options) {
// minIndex, maxIndex
// Only cursors whose value is in the range [minIndex, maxIndex] are considered.
// The calculated value is then subject to the minIndex/maxIndex constraint.
export const getCursorMap = function(analysis, cursorNames, options) {
export const getCursorMap = function (context: LayoutDirectiveContext, cursorNames: DirectiveVariableName[], options) {
const {minIndex, maxIndex} = options;
const cursorMap = []; // spare array

cursorNames.forEach(function(name) {
const cursorVariable = getVariable(analysis, name);
const cursorVariable = getVariable(context, name);
if (!cursorVariable) {
return;
}
Expand Down
5 changes: 3 additions & 2 deletions frontend/stepper/analysis/directives/sort.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {SvgPan} from '../../views/SvgPan';
import {DirectiveFrame} from "../../views/DirectiveFrame";
import {StepperControls} from "../../index";
import {CodecastAnalysisVariable} from "../analysis";
import {LayoutDirectiveContext} from '../../../task/layout/LayoutDirective';

const DEFAULT_MAX_VISIBLE_CELLS = 40;
const MARGIN_LEFT = 100;
Expand Down Expand Up @@ -145,7 +146,7 @@ function Threshold({view, threshold}: ThresholdProps) {
interface SortViewProps {
controls: StepperControls,
directive: any,
context: any,
context: LayoutDirectiveContext,
scale: any,
onChange: Function
}
Expand Down Expand Up @@ -200,7 +201,7 @@ export class SortView extends React.PureComponent<SortViewProps> {
return <DirectiveFrame {...this.props}>{view.error}</DirectiveFrame>;
}

view.thresholds = getVariables(context.analysis, thresholds);
view.thresholds = getVariables(context, thresholds);

const list = view.ref.variables;
view.nbCells = list.length;
Expand Down
81 changes: 57 additions & 24 deletions frontend/stepper/analysis/directives/utils.tsx
Original file line number Diff line number Diff line change
@@ -1,46 +1,79 @@
import React from 'react';
import {
CodecastAnalysisSnapshot,
CodecastAnalysisStackFrame,
CodecastAnalysisVariable
CodecastAnalysisVariable, convertVariableDAPToCodecastFormat
} from "../analysis";
import {LayoutDirectiveContext} from '../../../task/layout/LayoutDirective';
import {evalExpr, readValue, stringifyExpr} from '../../views/c/utils';
import {convertUnixValueToDAPVariable} from '../../c/analysis';
import * as C from '@france-ioi/persistent-c';
import {getMessage} from '../../../lang';
import {getOpsArray1D} from '../../views/c/array_utils';

/**
* Gets a variable by name in analysis.
*
* @param {object} analysis The analysis.
* @param {string} name The name.
*
* @return {object|null}
*/
export const getVariable = function(analysis: CodecastAnalysisSnapshot, name: string): CodecastAnalysisVariable {
export type DirectiveVariableName = string|[string, string];

export const getVariable = function (context: LayoutDirectiveContext, name: DirectiveVariableName, elemCount?: number): CodecastAnalysisVariable {
// Check in the last (the current) and the first (which is the global) scopes.

const variableName = Array.isArray(name) ? name[1] : name;
const analysis = context.analysis;
const nbScopes = analysis.stackFrames.length;
let variable = null;
let variable: CodecastAnalysisVariable = null;
if (nbScopes) {
variable = getVariableInScope(analysis.stackFrames[nbScopes - 1], name);
variable = getVariableInScope(analysis.stackFrames[nbScopes - 1], variableName);
}
if (!variable && nbScopes > 1) {
variable = getVariableInScope(analysis.stackFrames[0], name);
variable = getVariableInScope(analysis.stackFrames[0], variableName);
}

if (variable && undefined !== elemCount) {
const programState = context.programState;
const unixVariable = variable.unixVariable;
const localMap = new Map([[variableName, unixVariable]]);
const refExpr = name;
const cursorValue = evalExpr(programState, localMap, refExpr, false);
console.log('get var', {name, variable, unixVariable, analysis: analysis.stackFrames, nbScopes, elemCount, cursorValue})

const {type, ref} = unixVariable;
// const limits = {scalars: 0, maxScalars: 15};
// const value = readValue(context, C.pointerType(type), ref.address, limits);

if (ref.type.kind !== 'pointer') {
throw getMessage('ARRAY1D_EXPR_NOPTR').format({expr: stringifyExpr(refExpr)});
}
if (elemCount === undefined) {
if ('orig' in ref.type) {
// The array size can be obtained from the original type.
elemCount = ref.type.orig.count.toInteger();
} else {
throw getMessage('ARRAY1D_DIM_UNK').format({expr: stringifyExpr(refExpr)});
}
}
const address = ref.address;
const elemType = ref.type.pointee;
if (!/^(builtin|pointer|array)$/.test(elemType.kind)) {
throw getMessage('ARRAY1D_ELT_UNSUP').format({expr: stringifyExpr(refExpr)});
}
const cellOpsMap = getOpsArray1D(programState, address, elemCount, elemType.size);

const typeDecl = '';
// const typeDecl = renderDeclType(type, '', 0);

// const convertedVariable = convertUnixValueToDAPVariable(variableName, typeDecl, value, ref.address, {});
console.log('converted variable', cellOpsMap);

// return convertedVariable;

}

return variable;
};

/**
* Gets variables by name in analysis.
*
* @param {object} analysis The analysis.
* @param {Array} names The names.
*
* @return {object|null}
*/
export const getVariables = function(analysis: CodecastAnalysisSnapshot, names: string[]): {name: string, value: CodecastAnalysisVariable}[] {
export const getVariables = function (context: LayoutDirectiveContext, names: DirectiveVariableName[]): {name: DirectiveVariableName, value: CodecastAnalysisVariable}[] {
return names.map((name) => {
return {
name,
value: getVariable(analysis, name)
value: getVariable(context, name)
}
});
};
Expand Down
50 changes: 2 additions & 48 deletions frontend/stepper/c/analysis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,12 @@ A `Stored Value` can have one of these shapes:
*/

import {StepperDirectives} from "../index";
import {AnalysisScope, AnalysisSnapshot, AnalysisStackFrame, AnalysisVariable} from '../analysis/analysis';
import {readValue} from '../views/c/utils';
import * as C from '@france-ioi/persistent-c';

export interface AnalysisC {
functionCallStack: any,
callReturn?: {
func: any,
args: any,
result: any
}
functionCallStack: StackFrameUnixAnalysis[],
}

export interface StackFrameUnixAnalysis {
Expand All @@ -36,13 +30,6 @@ export interface StackFrameUnixAnalysis {
export const analyseState = function(programState): AnalysisC {
const functionCallStack = analyseScope(programState.scope);
const result: AnalysisC = {functionCallStack};
if (programState.direction === 'out') {
result.callReturn = {
func: programState.control.values[0],
args: programState.control.values.slice(1),
result: programState.result
};
}

return Object.freeze(result);
};
Expand Down Expand Up @@ -100,42 +87,8 @@ const analyseScope = function(scope): StackFrameUnixAnalysis[] {
return functionCallStack;
};

export const collectDirectives = function(functionCallStack, focusDepth): StepperDirectives {
const ordered = [];
const functionCallStackMap = {};
// StackFrames are collected in reverse order, so that the directive's render
// function should use functionCallStack[key][0] to access the innermost stackFrame.
for (let depth = functionCallStack.size - 1 - focusDepth; depth >= 0; depth -= 1) {
const stackFrame = functionCallStack.get(depth);
const directives = stackFrame.get('directives');
directives.forEach(function(directive) {
const {key} = directive;
if (key in functionCallStackMap) {
functionCallStackMap[key].push(stackFrame);
} else {
ordered.push(directive);
functionCallStackMap[key] = [stackFrame];
}
})
}

return Object.freeze({
ordered,
functionCallStackMap,
functionCallStack: null
});
};

export function convertUnixStateToAnalysisSnapshot(programState: any, lastProgramState: any): AnalysisSnapshot {
const functionCallStack = analyseScope(programState.scope);
const result: AnalysisC = {functionCallStack};
if (programState.direction === 'out') {
result.callReturn = {
func: programState.control.values[0],
args: programState.control.values.slice(1),
result: programState.result
};
}

/* Hide function calls that have no position in user code. */
const filteredFunctionCallStack = functionCallStack.filter(function(stackFrame) {
Expand All @@ -158,6 +111,7 @@ function convertUnixStackFrameToAnalysisStackFrame(unixStackFrame: StackFrameUni
const typeDecl = renderDeclType(type, '', 0);

const variable = convertUnixValueToDAPVariable(variableName, typeDecl, value, ref.address, {});
variable.unixVariable = unixStackFrame.localMap[variableName];
variables.push(variable);
}

Expand Down
Loading

0 comments on commit c7dbeed

Please sign in to comment.