From 9053d0ba6a9619a9b3b2d754c8ca7aad6164b0a4 Mon Sep 17 00:00:00 2001 From: Arun Patro Date: Sat, 13 Jul 2024 18:57:50 -0400 Subject: [PATCH] fix --- _docs/how.md | 56 ++++++++++++++-- _docs/index.md | 2 +- docs/404.html | 6 +- docs/How/index.html | 116 ++++++++++++++++++++++++++++------ docs/index.html | 17 +++-- docs/search/search_index.json | 2 +- mkdocs.yml | 4 +- 7 files changed, 163 insertions(+), 40 deletions(-) diff --git a/_docs/how.md b/_docs/how.md index 829676d..3799c02 100644 --- a/_docs/how.md +++ b/_docs/how.md @@ -2,15 +2,57 @@ title: How does Declo work? --- -## How does Declo work? The goal of declo is to manipulate Python objects with JavaScript syntax. We can do using three strategies: -**Strategy 1:** -Convert `js src => py src`. This can be kinda hard because of regex parsing etc, it will involve creating a custom grammar parser. This can be good at the start, but can quickly get complex, as and when we add more features. +## 1. Source to Source +Convert `js src => py src`. This can be kinda hard because of regex parsing etc, it will involve creating a custom grammar parser. This can be good at the start, but can quickly get complex, as and when we add more features. A simple way is: +```python +def arrow_func(js_code = "x => x + 1"): + parts = js_code.replace(" ", "").split("=>") + if len(parts) != 2: + raise ValueError("Invalid arrow_func expression format") -**Strategy 2:** -Convert `js ast => py ast`. It is easier to work with structured data. Coding the rules for the equivalence is relatively easier. + param, body = parts + py_code = f"lambda {param}: {body}" + code_obj = compile(py_code, "", "eval") -**Strategy 3:** -Convert `js src => py ast`. End to End convertion would be the best, but is the most complex which requires a mix of S1 and S2. \ No newline at end of file + return eval(code_obj) +``` + + + +## 2. AST to AST +Convert `js ast => py ast`. It is easier to work with structured data. Coding the rules for the equivalence is relatively easier. We provide this api in `declo.ast.ast_js2py`. This can get a little verbose too: +```python +def ast_js2py(js_node: Union[Program, ExpressionStatement, ArrowFunctionExpression, BinaryExpression, Identifier, Literal]) -> ast.AST: + if isinstance(js_node, Program): + return ast.Module(body=[ast_js2py(stmt) for stmt in js_node.body], type_ignores=[]) + elif isinstance(js_node, ExpressionStatement): + return ast.Expr(value=ast_js2py(js_node.expression)) + elif isinstance(js_node, ArrowFunctionExpression): + return ast.Lambda( + args=ast.arguments( + posonlyargs=[], + args=[ast.arg(arg=param.name, annotation=None, type_comment=None) for param in js_node.params], + vararg=None, + kwonlyargs=[], kw_defaults=[], kwarg=None, defaults=[] + ), + body=ast_js2py(js_node.body) + ) + elif isinstance(js_node, BinaryExpression): + return ast.BinOp( + left=ast_js2py(js_node.left), + op=ast.Add() if js_node.operator == "+" else None, # Extend this for other operators + right=ast_js2py(js_node.right) + ) + elif isinstance(js_node, Identifier): + return ast.Name(id=js_node.name, ctx=ast.Load()) + elif isinstance(js_node, Literal): + return ast.Constant(value=js_node.value, kind=None) + else: + raise ValueError(f"Unsupported JS AST node type: {js_node.__class__.__name__}") +``` + +## 3. SRC to AST +Convert `js src => py ast`. End to End convertion would be the best, but is the most complex which requires a mix of S1 and S2. We could do this by patching the python grammar `Python.asdl` to support the new syntax. See: ... We don't have to recompile python to run this code, we just reuse the python pgen parser with our new `JsPython.asdl` to directly create the python objects. \ No newline at end of file diff --git a/_docs/index.md b/_docs/index.md index 463bc99..ba1f3c8 100644 --- a/_docs/index.md +++ b/_docs/index.md @@ -1,5 +1,5 @@ --- -title: Intro +title: Introduction --- # declo diff --git a/docs/404.html b/docs/404.html index 8af381e..683970a 100644 --- a/docs/404.html +++ b/docs/404.html @@ -222,7 +222,7 @@ - declo + Introduction @@ -242,7 +242,7 @@ - How + How does Declo work? @@ -318,7 +318,7 @@

404 - Not found

- + diff --git a/docs/How/index.html b/docs/How/index.html index 1aa46d3..3dedb0b 100644 --- a/docs/How/index.html +++ b/docs/How/index.html @@ -24,7 +24,7 @@ - How - Declo + How does Declo work? - Declo @@ -74,7 +74,7 @@
- + Skip to content @@ -110,7 +110,7 @@
- How + How does Declo work?
@@ -231,7 +231,7 @@ - declo + Introduction @@ -258,7 +258,7 @@ - How + How does Declo work? @@ -269,7 +269,7 @@ - How + How does Declo work? @@ -289,9 +289,27 @@
  • - + - How does Declo work? + 1. Source to Source + + + +
  • + +
  • + + + 2. AST to AST + + + +
  • + +
  • + + + 3. SRC to AST @@ -330,9 +348,27 @@
    • - + - How does Declo work? + 1. Source to Source + + + +
    • + +
    • + + + 2. AST to AST + + + +
    • + +
    • + + + 3. SRC to AST @@ -356,16 +392,55 @@ -

      How

      +

      How does Declo work?

      -

      How does Declo work?

      The goal of declo is to manipulate Python objects with JavaScript syntax. We can do using three strategies:

      -

      Strategy 1: -Convert js src => py src. This can be kinda hard because of regex parsing etc, it will involve creating a custom grammar parser. This can be good at the start, but can quickly get complex, as and when we add more features.

      -

      Strategy 2: -Convert js ast => py ast. It is easier to work with structured data. Coding the rules for the equivalence is relatively easier.

      -

      Strategy 3: -Convert js src => py ast. End to End convertion would be the best, but is the most complex which requires a mix of S1 and S2.

      +

      1. Source to Source

      +

      Convert js src => py src. This can be kinda hard because of regex parsing etc, it will involve creating a custom grammar parser. This can be good at the start, but can quickly get complex, as and when we add more features. A simple way is: +

      def arrow_func(js_code = "x => x + 1"):
      +    parts = js_code.replace(" ", "").split("=>")
      +
      +    if len(parts) != 2:
      +        raise ValueError("Invalid arrow_func expression format")
      +
      +    param, body = parts
      +    py_code = f"lambda {param}: {body}"
      +    code_obj = compile(py_code, "<string>", "eval")
      +
      +    return eval(code_obj)
      +

      +

      2. AST to AST

      +

      Convert js ast => py ast. It is easier to work with structured data. Coding the rules for the equivalence is relatively easier. We provide this api in declo.ast.ast_js2py. This can get a little verbose too: +

      def ast_js2py(js_node: Union[Program, ExpressionStatement, ArrowFunctionExpression, BinaryExpression, Identifier, Literal]) -> ast.AST:
      +    if isinstance(js_node, Program):
      +        return ast.Module(body=[ast_js2py(stmt) for stmt in js_node.body], type_ignores=[])
      +    elif isinstance(js_node, ExpressionStatement):
      +        return ast.Expr(value=ast_js2py(js_node.expression))
      +    elif isinstance(js_node, ArrowFunctionExpression):
      +        return ast.Lambda(
      +            args=ast.arguments(
      +                posonlyargs=[],
      +                args=[ast.arg(arg=param.name, annotation=None, type_comment=None) for param in js_node.params],
      +                vararg=None,
      +                kwonlyargs=[], kw_defaults=[], kwarg=None, defaults=[]
      +            ),
      +            body=ast_js2py(js_node.body)
      +        )
      +    elif isinstance(js_node, BinaryExpression):
      +        return ast.BinOp(
      +            left=ast_js2py(js_node.left),
      +            op=ast.Add() if js_node.operator == "+" else None,  # Extend this for other operators
      +            right=ast_js2py(js_node.right)
      +        )
      +    elif isinstance(js_node, Identifier):
      +        return ast.Name(id=js_node.name, ctx=ast.Load())
      +    elif isinstance(js_node, Literal):
      +        return ast.Constant(value=js_node.value, kind=None)
      +    else:
      +        raise ValueError(f"Unsupported JS AST node type: {js_node.__class__.__name__}")
      +

      +

      3. SRC to AST

      +

      Convert js src => py ast. End to End convertion would be the best, but is the most complex which requires a mix of S1 and S2. We could do this by patching the python grammar Python.asdl to support the new syntax. See: ... We don't have to recompile python to run this code, we just reuse the python pgen parser with our new JsPython.asdl to directly create the python objects.

      @@ -373,6 +448,9 @@

      How does Declo work?

      + + + @@ -416,7 +494,7 @@

      How does Declo work?

- + diff --git a/docs/index.html b/docs/index.html index 603e411..60ebeb9 100644 --- a/docs/index.html +++ b/docs/index.html @@ -24,7 +24,7 @@ - Declo + Introduction - Declo @@ -110,7 +110,7 @@
- declo + Introduction
@@ -240,7 +240,7 @@ - declo + Introduction @@ -251,7 +251,7 @@ - declo + Introduction @@ -351,7 +351,7 @@ - How + How does Declo work? @@ -489,7 +489,7 @@

Usage

Why declo?

It should be easy to customize our python sytanx. I find the JS Syntax for functional programming easier to work with, allowing me to write declartive code easily.

-

Declo is about DSLs that compile to python bytecode during runtime.

+

Declo is about DSLs that compile to python bytecode during runti

FAQ

How is declo different from js2py?

js2py is a js compiler written in python. It emits custom objects that help run JS objects inside python. declo is simpler and restrictive, and deals only with python objects.

@@ -508,6 +508,9 @@

Thoughts

+ + + @@ -551,7 +554,7 @@

Thoughts

- + diff --git a/docs/search/search_index.json b/docs/search/search_index.json index f7b31d5..e0d66de 100644 --- a/docs/search/search_index.json +++ b/docs/search/search_index.json @@ -1 +1 @@ -{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"declo","text":"

declo aims to improve the ergonomics of functional programming syntax in python. It extends the JS syntax into python.

"},{"location":"#usage","title":"Usage","text":"
  1. Create lambdas with arrow notation

    import declo\n\nadd_one = declo.func(\"x => x + 1\")\nassert add_one(1) == 2 # True\n

  2. Create named functions globally

    import declo\n\n# this creates a function foo in the global name space. \ndeclo.run(\"let foo = x => x + 1\")\n\nassert foo(5) == 6\n

"},{"location":"#why-declo","title":"Why declo?","text":"

It should be easy to customize our python sytanx. I find the JS Syntax for functional programming easier to work with, allowing me to write declartive code easily.

Declo is about DSLs that compile to python bytecode during runtime.

"},{"location":"#faq","title":"FAQ","text":""},{"location":"#how-is-declo-different-from-js2py","title":"How is declo different from js2py?","text":"

js2py is a js compiler written in python. It emits custom objects that help run JS objects inside python. declo is simpler and restrictive, and deals only with python objects.

"},{"location":"#how-is-declo-different-from-macro-py","title":"How is declo different from macro-py?","text":"

TODO: I don't really understand macro-py.

"},{"location":"#thoughts","title":"Thoughts","text":"
  1. Can we introduce synctatic sugar with pre-processing?
  2. What are the hard things - like closures?
  3. How do we handle linting?
"},{"location":"how/","title":"How","text":""},{"location":"how/#how-does-declo-work","title":"How does Declo work?","text":"

The goal of declo is to manipulate Python objects with JavaScript syntax. We can do using three strategies:

Strategy 1: Convert js src => py src. This can be kinda hard because of regex parsing etc, it will involve creating a custom grammar parser. This can be good at the start, but can quickly get complex, as and when we add more features.

Strategy 2: Convert js ast => py ast. It is easier to work with structured data. Coding the rules for the equivalence is relatively easier.

Strategy 3: Convert js src => py ast. End to End convertion would be the best, but is the most complex which requires a mix of S1 and S2.

"}]} \ No newline at end of file +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"declo","text":"

declo aims to improve the ergonomics of functional programming syntax in python. It extends the JS syntax into python.

"},{"location":"#usage","title":"Usage","text":"
  1. Create lambdas with arrow notation

    import declo\n\nadd_one = declo.func(\"x => x + 1\")\nassert add_one(1) == 2 # True\n

  2. Create named functions globally

    import declo\n\n# this creates a function foo in the global name space. \ndeclo.run(\"let foo = x => x + 1\")\n\nassert foo(5) == 6\n

"},{"location":"#why-declo","title":"Why declo?","text":"

It should be easy to customize our python sytanx. I find the JS Syntax for functional programming easier to work with, allowing me to write declartive code easily.

Declo is about DSLs that compile to python bytecode during runti

"},{"location":"#faq","title":"FAQ","text":""},{"location":"#how-is-declo-different-from-js2py","title":"How is declo different from js2py?","text":"

js2py is a js compiler written in python. It emits custom objects that help run JS objects inside python. declo is simpler and restrictive, and deals only with python objects.

"},{"location":"#how-is-declo-different-from-macro-py","title":"How is declo different from macro-py?","text":"

TODO: I don't really understand macro-py.

"},{"location":"#thoughts","title":"Thoughts","text":"
  1. Can we introduce synctatic sugar with pre-processing?
  2. What are the hard things - like closures?
  3. How do we handle linting?
"},{"location":"how/","title":"How does Declo work?","text":"

The goal of declo is to manipulate Python objects with JavaScript syntax. We can do using three strategies:

"},{"location":"how/#1-source-to-source","title":"1. Source to Source","text":"

Convert js src => py src. This can be kinda hard because of regex parsing etc, it will involve creating a custom grammar parser. This can be good at the start, but can quickly get complex, as and when we add more features. A simple way is:

def arrow_func(js_code = \"x => x + 1\"):\n    parts = js_code.replace(\" \", \"\").split(\"=>\")\n\n    if len(parts) != 2:\n        raise ValueError(\"Invalid arrow_func expression format\")\n\n    param, body = parts\n    py_code = f\"lambda {param}: {body}\"\n    code_obj = compile(py_code, \"<string>\", \"eval\")\n\n    return eval(code_obj)\n

"},{"location":"how/#2-ast-to-ast","title":"2. AST to AST","text":"

Convert js ast => py ast. It is easier to work with structured data. Coding the rules for the equivalence is relatively easier. We provide this api in declo.ast.ast_js2py. This can get a little verbose too:

def ast_js2py(js_node: Union[Program, ExpressionStatement, ArrowFunctionExpression, BinaryExpression, Identifier, Literal]) -> ast.AST:\n    if isinstance(js_node, Program):\n        return ast.Module(body=[ast_js2py(stmt) for stmt in js_node.body], type_ignores=[])\n    elif isinstance(js_node, ExpressionStatement):\n        return ast.Expr(value=ast_js2py(js_node.expression))\n    elif isinstance(js_node, ArrowFunctionExpression):\n        return ast.Lambda(\n            args=ast.arguments(\n                posonlyargs=[],\n                args=[ast.arg(arg=param.name, annotation=None, type_comment=None) for param in js_node.params],\n                vararg=None,\n                kwonlyargs=[], kw_defaults=[], kwarg=None, defaults=[]\n            ),\n            body=ast_js2py(js_node.body)\n        )\n    elif isinstance(js_node, BinaryExpression):\n        return ast.BinOp(\n            left=ast_js2py(js_node.left),\n            op=ast.Add() if js_node.operator == \"+\" else None,  # Extend this for other operators\n            right=ast_js2py(js_node.right)\n        )\n    elif isinstance(js_node, Identifier):\n        return ast.Name(id=js_node.name, ctx=ast.Load())\n    elif isinstance(js_node, Literal):\n        return ast.Constant(value=js_node.value, kind=None)\n    else:\n        raise ValueError(f\"Unsupported JS AST node type: {js_node.__class__.__name__}\")\n

"},{"location":"how/#3-src-to-ast","title":"3. SRC to AST","text":"

Convert js src => py ast. End to End convertion would be the best, but is the most complex which requires a mix of S1 and S2. We could do this by patching the python grammar Python.asdl to support the new syntax. See: ... We don't have to recompile python to run this code, we just reuse the python pgen parser with our new JsPython.asdl to directly create the python objects.

"}]} \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index 4f9085c..5c4973d 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -27,9 +27,9 @@ theme: features: - content.code.copy - navigation.expand - - navigation.tabs + # - navigation.tabs - navigation.sections - - header.autohide + # - header.autohide - announce.dismiss # Extensions