Skip to content

Commit bbdab83

Browse files
authored
Merge pull request #473 from antfu/feat/execute
Execute function for core package
2 parents d97bf09 + 4e6608a commit bbdab83

File tree

13 files changed

+280
-379
lines changed

13 files changed

+280
-379
lines changed

documentation/Compiler-API.md

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,28 +44,53 @@ const compiled = Wenyan.compile('吾有一言。曰「「問天地好在。」
4444

4545
- core
4646
- [compile](#compile)
47+
- [execute](#execute)
48+
49+
### Execute
50+
51+
[Source](../src/parser.js)
52+
53+
```ts
54+
function execute(source: string, options?: ExecuteOptions)
55+
```
56+
57+
**Parameters**
58+
59+
| Name | Type | Note |
60+
| --- | --- | --- |
61+
| source | string | The Wenyan source code |
62+
| options | object | [Execute Options](#Execute-Options) |
4763

4864
### Compile
4965

5066
[Source](../src/parser.js)
5167

5268
```ts
53-
function compile(targetLang: string, source: string, options?: CompilerOptions)
69+
function compile(source: string, options?: CompilerOptions)
5470
```
5571

5672
**Parameters**
5773

5874
| Name | Type | Note |
5975
| --- | --- | --- |
60-
| targetLang | string | Can be `js`, `py` or `rb` |
6176
| source | string | The Wenyan source code |
6277
| options | object | [Compiler Options](#Compiler-Options) |
6378

64-
### Compiler Options
79+
#### Compiler Options
6580

6681
| Fields | Default Value | Note |
6782
| --- | --- | --- |
83+
| lang | `js` | Target language, can be `js`, `py` or `rb` |
6884
| romanizeIdentifiers | none | Romanize variable identifiers (e.g. `` to `JIA2`) |
6985
| resetVarCnt | false | Reset temporary variable counter |
7086
| logCallback | console.log | Get verbose debug log |
7187
| errorLog | process.exit | Error log |
88+
89+
#### Execute Options
90+
91+
Execute Options extends all field in [Compiler Options](#Compiler-Options)
92+
93+
| Fields | Default Value | Note |
94+
| --- | --- | --- |
95+
| outputHanzi | true | Convert numbers and bools to Hanzi |
96+
| output | `console.log` | You can redirect the output if you don't want to use `console.log` |

documentation/Runtime.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
You can now run Wenyan as normal Javscript script right in your html.
66

7-
[**Check out the demo**](https://jsfiddle.net/antfu/u532ny49/2/)
7+
[**Check out the demo**](https://jsfiddle.net/antfu/u532ny49/)
88

99
## Installation
1010

@@ -47,6 +47,16 @@ You can import remote scripts as you will do for Javascript.
4747
<script type="application/wenyan" src="https://raw.githubusercontent.com/LingDong-/wenyan-lang/master/examples/fizzbuzz.wy"></script>
4848
```
4949

50+
### Outputing Hanzi
51+
52+
By default, it will convert numbers and bools to hanzi. If you want to output raw numbers, you can specify `ouputHanzi="false"` in attr of script tag.
53+
54+
```html
55+
<script type="application/wenyan" ouputHanzi="false">
56+
吾有一數。曰三。書之。
57+
</script>
58+
```
59+
5060
### DOM Hacks
5161

5262
There are some hacks you can do to access the DOM and browser APIs. This allows wenyan to do some realworld applications.

documentation/Testing.md

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,7 @@
44

55
This project uses [Mocha](https://mochajs.org/) and [Chai](https://www.chaijs.com/) for unit testing and snapshot testing.
66

7-
You will need to build first
8-
9-
```bash
10-
npm run build
11-
```
12-
13-
Then you can run all the tests by
7+
You can run all the tests by
148

159
```bash
1610
npm test

src/browser_runtime.js

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,27 @@
11
/* wenyan-catsrc-ignore */
22

33
(() => {
4-
const { compile } = require("./parser");
4+
const { execute } = require("./parser");
55

66
const isDev = false;
77

88
async function run(script) {
99
const scoped = !!script.attributes.scoped;
10+
const outputHanzi = !(
11+
script.attributes.outputHanzi &&
12+
script.attributes.outputHanzi.value === "false"
13+
);
14+
let code = script.innerText;
1015
if (script.src) {
1116
const response = await fetch(script.src);
12-
const code = await response.text();
13-
await exec(code.toString(), scoped);
14-
} else {
15-
await exec(script.innerText, scoped);
17+
code = (await response.text()).toString();
1618
}
17-
}
18-
19-
async function exec(code, scoped = false) {
20-
let compiled = compile("js", code, {
19+
execute(code, {
20+
scoped,
21+
outputHanzi,
2122
logCallback: isDev ? console.log : () => {},
2223
resetVarCnt: false
2324
});
24-
25-
// wrap for scoped scripts that won't expose any variables to global
26-
if (scoped) compiled = `(()=>{${compiled}})()`;
27-
28-
// executing
29-
window.eval(compiled);
3025
}
3126

3227
document.addEventListener("DOMContentLoaded", async () => {

src/cli.js

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
const fs = require("fs");
22
const version = require("./version");
3-
const { compile } = require("./parser");
3+
const { compile, evalCompiled } = require("./parser");
44
const { render, unrender } = require("./render");
55
const path = require("path");
66
const commander = require("commander");
@@ -38,6 +38,7 @@ program
3838
"--roman [method]",
3939
'Romanize identifiers. The method can be "pinyin", "baxter" or "unicode"'
4040
)
41+
.option("--outputHanzi", "Convert output to hanzi", true)
4142
.option("--log <file>", "Save log to file")
4243
.option("--title <title>", "Override title in rendering")
4344
.helpOption("-h, --help", "Display help");
@@ -192,17 +193,11 @@ function exec() {
192193
);
193194
process.exit(1);
194195
}
195-
if (program.lang === "js") {
196-
eval(getCompiled());
197-
} else if (program.lang === "py") {
198-
var execSync = require("child_process").execSync;
199-
fs.writeFileSync("tmp.py", out);
200-
var ret = execSync(
201-
"which python3; if [ $? == 0 ]; then python3 tmp.py; else python tmp.py; fi; rm tmp.py",
202-
{ encoding: "utf-8" }
203-
);
204-
console.log(ret);
205-
}
196+
197+
evalCompiled(getCompiled(), {
198+
outputHanzi: program.outputHanzi,
199+
lang: program.lang
200+
});
206201
}
207202

208203
function replscope() {

src/macro.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
function extractMacros(lang, txt, { lib, reader }) {
1+
function extractMacros(txt, { lib, reader, lang }) {
22
function getImports() {
33
var imps = [];
44
for (var i = 0; i < txt.length; i++) {
@@ -108,7 +108,7 @@ function extractMacros(lang, txt, { lib, reader }) {
108108
} else {
109109
isrc = reader(imports[i]);
110110
}
111-
macros = macros.concat(extractMacros(lang, isrc, { lib, reader }));
111+
macros = macros.concat(extractMacros(isrc, { lib, reader, lang }));
112112
}
113113
return macros;
114114
}

src/parser.js

Lines changed: 90 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
try {
2-
var { hanzi2num, hanzi2numstr, num2hanzi, bool2hanzi } = require("./hanzi2num");
2+
var {
3+
hanzi2num,
4+
hanzi2numstr,
5+
num2hanzi,
6+
bool2hanzi
7+
} = require("./hanzi2num");
38
var hanzi2pinyin = require("./hanzi2pinyin");
49
var STDLIB = require("./stdlib");
510
var { NUMBER_KEYWORDS, KEYWORDS } = require("./keywords");
@@ -648,10 +653,21 @@ function defaultReader(x) {
648653
}
649654
}
650655

651-
function compile(
652-
lang,
653-
txt,
654-
{
656+
function compile(arg1, arg2, arg3) {
657+
let options = {};
658+
let txt = "";
659+
660+
if (typeof arg2 === "string") {
661+
// backward compatible
662+
txt = arg2;
663+
options = { ...arg3, lang: arg1 };
664+
} else {
665+
txt = arg1;
666+
options = arg2;
667+
}
668+
669+
const {
670+
lang = "js",
655671
romanizeIdentifiers = "none",
656672
resetVarCnt,
657673
logCallback = x =>
@@ -661,8 +677,8 @@ function compile(
661677
errorCallback = process.exit,
662678
lib = typeof STDLIB == "undefined" ? {} : STDLIB,
663679
reader = defaultReader
664-
} = {}
665-
) {
680+
} = options;
681+
666682
if (resetVarCnt) idenMap = {};
667683
txt = (txt || "").replace(/\r\n/g, "\n");
668684

@@ -692,7 +708,7 @@ function compile(
692708
return 0;
693709
}
694710

695-
var macros = extractMacros(lang, txt, { lib, reader });
711+
var macros = extractMacros(txt, { lib, reader, lang });
696712
txt = expandMacros(txt, macros);
697713

698714
logCallback("\n\n=== [PASS 0] EXPAND-MACROS ===");
@@ -740,7 +756,8 @@ function compile(
740756
targ =
741757
mwrapper(
742758
imports[i],
743-
compile(lang, isrc, {
759+
compile(isrc, {
760+
lang,
744761
romanizeIdentifiers,
745762
resetVarCnt: false,
746763
logCallback,
@@ -753,8 +770,72 @@ function compile(
753770
return targ;
754771
}
755772

773+
function isLangSupportedForEval(lang) {
774+
if (lang !== "js")
775+
throw new Error(
776+
`Executing for target language "${lang}" is not supported in current environment`
777+
);
778+
return true;
779+
}
780+
781+
function hanzinize(value) {
782+
if (typeof value == "number") {
783+
return num2hanzi(value);
784+
} else if (typeof value == "boolean") {
785+
return bool2hanzi(value);
786+
} else if (Array.isArray(value)) {
787+
return value.map(i => hanzinize(i)).join("。");
788+
} else {
789+
return value;
790+
}
791+
}
792+
793+
function outputHanziWrapper(log, outputHanzi) {
794+
return function output(...args) {
795+
log(...args.map(i => (outputHanzi ? hanzinize(i) : i)));
796+
};
797+
}
798+
799+
function evalCompiled(compiledCode, options = {}) {
800+
const {
801+
outputHanzi = true,
802+
scoped = false,
803+
lang = "js",
804+
output = console.log
805+
} = options;
806+
807+
isLangSupportedForEval(lang);
808+
809+
let code = compiledCode;
810+
811+
(() => {
812+
const _console_log = console.log;
813+
console.log = outputHanziWrapper(output, outputHanzi);
814+
try {
815+
if (!scoped && "window" in this) {
816+
window.eval(code);
817+
} else {
818+
eval(code);
819+
}
820+
} catch (e) {
821+
throw e;
822+
} finally {
823+
console.log = _console_log;
824+
}
825+
})();
826+
}
827+
828+
function execute(source, options = {}) {
829+
const { lang = "js" } = options;
830+
isLangSupportedForEval(lang);
831+
const compiled = compile(source, options);
832+
evalCompiled(compiled, options);
833+
}
834+
756835
var parser = {
757836
compile,
837+
evalCompiled,
838+
execute,
758839
version,
759840
wy2tokens,
760841
tokens2asc,

src/stdlib.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
const STDLIB = {};
2+
13
try {
24
function loadStdlib() {
35
const STDLIB = {};
@@ -17,6 +19,6 @@ try {
1719

1820
return STDLIB;
1921
}
20-
21-
module.exports = loadStdlib();
22+
STDLIB = loadStdlib();
23+
module.exports = STDLIB;
2224
} catch (e) {}

0 commit comments

Comments
 (0)