From 09f441203fdc224be83c179c33053e14821e89ae Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Sun, 7 Jan 2024 21:48:41 -0700 Subject: [PATCH 01/15] TODO --- src/g.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/g.rs b/src/g.rs index e66b4a593..be3c6152c 100644 --- a/src/g.rs +++ b/src/g.rs @@ -174,6 +174,10 @@ fn compile_expr(helpers_ctx: &S, program_ctx: &S, e: &S) -> S { tail(&epd), ) } else { + //TODO push locals + //TODO put locals into program_ctx + //TODO compile body expression + //TODO pop locals unimplemented!("compile_expr sugar lambda: {}. {}", args, body); } } else if is_nil(&e) { From 7351c05459df33689fc2691ad5a35db561e1f6cd Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Mon, 8 Jan 2024 10:18:25 -0700 Subject: [PATCH 02/15] improve flatten function intelligence --- src/g.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/g.rs b/src/g.rs index be3c6152c..5f025cbdf 100644 --- a/src/g.rs +++ b/src/g.rs @@ -19,6 +19,11 @@ use std::io::Write; fn flatten(output: &mut String, input: &S) { if is_cons(input) { flatten( output, &head(input) ); + if !(output.ends_with(" ") || + output.ends_with("\t") || + output.ends_with("\n")) { + output.push(' '); + } flatten( output, &tail(input) ); } else if is_atom(input) { let l = input.to_string(); @@ -34,7 +39,6 @@ fn flatten(output: &mut String, input: &S) { else if l=="\"" { output.push('"'); } else { output.push_str( &l ); - output.push( ' ' ); } } } From f30b6a3bfed736164193b008d395331b412ca1d5 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Mon, 8 Jan 2024 15:27:31 -0700 Subject: [PATCH 03/15] create failing testcase for sugared functions --- src/a.rs | 8 ++++++++ src/g.rs | 13 +++++++++++++ tests/c_cli.rs | 3 +++ tests/lm/user_function_sugar1.lm | 6 ++++++ tests/lm/user_function_sugar2.lm | 6 ++++++ tests/lm/user_function_sugar3.lm | 6 ++++++ 6 files changed, 42 insertions(+) create mode 100644 tests/lm/user_function_sugar1.lm create mode 100644 tests/lm/user_function_sugar2.lm create mode 100644 tests/lm/user_function_sugar3.lm diff --git a/src/a.rs b/src/a.rs index fc8b907f6..8de8ad867 100644 --- a/src/a.rs +++ b/src/a.rs @@ -27,6 +27,10 @@ pub fn typ(s: &str) -> S { s_cons( s_atom("type"), s_atom(s) ) } +pub fn local(s: &str) -> S { + s_cons( s_atom("local"), s_atom(s) ) +} + pub fn lambda(l: S, r: S) -> S { s_cons( s_atom("lambda"), s_cons(l,r) ) } @@ -83,6 +87,10 @@ pub fn kv_merge(l: &S, r: &S) -> S { kv(&kvs) } +pub fn kv_add(kv: &S, k: &S, v: &S) -> S { + s_cons( s_cons(k.clone(),v.clone()), kv.clone() ) +} + pub fn kv_ctx(s: &S) -> HashMap { let mut ctx = HashMap::new(); for (k,v) in kv_iter(s) { diff --git a/src/g.rs b/src/g.rs index 5f025cbdf..8f766d72b 100644 --- a/src/g.rs +++ b/src/g.rs @@ -134,6 +134,19 @@ fn is_free(program_ctx: &S, s: &str) -> bool { true } +fn is_local(program_ctx: &S, s: &str) -> String { + for (k,v) in kv_iter(program_ctx) { + let k = k.to_string(); + if s==k { + if head(&v).to_string() == "local" { + return tail(&v).to_string(); + } else { + return "".to_string(); + } + }} + panic!("is_local could not find variable: {}", s) +} + fn compile_expr(helpers_ctx: &S, program_ctx: &S, e: &S) -> S { let e = ctx_eval_soft(helpers_ctx, e); if head(&e).to_string() == "app" { diff --git a/tests/c_cli.rs b/tests/c_cli.rs index c27d16de4..50bf1f78b 100644 --- a/tests/c_cli.rs +++ b/tests/c_cli.rs @@ -66,4 +66,7 @@ fn cli_comparison() { #[test] fn user_defined() { assert_eq!( compile_and_run("tests/lm/user_function_unsugared.lm"), "b" ); + assert_eq!( compile_and_run("tests/lm/user_function_sugar1.lm"), "1" ); + assert_eq!( compile_and_run("tests/lm/user_function_sugar2.lm"), "2" ); + assert_eq!( compile_and_run("tests/lm/user_function_sugar3.lm"), "3" ); } diff --git a/tests/lm/user_function_sugar1.lm b/tests/lm/user_function_sugar1.lm new file mode 100644 index 000000000..1ac9308cf --- /dev/null +++ b/tests/lm/user_function_sugar1.lm @@ -0,0 +1,6 @@ + +f := λx y z. x; + +main := ( + print-s (f (1 2 3)) +); diff --git a/tests/lm/user_function_sugar2.lm b/tests/lm/user_function_sugar2.lm new file mode 100644 index 000000000..dcb436d4b --- /dev/null +++ b/tests/lm/user_function_sugar2.lm @@ -0,0 +1,6 @@ + +f := λx y z. y; + +main := ( + print-s (f (1 2 3)) +); diff --git a/tests/lm/user_function_sugar3.lm b/tests/lm/user_function_sugar3.lm new file mode 100644 index 000000000..71bfef8c5 --- /dev/null +++ b/tests/lm/user_function_sugar3.lm @@ -0,0 +1,6 @@ + +f := λx y z. z; + +main := ( + print-s (f (1 2 3)) +); From 81333babd8b32b1fc5b6b0066450e6e62a301799 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Mon, 8 Jan 2024 15:33:26 -0700 Subject: [PATCH 04/15] define argument destructuring for 2+ args --- src/g.rs | 2 ++ tests/b_p.rs | 1 + 2 files changed, 3 insertions(+) diff --git a/src/g.rs b/src/g.rs index 8f766d72b..3136dc0f2 100644 --- a/src/g.rs +++ b/src/g.rs @@ -191,6 +191,8 @@ fn compile_expr(helpers_ctx: &S, program_ctx: &S, e: &S) -> S { tail(&epd), ) } else { + let mut push_locals = s_nil(); + unimplemented!("destructure args: {}", args); //TODO push locals //TODO put locals into program_ctx //TODO compile body expression diff --git a/tests/b_p.rs b/tests/b_p.rs index 68b963769..4c943815d 100644 --- a/tests/b_p.rs +++ b/tests/b_p.rs @@ -10,6 +10,7 @@ fn expressions() { assert_eq!( parse_expression("λx.y z").to_string(), "(lambda . ((variable . x) . (app . ((variable . y) . (variable . z)))))" ); assert_eq!( parse_expression("(λx.y) z").to_string(), "(app . ((lambda . ((variable . x) . (variable . y))) . (variable . z)))" ); assert_eq!( parse_expression("λx y.z").to_string(), "(lambda . ((app . ((variable . x) . (variable . y))) . (variable . z)))" ); + assert_eq!( parse_expression("λx y z.z").to_string(), "(lambda . ((app . ((app . ((variable . x) . (variable . y))) . (variable . z))) . (variable . z)))" ); } #[test] From 37ed02fcf24b541a37483d24cb572730e581d6f2 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Mon, 8 Jan 2024 15:40:57 -0700 Subject: [PATCH 05/15] start destructuring --- src/g.rs | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/src/g.rs b/src/g.rs index 3136dc0f2..ade9cdbb1 100644 --- a/src/g.rs +++ b/src/g.rs @@ -147,6 +147,18 @@ fn is_local(program_ctx: &S, s: &str) -> String { panic!("is_local could not find variable: {}", s) } +fn destructure_args(helpers_ctx: &S, program_ctx: &S, e: &S) -> (S,S) { + if is_nil(e) { + ( s_nil(), program_ctx.clone() ) + } else if head(&e).to_string()=="variable" { + unimplemented!("destructure_args: {}", e) + } else if head(&e).to_string()=="app" { + unimplemented!("destructure_args: {}", e) + } else { + panic!("Unexpected lhs in destructure_args: {}", e) + } +} + fn compile_expr(helpers_ctx: &S, program_ctx: &S, e: &S) -> S { let e = ctx_eval_soft(helpers_ctx, e); if head(&e).to_string() == "app" { @@ -183,22 +195,16 @@ fn compile_expr(helpers_ctx: &S, program_ctx: &S, e: &S) -> S { } else if head(&e).to_string() == "lambda" { let args = head(&tail(&e)); let body = tail(&tail(&e)); - if is_nil(&args) { - let epd = compile_expr(helpers_ctx, program_ctx, &body); - //don't forget to ret... - s_cons( - s_cons( head(&epd), variable("\n\t ret \n") ), - tail(&epd), - ) - } else { - let mut push_locals = s_nil(); - unimplemented!("destructure args: {}", args); - //TODO push locals - //TODO put locals into program_ctx - //TODO compile body expression - //TODO pop locals - unimplemented!("compile_expr sugar lambda: {}. {}", args, body); - } + let (push_locals,program_ctx) = destructure_args(helpers_ctx, program_ctx, &args); + let epd = compile_expr(helpers_ctx, &program_ctx, &body); + //TODO put locals into program_ctx + //TODO compile body expression + //TODO pop locals + //don't forget to ret... + s_cons( + s_cons( head(&epd), variable("\n\t ret \n") ), + tail(&epd), + ) } else if is_nil(&e) { s_cons( ctx_eval_soft(helpers_ctx, &variable("::yield-nil")), From ba51bddd9884095707ebbd22f4f25c61dd8f7df7 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Mon, 8 Jan 2024 15:45:13 -0700 Subject: [PATCH 06/15] destructuring starts from the tail --- src/g.rs | 4 +++- tests/b_p.rs | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/g.rs b/src/g.rs index ade9cdbb1..23d577420 100644 --- a/src/g.rs +++ b/src/g.rs @@ -153,7 +153,9 @@ fn destructure_args(helpers_ctx: &S, program_ctx: &S, e: &S) -> (S,S) { } else if head(&e).to_string()=="variable" { unimplemented!("destructure_args: {}", e) } else if head(&e).to_string()=="app" { - unimplemented!("destructure_args: {}", e) + let arg_head = head(&tail(&e)); + let arg_tail = tail(&tail(&e)); + unimplemented!("destructure_args: {} {}", arg_head, arg_tail) } else { panic!("Unexpected lhs in destructure_args: {}", e) } diff --git a/tests/b_p.rs b/tests/b_p.rs index 4c943815d..aefcb3377 100644 --- a/tests/b_p.rs +++ b/tests/b_p.rs @@ -5,6 +5,7 @@ use lambda_mountain::*; fn expressions() { assert_eq!( parse_expression("a").to_string(), "(variable . a)" ); assert_eq!( parse_expression("a b").to_string(), "(app . ((variable . a) . (variable . b)))" ); + assert_eq!( parse_expression("a b c").to_string(), "(app . ((app . ((variable . a) . (variable . b))) . (variable . c)))" ); assert_eq!( parse_expression("123").to_string(), "(literal . 123)" ); assert_eq!( parse_expression("λx.y").to_string(), "(lambda . ((variable . x) . (variable . y)))" ); assert_eq!( parse_expression("λx.y z").to_string(), "(lambda . ((variable . x) . (app . ((variable . y) . (variable . z)))))" ); From a87a1e7acb1c55be1b994848f212678e82092f9d Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Mon, 8 Jan 2024 15:49:18 -0700 Subject: [PATCH 07/15] recurse --- src/g.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/g.rs b/src/g.rs index 23d577420..3224ab47c 100644 --- a/src/g.rs +++ b/src/g.rs @@ -155,7 +155,9 @@ fn destructure_args(helpers_ctx: &S, program_ctx: &S, e: &S) -> (S,S) { } else if head(&e).to_string()=="app" { let arg_head = head(&tail(&e)); let arg_tail = tail(&tail(&e)); - unimplemented!("destructure_args: {} {}", arg_head, arg_tail) + let (mut preh, program_ctx) = destructure_args(helpers_ctx, program_ctx, &arg_head); + let (mut pret, program_ctx) = destructure_args(helpers_ctx, &program_ctx, &arg_tail); + ( s_cons(preh, pret), program_ctx ) } else { panic!("Unexpected lhs in destructure_args: {}", e) } From 40d28529f937344ec5d47417e2eadce988a8fdce Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Mon, 8 Jan 2024 16:01:36 -0700 Subject: [PATCH 08/15] use type checking in Rust --- src/g.rs | 56 +++++++++++++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/src/g.rs b/src/g.rs index 3224ab47c..727fd8a57 100644 --- a/src/g.rs +++ b/src/g.rs @@ -113,9 +113,10 @@ fn uuid() -> String { format!("_uuid_{}", id) } -fn yield_atom(helpers_ctx: &S, s: &str) -> S { +//returns (prog, data) +fn yield_atom(helpers_ctx: &S, s: &str) -> (S,S) { let id = uuid(); - s_cons( + ( ctx_eval_soft(helpers_ctx, &app( variable("::yield-atom"), variable(&id) )), variable(&format!("\n{}:\n\t.ascii \"{}\"\n\t.zero 1\n", id, s)), ) @@ -147,51 +148,60 @@ fn is_local(program_ctx: &S, s: &str) -> String { panic!("is_local could not find variable: {}", s) } -fn destructure_args(helpers_ctx: &S, program_ctx: &S, e: &S) -> (S,S) { +//returns (program, data, new program_ctx) +fn destructure_args(helpers_ctx: &S, program_ctx: &S, e: &S) -> (S,S,S) { if is_nil(e) { - ( s_nil(), program_ctx.clone() ) + ( s_nil(), s_nil(), program_ctx.clone() ) } else if head(&e).to_string()=="variable" { unimplemented!("destructure_args: {}", e) } else if head(&e).to_string()=="app" { let arg_head = head(&tail(&e)); let arg_tail = tail(&tail(&e)); + //store head in %r8, r9, r10, r11 + //load tail into this + /* + let store_head = compile_expr(helpers_ctx, program_ctx + let load_head_into_this = compile_expr(helpers_ctx, program_ctx, &app(variable("head"),variable("$_")) ) let (mut preh, program_ctx) = destructure_args(helpers_ctx, program_ctx, &arg_head); let (mut pret, program_ctx) = destructure_args(helpers_ctx, &program_ctx, &arg_tail); ( s_cons(preh, pret), program_ctx ) + */ + unimplemented!("destructure_args: {}", e) } else { panic!("Unexpected lhs in destructure_args: {}", e) } } -fn compile_expr(helpers_ctx: &S, program_ctx: &S, e: &S) -> S { +//returns (program, data) +fn compile_expr(helpers_ctx: &S, program_ctx: &S, e: &S) -> (S,S) { let e = ctx_eval_soft(helpers_ctx, e); if head(&e).to_string() == "app" { let fx = tail(&e); let f = head(&fx); let x = tail(&fx); - let xpd = compile_expr(helpers_ctx, program_ctx, &x); + let (xprog,xdata) = compile_expr(helpers_ctx, program_ctx, &x); if (head(&f).to_string() == "variable" || head(&f).to_string() == "literal") && !is_free(program_ctx, &tail(&f).to_string()) { let f_name = variable(&label_case( &tail(&f).to_string() )); - let prog = s_cons( head(&xpd) , s_cons( s_cons( variable("\tcall"), f_name ), variable("\n") )); - s_cons(prog, tail(&xpd)) + let prog = s_cons( xprog , s_cons( s_cons( variable("\tcall"), f_name ), variable("\n") )); + (prog, xdata) } else { - let fpd = compile_expr(helpers_ctx, program_ctx, &f); + let (fprog,fdata) = compile_expr(helpers_ctx, program_ctx, &f); let prog = ctx_eval_soft(helpers_ctx, &app( variable("::yield-cons"), - app( head(&fpd), head(&xpd) ) + app( fprog, xprog ) )); let data = app( - tail(&fpd), - tail(&xpd), + fdata, + xdata, ); - s_cons(prog, data) + (prog, data) } } else if head(&e).to_string() == "variable" && tail(&e).to_string() == "$_" { // $_ is a noop expression and colloquially refers to 'this' expression - s_cons( s_nil(), s_nil() ) + ( s_nil(), s_nil() ) } else if head(&e).to_string() == "variable" { yield_atom(helpers_ctx, &tail(&e).to_string() ) } else if head(&e).to_string() == "literal" { @@ -199,18 +209,18 @@ fn compile_expr(helpers_ctx: &S, program_ctx: &S, e: &S) -> S { } else if head(&e).to_string() == "lambda" { let args = head(&tail(&e)); let body = tail(&tail(&e)); - let (push_locals,program_ctx) = destructure_args(helpers_ctx, program_ctx, &args); - let epd = compile_expr(helpers_ctx, &program_ctx, &body); + let (push_prog,push_data,program_ctx) = destructure_args(helpers_ctx, program_ctx, &args); + let (eprog,edata) = compile_expr(helpers_ctx, &program_ctx, &body); //TODO put locals into program_ctx //TODO compile body expression //TODO pop locals //don't forget to ret... - s_cons( - s_cons( head(&epd), variable("\n\t ret \n") ), - tail(&epd), + ( + s_cons( eprog, variable("\n\t ret \n") ), + edata, ) } else if is_nil(&e) { - s_cons( + ( ctx_eval_soft(helpers_ctx, &variable("::yield-nil")), nil(), ) @@ -253,12 +263,12 @@ pub fn compile(cfg: &str, main_ctx: &S) { } for (k,v) in kv_iter(&main_ctx) { let k = k.to_string(); - let vpd = compile_expr(&helpers_ctx, &main_ctx, &v); + let (vprog,vdata) = compile_expr(&helpers_ctx, &main_ctx, &v); raw_program = app( raw_program, app( variable(&format!("\n{}:\n",label_case(&k))), - head(&vpd), + vprog, ), ); if k == "main" { @@ -269,7 +279,7 @@ pub fn compile(cfg: &str, main_ctx: &S) { } raw_data = app( raw_data, - tail(&vpd), + vdata, ); } let program = compile_program(&helpers_ctx, &raw_program, &raw_data); From bc790e08d65ac06556f70b3cf9d4e237c8986b8b Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Mon, 8 Jan 2024 16:23:20 -0700 Subject: [PATCH 09/15] destructure simple cons --- src/g.rs | 37 +++++++++++++++++++------------------ stdlib/helpers.lm | 14 ++++++++++++++ 2 files changed, 33 insertions(+), 18 deletions(-) diff --git a/src/g.rs b/src/g.rs index 727fd8a57..71abcb2ef 100644 --- a/src/g.rs +++ b/src/g.rs @@ -148,25 +148,27 @@ fn is_local(program_ctx: &S, s: &str) -> String { panic!("is_local could not find variable: {}", s) } -//returns (program, data, new program_ctx) -fn destructure_args(helpers_ctx: &S, program_ctx: &S, e: &S) -> (S,S,S) { +//returns (program, new program_ctx) +fn destructure_args(helpers_ctx: &S, program_ctx: &S, e: &S) -> (S,S) { if is_nil(e) { - ( s_nil(), s_nil(), program_ctx.clone() ) + ( s_nil(), program_ctx.clone() ) } else if head(&e).to_string()=="variable" { unimplemented!("destructure_args: {}", e) } else if head(&e).to_string()=="app" { let arg_head = head(&tail(&e)); let arg_tail = tail(&tail(&e)); - //store head in %r8, r9, r10, r11 - //load tail into this - /* - let store_head = compile_expr(helpers_ctx, program_ctx - let load_head_into_this = compile_expr(helpers_ctx, program_ctx, &app(variable("head"),variable("$_")) ) - let (mut preh, program_ctx) = destructure_args(helpers_ctx, program_ctx, &arg_head); - let (mut pret, program_ctx) = destructure_args(helpers_ctx, &program_ctx, &arg_tail); - ( s_cons(preh, pret), program_ctx ) - */ - unimplemented!("destructure_args: {}", e) + let (store_this,_) = compile_expr(helpers_ctx, program_ctx, &variable("::shadow-this")); + let (restore_this,_) = compile_expr(helpers_ctx, program_ctx, &variable("::unshadow-this")); + let (load_head,_) = compile_expr(helpers_ctx, program_ctx, &app(variable("head"),variable("$_")) ); + let (load_tail,_) = compile_expr(helpers_ctx, program_ctx, &app(variable("tail"),variable("$_")) ); + let (dest_head, program_ctx) = destructure_args(helpers_ctx, program_ctx, &arg_head); + let (dest_tail, program_ctx) = destructure_args(helpers_ctx, &program_ctx, &arg_tail); + let prog = s_cons(store_this, load_tail); + let prog = s_cons(prog, dest_tail); + let prog = s_cons(prog, restore_this); + let prog = s_cons(prog, load_head); + let prog = s_cons(prog, dest_head); + (prog, program_ctx) } else { panic!("Unexpected lhs in destructure_args: {}", e) } @@ -209,16 +211,15 @@ fn compile_expr(helpers_ctx: &S, program_ctx: &S, e: &S) -> (S,S) { } else if head(&e).to_string() == "lambda" { let args = head(&tail(&e)); let body = tail(&tail(&e)); - let (push_prog,push_data,program_ctx) = destructure_args(helpers_ctx, program_ctx, &args); + let (push_prog,program_ctx) = destructure_args(helpers_ctx, program_ctx, &args); let (eprog,edata) = compile_expr(helpers_ctx, &program_ctx, &body); + let prog = s_cons( push_prog, eprog ); + let prog = s_cons( prog, variable("\n\tret\n") ); //TODO put locals into program_ctx //TODO compile body expression //TODO pop locals //don't forget to ret... - ( - s_cons( eprog, variable("\n\t ret \n") ), - edata, - ) + ( prog, edata ) } else if is_nil(&e) { ( ctx_eval_soft(helpers_ctx, &variable("::yield-nil")), diff --git a/stdlib/helpers.lm b/stdlib/helpers.lm index 9fc49fb63..a1ef117be 100644 --- a/stdlib/helpers.lm +++ b/stdlib/helpers.lm @@ -274,6 +274,20 @@ \t pop %r12 \n ); +::shadow-this := ( + \t mov %r12, %r8 \n + \t mov %r13, %r9 \n + \t mov %r14, %r10 \n + \t mov %r15, %r11 \n +); + +::unshadow-this := ( + \t mov %r8, %r15 \n + \t mov %r9, %r14 \n + \t mov %r10, %r13 \n + \t mov %r11, %r12 \n +); + ::close-this := ( # move this S onto the heap # %rsi becomes pointer to new location From 36c6048a4360dc0b97394395ab05b3682cfa0e02 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Mon, 8 Jan 2024 16:34:45 -0700 Subject: [PATCH 10/15] compiling --- src/g.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/g.rs b/src/g.rs index 71abcb2ef..8cb4e9917 100644 --- a/src/g.rs +++ b/src/g.rs @@ -149,20 +149,23 @@ fn is_local(program_ctx: &S, s: &str) -> String { } //returns (program, new program_ctx) -fn destructure_args(helpers_ctx: &S, program_ctx: &S, e: &S) -> (S,S) { +fn destructure_args(helpers_ctx: &S, program_ctx: &S, e: &S, offset: usize) -> (S,S) { if is_nil(e) { ( s_nil(), program_ctx.clone() ) } else if head(&e).to_string()=="variable" { - unimplemented!("destructure_args: {}", e) + let vname = tail(&e); + let push_this = ctx_eval_soft(helpers_ctx, &variable("::push-this")); + let program_ctx = kv_add( program_ctx, &vname, &local(&format!("{}",offset*32)) ); + (push_this, program_ctx) } else if head(&e).to_string()=="app" { let arg_head = head(&tail(&e)); let arg_tail = tail(&tail(&e)); - let (store_this,_) = compile_expr(helpers_ctx, program_ctx, &variable("::shadow-this")); - let (restore_this,_) = compile_expr(helpers_ctx, program_ctx, &variable("::unshadow-this")); + let store_this = ctx_eval_soft(helpers_ctx, &variable("::shadow-this")); + let restore_this = ctx_eval_soft(helpers_ctx, &variable("::unshadow-this")); let (load_head,_) = compile_expr(helpers_ctx, program_ctx, &app(variable("head"),variable("$_")) ); let (load_tail,_) = compile_expr(helpers_ctx, program_ctx, &app(variable("tail"),variable("$_")) ); - let (dest_head, program_ctx) = destructure_args(helpers_ctx, program_ctx, &arg_head); - let (dest_tail, program_ctx) = destructure_args(helpers_ctx, &program_ctx, &arg_tail); + let (dest_head, program_ctx) = destructure_args(helpers_ctx, program_ctx, &arg_head, offset+1); + let (dest_tail, program_ctx) = destructure_args(helpers_ctx, &program_ctx, &arg_tail, offset); let prog = s_cons(store_this, load_tail); let prog = s_cons(prog, dest_tail); let prog = s_cons(prog, restore_this); @@ -211,7 +214,7 @@ fn compile_expr(helpers_ctx: &S, program_ctx: &S, e: &S) -> (S,S) { } else if head(&e).to_string() == "lambda" { let args = head(&tail(&e)); let body = tail(&tail(&e)); - let (push_prog,program_ctx) = destructure_args(helpers_ctx, program_ctx, &args); + let (push_prog,program_ctx) = destructure_args(helpers_ctx, program_ctx, &args, 0); let (eprog,edata) = compile_expr(helpers_ctx, &program_ctx, &body); let prog = s_cons( push_prog, eprog ); let prog = s_cons( prog, variable("\n\tret\n") ); From 0d0ee8b0bf9202244a42e9fd16643902f4fce8cb Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Mon, 8 Jan 2024 17:18:59 -0700 Subject: [PATCH 11/15] allocating space for local variables on stack frame works --- src/g.rs | 23 +++++++++++++---------- stdlib/helpers.lm | 15 +++++++++++---- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/src/g.rs b/src/g.rs index 8cb4e9917..977b7c3ae 100644 --- a/src/g.rs +++ b/src/g.rs @@ -148,15 +148,16 @@ fn is_local(program_ctx: &S, s: &str) -> String { panic!("is_local could not find variable: {}", s) } -//returns (program, new program_ctx) -fn destructure_args(helpers_ctx: &S, program_ctx: &S, e: &S, offset: usize) -> (S,S) { +//returns (push program, pop program, new program_ctx) +fn destructure_args(helpers_ctx: &S, program_ctx: &S, e: &S, offset: usize) -> (S,S,S) { if is_nil(e) { - ( s_nil(), program_ctx.clone() ) + ( s_nil(), s_nil(), program_ctx.clone() ) } else if head(&e).to_string()=="variable" { let vname = tail(&e); let push_this = ctx_eval_soft(helpers_ctx, &variable("::push-this")); + let pop_this = ctx_eval_soft(helpers_ctx, &variable("::unpush-this")); let program_ctx = kv_add( program_ctx, &vname, &local(&format!("{}",offset*32)) ); - (push_this, program_ctx) + (push_this, pop_this, program_ctx) } else if head(&e).to_string()=="app" { let arg_head = head(&tail(&e)); let arg_tail = tail(&tail(&e)); @@ -164,14 +165,15 @@ fn destructure_args(helpers_ctx: &S, program_ctx: &S, e: &S, offset: usize) -> ( let restore_this = ctx_eval_soft(helpers_ctx, &variable("::unshadow-this")); let (load_head,_) = compile_expr(helpers_ctx, program_ctx, &app(variable("head"),variable("$_")) ); let (load_tail,_) = compile_expr(helpers_ctx, program_ctx, &app(variable("tail"),variable("$_")) ); - let (dest_head, program_ctx) = destructure_args(helpers_ctx, program_ctx, &arg_head, offset+1); - let (dest_tail, program_ctx) = destructure_args(helpers_ctx, &program_ctx, &arg_tail, offset); + let (push_head, pop_head, program_ctx) = destructure_args(helpers_ctx, program_ctx, &arg_head, offset+1); + let (push_tail, pop_tail, program_ctx) = destructure_args(helpers_ctx, &program_ctx, &arg_tail, offset); let prog = s_cons(store_this, load_tail); - let prog = s_cons(prog, dest_tail); + let prog = s_cons(prog, push_tail); let prog = s_cons(prog, restore_this); let prog = s_cons(prog, load_head); - let prog = s_cons(prog, dest_head); - (prog, program_ctx) + let prog = s_cons(prog, push_head); + let unprog = s_cons(pop_head, pop_tail); + (prog, unprog, program_ctx) } else { panic!("Unexpected lhs in destructure_args: {}", e) } @@ -214,9 +216,10 @@ fn compile_expr(helpers_ctx: &S, program_ctx: &S, e: &S) -> (S,S) { } else if head(&e).to_string() == "lambda" { let args = head(&tail(&e)); let body = tail(&tail(&e)); - let (push_prog,program_ctx) = destructure_args(helpers_ctx, program_ctx, &args, 0); + let (push_prog,pop_prog,program_ctx) = destructure_args(helpers_ctx, program_ctx, &args, 0); let (eprog,edata) = compile_expr(helpers_ctx, &program_ctx, &body); let prog = s_cons( push_prog, eprog ); + let prog = s_cons( prog, pop_prog ); let prog = s_cons( prog, variable("\n\tret\n") ); //TODO put locals into program_ctx //TODO compile body expression diff --git a/stdlib/helpers.lm b/stdlib/helpers.lm index a1ef117be..6967a7f4e 100644 --- a/stdlib/helpers.lm +++ b/stdlib/helpers.lm @@ -267,6 +267,13 @@ \t push %r15 \n ); +::unpush-this := ( + \t pop %r8 \n + \t pop %r8 \n + \t pop %r8 \n + \t pop %r8 \n +); + ::pop-this := ( \t pop %r15 \n \t pop %r14 \n @@ -282,10 +289,10 @@ ); ::unshadow-this := ( - \t mov %r8, %r15 \n - \t mov %r9, %r14 \n - \t mov %r10, %r13 \n - \t mov %r11, %r12 \n + \t mov %r8, %r12 \n + \t mov %r9, %r13 \n + \t mov %r10, %r14 \n + \t mov %r11, %r15 \n ); ::close-this := ( From fa4071feb0cae2e662bbd999d72f511d40a3c47b Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Mon, 8 Jan 2024 17:32:10 -0700 Subject: [PATCH 12/15] fixup frame pointer in functions --- src/g.rs | 11 ++++++++--- stdlib/helpers.lm | 10 ++++++++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/g.rs b/src/g.rs index 977b7c3ae..ee0802a09 100644 --- a/src/g.rs +++ b/src/g.rs @@ -156,7 +156,8 @@ fn destructure_args(helpers_ctx: &S, program_ctx: &S, e: &S, offset: usize) -> ( let vname = tail(&e); let push_this = ctx_eval_soft(helpers_ctx, &variable("::push-this")); let pop_this = ctx_eval_soft(helpers_ctx, &variable("::unpush-this")); - let program_ctx = kv_add( program_ctx, &vname, &local(&format!("{}",offset*32)) ); + let refer = local("TODO"); + let program_ctx = kv_add( program_ctx, &vname, &refer ); (push_this, pop_this, program_ctx) } else if head(&e).to_string()=="app" { let arg_head = head(&tail(&e)); @@ -218,9 +219,13 @@ fn compile_expr(helpers_ctx: &S, program_ctx: &S, e: &S) -> (S,S) { let body = tail(&tail(&e)); let (push_prog,pop_prog,program_ctx) = destructure_args(helpers_ctx, program_ctx, &args, 0); let (eprog,edata) = compile_expr(helpers_ctx, &program_ctx, &body); - let prog = s_cons( push_prog, eprog ); + let enter = ctx_eval_soft(helpers_ctx, &variable("::enter-function")); + let leave = ctx_eval_soft(helpers_ctx, &variable("::leave-function")); + let prog = enter; + let prog = s_cons( prog, push_prog ); + let prog = s_cons( prog, eprog ); let prog = s_cons( prog, pop_prog ); - let prog = s_cons( prog, variable("\n\tret\n") ); + let prog = s_cons( prog, leave ); //TODO put locals into program_ctx //TODO compile body expression //TODO pop locals diff --git a/stdlib/helpers.lm b/stdlib/helpers.lm index 6967a7f4e..18e78689c 100644 --- a/stdlib/helpers.lm +++ b/stdlib/helpers.lm @@ -56,6 +56,16 @@ \t pop %r12 \n ); +::enter-function := ( + \t push %rbp \n + \t mov %rsp, %rbp \n +); +::leave-function := ( + \t mov %rbp, %rsp \n + \t pop %rbp \n + \t ret \n +); + # put8 (%r8 bool[4], %r9: *char) ::put8 := ( \t mov %r8b, %al \n # lower byte of %r11 goes into %rax From b8c58494c61a045808a5d73f1daccf5b28334daf Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Mon, 8 Jan 2024 17:44:34 -0700 Subject: [PATCH 13/15] interesting bug pointing to strings from the ELF section --- src/g.rs | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/g.rs b/src/g.rs index ee0802a09..d3608348e 100644 --- a/src/g.rs +++ b/src/g.rs @@ -145,7 +145,7 @@ fn is_local(program_ctx: &S, s: &str) -> String { return "".to_string(); } }} - panic!("is_local could not find variable: {}", s) + "".to_string() } //returns (push program, pop program, new program_ctx) @@ -156,7 +156,16 @@ fn destructure_args(helpers_ctx: &S, program_ctx: &S, e: &S, offset: usize) -> ( let vname = tail(&e); let push_this = ctx_eval_soft(helpers_ctx, &variable("::push-this")); let pop_this = ctx_eval_soft(helpers_ctx, &variable("::unpush-this")); - let refer = local("TODO"); + let refer = local(&format!( + "\tmov {}(%rbp), %r12\n \ + \tmov {}(%rbp), %r13\n \ + \tmov {}(%rbp), %r14\n \ + \tmov {}(%rbp), %r15\n", + offset*32 + 0, + offset*32 + 8, + offset*32 + 16, + offset*32 + 24 + )); let program_ctx = kv_add( program_ctx, &vname, &refer ); (push_this, pop_this, program_ctx) } else if head(&e).to_string()=="app" { @@ -211,7 +220,13 @@ fn compile_expr(helpers_ctx: &S, program_ctx: &S, e: &S) -> (S,S) { // $_ is a noop expression and colloquially refers to 'this' expression ( s_nil(), s_nil() ) } else if head(&e).to_string() == "variable" { - yield_atom(helpers_ctx, &tail(&e).to_string() ) + let vname = tail(&e).to_string(); + let local = is_local(program_ctx, &vname); + if local == "" { + yield_atom(helpers_ctx, &vname ) + } else { + ( s_atom(&local), s_nil() ) + } } else if head(&e).to_string() == "literal" { yield_atom(helpers_ctx, &tail(&e).to_string() ) } else if head(&e).to_string() == "lambda" { From ad4cdd1c0b2fa289ae4a966009463bad80af5dc7 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Mon, 8 Jan 2024 18:05:02 -0700 Subject: [PATCH 14/15] sugar --- src/g.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/g.rs b/src/g.rs index d3608348e..d4fa9a096 100644 --- a/src/g.rs +++ b/src/g.rs @@ -149,7 +149,7 @@ fn is_local(program_ctx: &S, s: &str) -> String { } //returns (push program, pop program, new program_ctx) -fn destructure_args(helpers_ctx: &S, program_ctx: &S, e: &S, offset: usize) -> (S,S,S) { +fn destructure_args(helpers_ctx: &S, program_ctx: &S, e: &S, offset: i64) -> (S,S,S) { if is_nil(e) { ( s_nil(), s_nil(), program_ctx.clone() ) } else if head(&e).to_string()=="variable" { @@ -161,10 +161,10 @@ fn destructure_args(helpers_ctx: &S, program_ctx: &S, e: &S, offset: usize) -> ( \tmov {}(%rbp), %r13\n \ \tmov {}(%rbp), %r14\n \ \tmov {}(%rbp), %r15\n", - offset*32 + 0, - offset*32 + 8, - offset*32 + 16, - offset*32 + 24 + -offset*32 - 8, + -offset*32 - 16, + -offset*32 - 24, + -offset*32 - 32, )); let program_ctx = kv_add( program_ctx, &vname, &refer ); (push_this, pop_this, program_ctx) From 166a796602bd02ce7e45b7fca11c76b8b4b86a64 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Mon, 8 Jan 2024 18:05:34 -0700 Subject: [PATCH 15/15] C-style stackframes are good for bootstrapping --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index e4d395a08..1aa9c5437 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lambda_mountain" -version = "0.1.14" +version = "0.1.15" authors = ["Andrew "] license = "MIT" description = "Lambda Mountain"