Skip to content

Commit

Permalink
try js codegen of async/await ; bump 0.4.12
Browse files Browse the repository at this point in the history
  • Loading branch information
tiye committed Jul 30, 2021
1 parent d461c3a commit 43323b2
Show file tree
Hide file tree
Showing 10 changed files with 83 additions and 13 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "calcit_runner"
version = "0.4.11"
version = "0.4.12"
authors = ["jiyinyiyong <jiyinyiyong@gmail.com>"]
edition = "2018"
license = "MIT"
Expand Down
18 changes: 18 additions & 0 deletions calcit/snapshots/test-js.cirru
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,22 @@
assert= 3 $ .-c b
assert= 2 $ aget b |b

|test-async $ quote
fn ()
let
f1 $ fn ()
hint-fn async
new js/Promise $ fn (resolve reject)
js/setTimeout
fn ()
println "|async code finished after 1s"
resolve true
, 1000
f2 $ fn ()
hint-fn async
js-await $ f1
f2

|main! $ quote
defn main! ()
log-title "|Testing js"
Expand All @@ -84,6 +100,8 @@

test-collection

test-async

when (> 1 2)
raise (str "|error of math" 2 1)
raise "|base error"
Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@calcit/procs",
"version": "0.4.11",
"version": "0.4.12",
"main": "./lib/calcit.procs.js",
"devDependencies": {
"@types/node": "^15.12.2",
Expand All @@ -12,7 +12,8 @@
"compile": "rm -rfv lib/* && tsc",
"procs-link": "ln -s ../../ node_modules/@calcit/procs",
"cp-mac": "cargo build --release && rm -rfv builds/* && node scripts/cp-version.js && scp builds/* rsync-user@calcit-lang.org:/web-assets/repo/calcit-lang/binaries/macos/",
"test-js": "cargo run calcit/snapshots/test.cirru --emit-js && yarn tsc && target=node yarn webpack && node js-out/bundle.js"
"try-rs": "cargo run --bin cr -- calcit/snapshots/test.cirru -1",
"try-js": "cargo run --bin cr -- calcit/snapshots/test.cirru --emit-js -1 && target=node yarn webpack && node js-out/bundle.js"
},
"dependencies": {
"@calcit/ternary-tree": "0.0.16",
Expand Down
4 changes: 4 additions & 0 deletions src/builtins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,7 @@ pub fn is_syntax_name(s: &str) -> bool {
| "sort" // TODO need better solution
| "defatom"
| "reset!"
| "hint-fn"
)
}

Expand Down Expand Up @@ -406,6 +407,8 @@ pub fn handle_syntax(
// "define reference" although it uses a confusing name "atom"
"defatom" => refs::defatom(nodes, scope, file_ns, program),
"reset!" => refs::reset_bang(nodes, scope, file_ns, program),
// different behavoirs, in Rust interpreter it's nil, in js codegen it's nothing
"hint-fn" => meta::no_op(),
a => Err(format!("TODO syntax: {}", a)),
}
}
Expand All @@ -423,6 +426,7 @@ pub fn is_js_syntax_procs(s: &str) -> bool {
| "instance?"
| "&js-object"
| "js-array"
| "js-await"
| "load-console-formatter!"
| "printable"
| "new"
Expand Down
4 changes: 4 additions & 0 deletions src/builtins/meta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -347,3 +347,7 @@ pub fn assoc(xs: &CalcitItems) -> Result<Calcit, String> {
(None, ..) => Err(format!("tuplu:assoc expected 3 arguments, got: {:?}", xs)),
}
}

pub fn no_op() -> Result<Calcit, String> {
Ok(Calcit::Nil)
}
44 changes: 40 additions & 4 deletions src/codegen/emit_js.rs
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,13 @@ fn gen_call_code(
}
None => Err(format!("`new` expected constructor, got nothing, {}", xs)),
},
"js-await" => match body.get(0) {
Some(body) => Ok(format!(
"await {}",
to_js_code(&body, ns, local_defs, file_imports, &None)?,
)),
None => Err(format!("`new` expected constructor, got nothing, {}", xs)),
},
"instance?" => match (body.get(0), body.get(1)) {
(Some(ctor), Some(v)) => Ok(format!(
"{}({} instanceof {})",
Expand Down Expand Up @@ -909,7 +916,7 @@ fn uses_recur(xs: &Calcit) -> bool {
fn gen_js_func(
name: &str,
args: &CalcitItems,
body: &CalcitItems,
raw_body: &CalcitItems,
ns: &str,
exported: bool,
outer_defs: &HashSet<String>,
Expand Down Expand Up @@ -973,6 +980,23 @@ fn gen_js_func(
snippets::tmpl_args_exact(args_count)
};

let mut body: CalcitItems = im::Vector::new();
let mut async_prefix: String = String::from("");

for line in raw_body {
if let Calcit::List(xs) = line {
if let Some(Calcit::Syntax(sym, _ns)) = xs.get(0) {
if sym == "hint-fn" {
if hinted_async(xs) {
async_prefix = String::from("async ")
}
continue;
}
}
}
body.push_back(line.to_owned());
}

if !body.is_empty() && uses_recur(&body[body.len() - 1]) {
let return_var = js_gensym("return_mark");
let fn_def = snippets::tmpl_tail_recursion(
Expand All @@ -983,8 +1007,8 @@ fn gen_js_func(
/* body = */
list_to_js_code(&body, ns, local_defs, &format!("%%{}%% =", return_var), file_imports)?, // dirty trick
/* var_prefix = */ var_prefix.to_owned(),
/* return_mark */
&format!("%%{}%%", return_var),
/* return_mark */ &format!("%%{}%%", return_var),
/* async_prefix */ &async_prefix,
);

let export_mark = if exported {
Expand All @@ -995,7 +1019,8 @@ fn gen_js_func(
Ok(format!("{}{}\n", export_mark, fn_def))
} else {
let fn_definition = format!(
"function {}({}) {{ {}{}\n{} }}",
"{}function {}({}) {{ {}{}\n{} }}",
async_prefix,
escape_var(name),
args_code,
check_args,
Expand All @@ -1007,6 +1032,17 @@ fn gen_js_func(
}
}

/// this is a very rough implementation for now
fn hinted_async(xs: &im::Vector<Calcit>) -> bool {
for x in xs {
match x {
Calcit::Symbol(sym, ..) if sym == "async" => return true,
_ => {}
}
}
return false;
}

fn contains_symbol(xs: &Calcit, y: &str) -> bool {
match xs {
Calcit::Symbol(s, ..) => s == y,
Expand Down
6 changes: 4 additions & 2 deletions src/codegen/emit_js/snippets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ pub fn tmpl_tail_recursion(
body0: String,
var_prefix: String,
return_mark: &str,
async_prefix: &str,
) -> String {
let ret_var = js_gensym("ret");
let times_var = js_gensym("times");
Expand All @@ -63,7 +64,7 @@ pub fn tmpl_tail_recursion(
let check_recur_args = check_args.replace("arguments.length", &format!("{}.args.length", ret_var));

format!(
"function {name}({args_code}) {{
"{async_prefix}function {name}({args_code}) {{
{check_args}
{spreading_code}
let {ret_var} = null;
Expand Down Expand Up @@ -91,7 +92,8 @@ pub fn tmpl_tail_recursion(
var_prefix = var_prefix,
ret_var = ret_var,
times_var = times_var,
check_recur_args = check_recur_args
check_recur_args = check_recur_args,
async_prefix = async_prefix
)
}

Expand Down
2 changes: 1 addition & 1 deletion src/runner/preprocess.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ fn process_list_call(
preprocess_each_items(&name, &name_ns, args, scope_defs, file_ns, program_code, check_warnings)?,
None,
)),
"quote" | "eval" => Ok((
"quote" | "eval" | "hint-fn" => Ok((
preprocess_quote(&name, &name_ns, args, scope_defs, file_ns, program_code)?,
None,
)),
Expand Down
9 changes: 7 additions & 2 deletions ts-src/calcit.procs.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// CALCIT VERSION
export const calcit_version = "0.4.11";
export const calcit_version = "0.4.12";

import { overwriteComparator, initTernaryTreeMap } from "@calcit/ternary-tree";
import { parse } from "@cirru/parser.ts";
Expand Down Expand Up @@ -1263,7 +1263,9 @@ export function invoke_method(p: string) {
return (obj: CalcitValue, ...args: CalcitValue[]) => {
let klass: CalcitRecord;
let value = obj;
if (obj instanceof CalcitTuple) {
if (obj == null) {
throw new Error(`Cannot invoke method \`${p}\` on nil`);
} else if (obj instanceof CalcitTuple) {
if (obj.fst instanceof CalcitRecord) {
klass = obj.fst;
} else {
Expand All @@ -1282,6 +1284,9 @@ export function invoke_method(p: string) {
} else if (obj instanceof CalcitMap) {
klass = calcit_builtin_classes.map;
} else {
if ((obj as any)[p] == null) {
throw new Error(`Missing method \`${p}\` on object`);
}
return (obj as any)[p](...args); // trying to call JavaScript method
}
if (klass == null) {
Expand Down

0 comments on commit 43323b2

Please sign in to comment.