@@ -29,9 +29,10 @@ import {
2929 SET_LEX_ADDR_FX ,
3030 SET_PAIR_HEAD_FX ,
3131 SET_PAIR_TAIL_FX ,
32+ SET_PARAM_FX ,
3233} from "./constants" ;
3334import { f64 , global , i32 , i64 , local , mut , wasm } from "./wasm-util/builder" ;
34- import { WasmCall , WasmInstruction } from "./wasm-util/types" ;
35+ import { WasmCall , WasmInstruction , WasmRaw } from "./wasm-util/types" ;
3536
3637const builtInFunctions : {
3738 name : string ;
@@ -102,8 +103,11 @@ type Binding = { name: string; tag: "local" | "nonlocal" };
102103
103104// all expressions compile to a call to a function like makeX, get/setLexAddress, arithOp, etc.
104105// so expressions return WasmCalls. (every expression results in i32 i64)
106+ // WasmRaw is for function calls
105107export class BuilderGenerator
106- implements StmtNS . Visitor < WasmInstruction > , ExprNS . Visitor < WasmCall >
108+ implements
109+ StmtNS . Visitor < WasmInstruction > ,
110+ ExprNS . Visitor < WasmCall | WasmRaw >
107111{
108112 private strings : [ string , number ] [ ] = [ ] ;
109113 private heapPointer = 0 ;
@@ -256,9 +260,12 @@ export class BuilderGenerator
256260 . func ( "$main" )
257261 . results ( ...( undroppedInstr ? [ i32 , i64 ] : [ ] ) )
258262 . body (
259- wasm
260- . call ( ALLOC_ENV_FX )
261- . args ( i32 . const ( globalEnvLength ) , i32 . const ( 0 ) ) ,
263+ global . set (
264+ CURR_ENV ,
265+ wasm
266+ . call ( ALLOC_ENV_FX )
267+ . args ( i32 . const ( globalEnvLength ) , i32 . const ( 0 ) , i32 . const ( 0 ) )
268+ ) ,
262269
263270 ...builtInFuncsDeclarations ,
264271
@@ -408,42 +415,35 @@ export class BuilderGenerator
408415 ) ;
409416 }
410417
411- visitCallExpr ( expr : ExprNS . Call ) : WasmCall {
418+ visitCallExpr ( expr : ExprNS . Call ) : WasmRaw {
412419 const callee = this . visit ( expr . callee ) ;
420+ const args = expr . args . map ( ( arg ) => this . visit ( arg ) ) ;
413421
414- // because we're not actually passing in arguments to apply, the lex addresses from the args
415- // are not accurate.
416- // they assume that we're not yet in the new function call's environment, because that's how it is
417- // from the compiler's perspective.
418- // but here, we're already in the new environment because PRE_APPLY was called. so we have to
419- // increment the depth from each GET_LEX_ADDRESS call from each arg by 1.
420- const args : WasmCall [ ] = expr . args
421- . map ( ( arg ) => this . visit ( arg ) )
422- . map ( ( arg ) => ( {
423- ...arg ,
424- ...( arg . function === GET_LEX_ADDR_FX . name && {
425- arguments : arg . arguments . map ( ( a , i ) => ( {
426- ...a ,
427-
428- // first argument is depth
429- ...( i === 0 &&
430- a . op === "i32.const" && { value : a . value + BigInt ( 1 ) } ) ,
431- } ) ) ,
432- } ) ,
433- } ) ) ;
434-
435- return wasm . call ( APPLY_FX_NAME ) . args (
436- global . get ( CURR_ENV ) ,
437- wasm . call ( PRE_APPLY_FX ) . args ( callee , i32 . const ( args . length ) ) ,
438-
439- // these are not arguments, but they don't produce values, so it's ok to insert them here
440- // this is to maintain the return type of WasmCall
441- // this is equivalent to setting lex addresses after calling PRE_APPLY, but before APPLY
442-
443- ...[ ...Array ( args . length ) . keys ( ) ] . map ( ( i ) =>
444- wasm . call ( SET_LEX_ADDR_FX ) . args ( i32 . const ( 0 ) , i32 . const ( i ) , args [ i ] )
445- )
446- ) ;
422+ // PRE_APPLY returns (1, 2) callee tag and value, (3) pointer to new environment
423+ // APPLY expects (1) pointer to return environment, (2, 3) callee tag and value
424+
425+ // we call PRE_APPLY first, which verifies the callee is a closure and arity matches
426+ // AND creates a new environment for the function call, but does not set CURR_ENV yet
427+ // this is so that we can set the arguments in the new environment first
428+
429+ // this means we can't use SET_LEX_ADDR_FX because it uses CURR_ENV internally
430+ // so we manually set the arguments in the new environment using SET_PARAM_FX
431+
432+ // the SET_PARAM function returns the env address after setting the parameter
433+ // so we can chain the calls together
434+ return wasm . raw `
435+ (global.get ${ CURR_ENV } )
436+ (call ${ PRE_APPLY_FX . name } ${ callee } (i32.const ${ args . length } ))
437+
438+ ${ args . map (
439+ ( arg , i ) =>
440+ wasm . raw `
441+ (i32.const ${ i * 12 } ) (i32.add) ${ arg } (call ${ SET_PARAM_FX . name } )`
442+ ) }
443+
444+ (global.set ${ CURR_ENV } )
445+ (call ${ APPLY_FX_NAME } )
446+ ` ;
447447 }
448448
449449 visitReturnStmt ( stmt : StmtNS . Return ) : WasmInstruction {
0 commit comments