| // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| library sourcemap.js_tracer; |
| |
| import 'package:compiler/src/io/source_information.dart'; |
| import 'package:compiler/src/io/position_information.dart'; |
| import 'package:compiler/src/js/js.dart' as js; |
| import 'sourcemap_helper.dart'; |
| import 'trace_graph.dart'; |
| |
| /// Create a [TraceGraph] for [info] registering usage in [coverage]. |
| TraceGraph createTraceGraph(SourceMapInfo info, Coverage coverage) { |
| TraceGraph graph = new TraceGraph(); |
| TraceListener listener = new StepTraceListener(graph); |
| CodePositionMap codePositions = |
| new CodePositionCoverage(info.jsCodePositions, coverage); |
| JavaScriptTracer tracer = new JavaScriptTracer( |
| codePositions, [new CoverageListener(coverage), listener]); |
| info.node.accept(tracer); |
| return graph; |
| } |
| |
| class StepTraceListener extends TraceListener |
| with NodeToSourceInformationMixin { |
| Map<js.Node, TraceStep> steppableMap = <js.Node, TraceStep>{}; |
| final TraceGraph graph; |
| |
| StepTraceListener(this.graph); |
| |
| @override |
| void onStep(js.Node node, Offset offset, StepKind kind) { |
| SourceInformation sourceInformation = computeSourceInformation(node); |
| SourcePositionKind sourcePositionKind = SourcePositionKind.START; |
| List text = [node]; |
| switch (kind) { |
| case StepKind.FUN: |
| sourcePositionKind = SourcePositionKind.INNER; |
| text = ['<exit>']; |
| break; |
| case StepKind.CALL: |
| CallPosition callPosition = |
| CallPosition.getSemanticPositionForCall(node); |
| sourcePositionKind = callPosition.sourcePositionKind; |
| break; |
| case StepKind.NEW: |
| case StepKind.RETURN: |
| case StepKind.BREAK: |
| case StepKind.CONTINUE: |
| case StepKind.THROW: |
| case StepKind.EXPRESSION_STATEMENT: |
| break; |
| case StepKind.IF_CONDITION: |
| js.If ifNode = node; |
| text = ['if(', ifNode.condition, ') ...']; |
| break; |
| case StepKind.FOR_INITIALIZER: |
| js.For forNode = node; |
| text = ['for(', forNode.init, '; ...) ...']; |
| break; |
| case StepKind.FOR_CONDITION: |
| js.For forNode = node; |
| text = ['for(...;', forNode.condition, '; ...) ...']; |
| break; |
| case StepKind.FOR_UPDATE: |
| js.For forNode = node; |
| text = ['for(...; ...', forNode.update, ') ...']; |
| break; |
| case StepKind.WHILE_CONDITION: |
| js.While whileNode = node; |
| text = ['while(', whileNode.condition, ') ...']; |
| break; |
| case StepKind.DO_CONDITION: |
| js.Do doNode = node; |
| text = ['do {... } (', doNode.condition, ')']; |
| break; |
| case StepKind.SWITCH_EXPRESSION: |
| js.Switch switchNode = node; |
| text = ['switch(', switchNode.key, ') ...']; |
| break; |
| |
| } |
| createTraceStep( |
| kind, |
| node, |
| offset: offset, |
| sourceLocation: getSourceLocation( |
| sourceInformation, sourcePositionKind), |
| text: text); |
| } |
| |
| void createTraceStep( |
| StepKind kind, |
| js.Node node, |
| {Offset offset, |
| List text, |
| String note, |
| SourceLocation sourceLocation}) { |
| int id = steppableMap.length; |
| |
| if (text == null) { |
| text = [node]; |
| } |
| |
| TraceStep step = new TraceStep( |
| kind, |
| id, |
| node, |
| offset, |
| text, |
| sourceLocation); |
| graph.addStep(step); |
| |
| steppableMap[node] = step; |
| } |
| |
| |
| void pushBranch(BranchKind kind, [value]) { |
| var branch; |
| switch (kind) { |
| case BranchKind.CONDITION: |
| branch = value ? 't' : 'f'; |
| break; |
| case BranchKind.LOOP: |
| branch = 'l'; |
| break; |
| case BranchKind.CATCH: |
| branch = 'c'; |
| break; |
| case BranchKind.FINALLY: |
| branch = 'F'; |
| break; |
| case BranchKind.CASE: |
| branch = '$value'; |
| break; |
| } |
| graph.pushBranch(branch); |
| } |
| |
| void popBranch() { |
| graph.popBranch(); |
| } |
| } |