Skip to content

Commit

Permalink
Merge pull request #473 from antfu/feat/execute
Browse files Browse the repository at this point in the history
Execute function for core package
  • Loading branch information
LingDong- committed Jan 2, 2020
2 parents 41ae6fe + af6de60 commit bf28dc2
Show file tree
Hide file tree
Showing 13 changed files with 280 additions and 379 deletions.
31 changes: 28 additions & 3 deletions documentation/Compiler-API.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,28 +44,53 @@ const compiled = Wenyan.compile('吾有一言。曰「「問天地好在。」

- core
- [compile](#compile)
- [execute](#execute)

### Execute

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

```ts
function execute(source: string, options?: ExecuteOptions)
```

**Parameters**

| Name | Type | Note |
| --- | --- | --- |
| source | string | The Wenyan source code |
| options | object | [Execute Options](#Execute-Options) |

### Compile

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

```ts
function compile(targetLang: string, source: string, options?: CompilerOptions)
function compile(source: string, options?: CompilerOptions)
```

**Parameters**

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

### Compiler Options
#### Compiler Options

| Fields | Default Value | Note |
| --- | --- | --- |
| lang | `js` | Target language, can be `js`, `py` or `rb` |
| romanizeIdentifiers | none | Romanize variable identifiers (e.g. `` to `JIA2`) |
| resetVarCnt | false | Reset temporary variable counter |
| logCallback | console.log | Get verbose debug log |
| errorLog | process.exit | Error log |

#### Execute Options

Execute Options extends all field in [Compiler Options](#Compiler-Options)

| Fields | Default Value | Note |
| --- | --- | --- |
| outputHanzi | true | Convert numbers and bools to Hanzi |
| output | `console.log` | You can redirect the output if you don't want to use `console.log` |
12 changes: 11 additions & 1 deletion documentation/Runtime.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

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

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

## Installation

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

### Outputing Hanzi

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.

```html
<script type="application/wenyan" ouputHanzi="false">
吾有一數。曰三。書之。
</script>
```

### DOM Hacks

There are some hacks you can do to access the DOM and browser APIs. This allows wenyan to do some realworld applications.
Expand Down
8 changes: 1 addition & 7 deletions documentation/Testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,7 @@

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

You will need to build first

```bash
npm run build
```

Then you can run all the tests by
You can run all the tests by

```bash
npm test
Expand Down
25 changes: 10 additions & 15 deletions src/browser_runtime.js
Original file line number Diff line number Diff line change
@@ -1,32 +1,27 @@
/* wenyan-catsrc-ignore */

(() => {
const { compile } = require("./parser");
const { execute } = require("./parser");

const isDev = false;

async function run(script) {
const scoped = !!script.attributes.scoped;
const outputHanzi = !(
script.attributes.outputHanzi &&
script.attributes.outputHanzi.value === "false"
);
let code = script.innerText;
if (script.src) {
const response = await fetch(script.src);
const code = await response.text();
await exec(code.toString(), scoped);
} else {
await exec(script.innerText, scoped);
code = (await response.text()).toString();
}
}

async function exec(code, scoped = false) {
let compiled = compile("js", code, {
execute(code, {
scoped,
outputHanzi,
logCallback: isDev ? console.log : () => {},
resetVarCnt: false
});

// wrap for scoped scripts that won't expose any variables to global
if (scoped) compiled = `(()=>{${compiled}})()`;

// executing
window.eval(compiled);
}

document.addEventListener("DOMContentLoaded", async () => {
Expand Down
19 changes: 7 additions & 12 deletions src/cli.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const fs = require("fs");
const version = require("./version");
const { compile } = require("./parser");
const { compile, evalCompiled } = require("./parser");
const { render, unrender } = require("./render");
const path = require("path");
const commander = require("commander");
Expand Down Expand Up @@ -38,6 +38,7 @@ program
"--roman [method]",
'Romanize identifiers. The method can be "pinyin", "baxter" or "unicode"'
)
.option("--outputHanzi", "Convert output to hanzi", true)
.option("--log <file>", "Save log to file")
.option("--title <title>", "Override title in rendering")
.helpOption("-h, --help", "Display help");
Expand Down Expand Up @@ -192,17 +193,11 @@ function exec() {
);
process.exit(1);
}
if (program.lang === "js") {
eval(getCompiled());
} else if (program.lang === "py") {
var execSync = require("child_process").execSync;
fs.writeFileSync("tmp.py", out);
var ret = execSync(
"which python3; if [ $? == 0 ]; then python3 tmp.py; else python tmp.py; fi; rm tmp.py",
{ encoding: "utf-8" }
);
console.log(ret);
}

evalCompiled(getCompiled(), {
outputHanzi: program.outputHanzi,
lang: program.lang
});
}

function replscope() {
Expand Down
4 changes: 2 additions & 2 deletions src/macro.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
function extractMacros(lang, txt, { lib, reader }) {
function extractMacros(txt, { lib, reader, lang }) {
function getImports() {
var imps = [];
for (var i = 0; i < txt.length; i++) {
Expand Down Expand Up @@ -108,7 +108,7 @@ function extractMacros(lang, txt, { lib, reader }) {
} else {
isrc = reader(imports[i]);
}
macros = macros.concat(extractMacros(lang, isrc, { lib, reader }));
macros = macros.concat(extractMacros(isrc, { lib, reader, lang }));
}
return macros;
}
Expand Down
99 changes: 90 additions & 9 deletions src/parser.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
try {
var { hanzi2num, hanzi2numstr, num2hanzi, bool2hanzi } = require("./hanzi2num");
var {
hanzi2num,
hanzi2numstr,
num2hanzi,
bool2hanzi
} = require("./hanzi2num");
var hanzi2pinyin = require("./hanzi2pinyin");
var STDLIB = require("./stdlib");
var { NUMBER_KEYWORDS, KEYWORDS } = require("./keywords");
Expand Down Expand Up @@ -648,10 +653,21 @@ function defaultReader(x) {
}
}

function compile(
lang,
txt,
{
function compile(arg1, arg2, arg3) {
let options = {};
let txt = "";

if (typeof arg2 === "string") {
// backward compatible
txt = arg2;
options = { ...arg3, lang: arg1 };
} else {
txt = arg1;
options = arg2;
}

const {
lang = "js",
romanizeIdentifiers = "none",
resetVarCnt,
logCallback = x =>
Expand All @@ -661,8 +677,8 @@ function compile(
errorCallback = process.exit,
lib = typeof STDLIB == "undefined" ? {} : STDLIB,
reader = defaultReader
} = {}
) {
} = options;

if (resetVarCnt) idenMap = {};
txt = (txt || "").replace(/\r\n/g, "\n");

Expand Down Expand Up @@ -692,7 +708,7 @@ function compile(
return 0;
}

var macros = extractMacros(lang, txt, { lib, reader });
var macros = extractMacros(txt, { lib, reader, lang });
txt = expandMacros(txt, macros);

logCallback("\n\n=== [PASS 0] EXPAND-MACROS ===");
Expand Down Expand Up @@ -740,7 +756,8 @@ function compile(
targ =
mwrapper(
imports[i],
compile(lang, isrc, {
compile(isrc, {
lang,
romanizeIdentifiers,
resetVarCnt: false,
logCallback,
Expand All @@ -753,8 +770,72 @@ function compile(
return targ;
}

function isLangSupportedForEval(lang) {
if (lang !== "js")
throw new Error(
`Executing for target language "${lang}" is not supported in current environment`
);
return true;
}

function hanzinize(value) {
if (typeof value == "number") {
return num2hanzi(value);
} else if (typeof value == "boolean") {
return bool2hanzi(value);
} else if (Array.isArray(value)) {
return value.map(i => hanzinize(i)).join("。");
} else {
return value;
}
}

function outputHanziWrapper(log, outputHanzi) {
return function output(...args) {
log(...args.map(i => (outputHanzi ? hanzinize(i) : i)));
};
}

function evalCompiled(compiledCode, options = {}) {
const {
outputHanzi = true,
scoped = false,
lang = "js",
output = console.log
} = options;

isLangSupportedForEval(lang);

let code = compiledCode;

(() => {
const _console_log = console.log;
console.log = outputHanziWrapper(output, outputHanzi);
try {
if (!scoped && "window" in this) {
window.eval(code);
} else {
eval(code);
}
} catch (e) {
throw e;
} finally {
console.log = _console_log;
}
})();
}

function execute(source, options = {}) {
const { lang = "js" } = options;
isLangSupportedForEval(lang);
const compiled = compile(source, options);
evalCompiled(compiled, options);
}

var parser = {
compile,
evalCompiled,
execute,
version,
wy2tokens,
tokens2asc,
Expand Down
6 changes: 4 additions & 2 deletions src/stdlib.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
const STDLIB = {};

try {
function loadStdlib() {
const STDLIB = {};
Expand All @@ -17,6 +19,6 @@ try {

return STDLIB;
}

module.exports = loadStdlib();
STDLIB = loadStdlib();
module.exports = STDLIB;
} catch (e) {}
Loading

0 comments on commit bf28dc2

Please sign in to comment.