Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Execute function for core package #473

Merged
merged 8 commits into from
Jan 2, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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