Index: pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart |
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart |
index 77806c00c334282149e35f446964ba6b83a99a65..d1461fc838d07c113de8da951b130f782369820d 100644 |
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart |
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart |
@@ -20,7 +20,7 @@ import 'cps_ir_builder_task.dart' show DartCapturedVariables, |
GlobalProgramInformation; |
import '../common.dart' as types show TypeMask; |
-import '../js/js.dart' as js show Template; |
+import '../js/js.dart' as js show Template, js, LiteralStatement; |
import '../native/native.dart' show NativeBehavior; |
/// A mapping from variable elements to their compile-time values. |
@@ -2025,6 +2025,88 @@ class IrBuilder { |
} |
} |
+ /// Build a call to the closure conversion helper for the [Function] typed |
+ /// value in [value]. |
+ ir.Primitive _convertDartClosure(ir.Primitive value, FunctionType type) { |
+ ir.Constant arity = buildIntegerConstant(type.computeArity()); |
+ return buildStaticFunctionInvocation( |
+ program.closureConverter, |
+ CallStructure.TWO_ARGS, |
+ <ir.Primitive>[value, arity]); |
+ } |
+ |
+ final RegExp nativeRedirectionRegExp = |
+ new RegExp(r'^[a-zA-Z][a-zA-Z_$0-9]*$'); |
asgerf
2015/08/12 13:15:02
Make this static?
|
+ |
+ /// Generate the body for a native function. |
+ /// |
+ /// If [nativeBody] is non-null, generate a [ForeignCode] statement for the |
+ /// body defined in JavaScript. Otherwise, generate a call to the real |
+ /// target, which is given by the [FunctionElement]'s `fixedBackendName`. |
+ /// The target can be a function, getter, or setter. |
+ void buildNativeFunctionBody(ast.Node nativeBody, |
+ SourceInformation source) { |
+ FunctionElement function = state.currentElement; |
+ assert(function.isNative); |
+ String name = function.fixedBackendName; |
+ List<ir.Primitive> arguments = <ir.Primitive>[]; |
+ NativeBehavior behavior = new NativeBehavior(); |
+ behavior.sideEffects.setAllSideEffects(); |
+ |
+ if (nativeBody != null) { |
asgerf
2015/08/12 13:15:02
I think it would make more sense to have this spli
|
+ ast.LiteralString jsCode = nativeBody.asLiteralString(); |
+ String code = jsCode.dartString.slowToString(); |
+ assert(invariant(nativeBody, !nativeRedirectionRegExp.hasMatch(code), |
+ message: "Deprecated syntax, use @JSName('name') instead.")); |
+ assert(invariant(nativeBody, |
+ function.functionSignature.parameterCount == 0, |
+ message: 'native "..." syntax is restricted to ' |
+ 'functions with zero parameters.')); |
+ // Generate a [ForeignCode] statement from the given native code. |
+ buildForeignCode( |
+ js.js.statementTemplateYielding(new js.LiteralStatement(code)), |
+ <ir.Primitive>[], |
+ behavior); |
+ } else { |
+ program.addNativeMethod(function); |
+ // Construct the access of the target element. |
+ String code = function.isInstanceMember ? '#.$name' : name; |
+ if (function.isInstanceMember) { |
+ arguments.add(state.thisParameter); |
+ } |
+ // Collect all parameters of the function and templates for them to be |
+ // inserted into the JavaScript code. |
+ List<String> argumentTemplates = <String>[]; |
+ function.functionSignature.forEachParameter((ParameterElement parameter) { |
+ ir.Primitive input = environment.lookup(parameter); |
+ DartType type = program.unaliasType(parameter.type); |
+ if (type is FunctionType) { |
+ // The parameter type is a function type either directly or through |
+ // typedef(s). |
+ input = _convertDartClosure(input, type); |
+ } |
+ arguments.add(input); |
+ argumentTemplates.add('#'); |
+ }); |
+ // Construct the application of parameters for functions and setters. |
+ if (function.kind == ElementKind.FUNCTION) { |
+ code = "$code(${argumentTemplates.join(', ')})"; |
+ } else if (function.kind == ElementKind.SETTER) { |
+ code = "$code = ${argumentTemplates.single}"; |
+ } else { |
+ assert(argumentTemplates.isEmpty); |
+ assert(function.kind == ElementKind.GETTER); |
+ } |
+ // Generate the [ForeignCode] expression and a return statement to return |
+ // its value. |
+ ir.Primitive value = buildForeignCode( |
+ js.js.uncachedExpressionTemplate(code), |
+ arguments, |
+ behavior); |
+ buildReturn(value: value, sourceInformation: source); |
+ } |
+ } |
+ |
/// Create a blocks of [statements] by applying [build] to all reachable |
/// statements. The first statement is assumed to be reachable. |
// TODO(johnniwinther): Type [statements] as `Iterable` when `NodeList` uses |
@@ -2599,6 +2681,7 @@ class IrBuilder { |
List<ir.Primitive> arguments, |
NativeBehavior behavior, |
{Element dependency}) { |
+ assert(behavior != null); |
types.TypeMask type = program.getTypeMaskForForeign(behavior); |
ir.Primitive result = _continueWithExpression((k) => new ir.ForeignCode( |
codeTemplate, |
@@ -2608,7 +2691,7 @@ class IrBuilder { |
k, |
dependency: dependency)); |
if (!codeTemplate.isExpression) { |
- // Close the term if this is a "throw" expression. |
+ // Close the term if this is a "throw" expression or native body. |
add(new ir.Unreachable()); |
_current = null; |
} |