Code Transformation for Fun and Profit

 

Slides link

https://slides.com/roman01la/code-transformation-for-fun-and-profit/live

Roman Liutikov

front-end @ Attendify

What is code transformation?

Source-to-source compilation

  • ES2015 into ES5 (Babel)
  • Elm into JavaScript
  • System language into binary

Human is a compiler

your

native

language

📝

your

native

language

Computer is a compiler

AST

📝

AST

CODE

CODE

AST

(Abstract Syntax Tree)

const c = a + b;

AST is a rich representation of code

What AST is used for?

  • Static analysis
  • Linting (ESLint)
  • Type inference (statically typed languages)
  • Refactoring
  • Code formatting (Prettier)
  • Code optimization

Code Optimization

Constant folding

const a = 1;

const b = 2;

const c = a + b;

(evaluating constant expressions at compile time)

Input

const c = 3;

Output

Function call inlining

const add = (a, b) => a + b;

const c = add(1, 2);

(replaces a function call site with the body of that function)

Input

const c = 1 + 2;

Output

Loop unrolling

for (let i = 0; i < 3; i++) {
  console.log(i);
}

(replaces a loop with a sequence of expressions)

Input

console.log(0);
console.log(1);
console.log(2);

Output

Refactoring

React Codemods

class Button extends Component {
  render() {
    const { label, onClick } = this.props; 
    return (
      <button onClick={onClick}>
        {label}
      </button>
    );
  }
}

React Codemods

const Button = (props) => {
  const { label, onClick } = props; 
  return (
    <button onClick={onClick}>
      {label}
    </button>
  );
}

Extending

Language Syntax

Pipeline operator

[0 1 2] |> map(inc) |> filter(odd)

// [1, 3]

Data structures literal syntax

#[1, 2, 3] > Immutable.List([1, 2, 3])

#{1, 2, 3} > Immutable.Set([1, 2, 3])

Syntax Extension Tools

  • Acorn parser
  • Babylon (Babel) parser
  • Sweet.js macros

Ahead-of-Time Compilation

Prepack

  • JavaScript interpreter
  • Runs code in compile-time
  • Outputs everything that can't be evaluated further
  • Used in React Native to improve startup performance

Procedural macros with Prepack

const getFileNames = (dir) => {
  if (__prepack) {
    return getFileNamesFrom(dir);
  }
}

const files = getFileNames('./');

Procedural macros with Prepack

const files = [
  "img1.png",
  "data.json"
];

Zero runtime cost abstraction

via domain specific optimization

(macros)

babel-plugin-preval

(runs code in Node.js at compile-time)

babel-plugin-preval

const files = preval`
  module.exports = getFilesFrom("./");
`;

 

const files = [
  "img1.png",
  "data.json"
];

babel-macros

  • Babel plugins w/o config
  • Compile-time optimizations for libraries
  • Explicit, localized and safe code transformations

CSS-in-JS

import css from "css.macro";

 

const styles = css`
  color: black;
  font-size: ${base * 2}
`;

(input)

CSS-in-JS

const styles = css("css-63457", {
  fontSize: base * 2
});

(output)

Stateful functional React components

const Counter = ({ text }, { theme }, { val } = { val: 0 }, setState) => (
  <div className={theme}>
    <h1>{text}</h1>
    <div>
      <button onClick={() => setState({ val: val - 1 })}>-</button>
      <span>{val}</span>
      <button onClick={() => setState({ val: val + 1 })}>+</button>
    </div>
  </div>
);

Other use cases

  • JSX
  • GraphQL queries
  • SQL builder
  • DB schema definition

Conclusion

  • Code transformation can be useful
  • Provides higher abstractions without runtime cost
  • Should be used with confidence

Thanks!

Code Transformation for Fun and Profit

By Roman Liutikov

Code Transformation for Fun and Profit

  • 729